Personal opinions about best practices for Panel + HoloViews

A more coherent version by ChatGPT
“”"
After completing the development of what I consider one of my most refined applications yet (Year vs Climatology - a Hugging Face Space by ahuang11), I realized it encompasses numerous examples of best practices, mostly drawn from my experience using HoloViz. In a spontaneous decision, I decided to compile a somewhat unpolished brain dump of these practices:

  • Instead of inheriting from param.Parameterized, opting for inheritance from pn.viewable.Viewer allows direct invocation of the class, resembling a native Panel object. This eliminates the need for calling a method like ClimateApp().view().servable().
  • To ensure sliders only trigger callbacks upon mouse-up, set throttled=True.
  • Start by instantiating the initial layout with placeholder pn.Columns in __init__, then populate it later in onload.
  • Enhance app responsiveness by employing onload to prevent webpage hang-ups during slow loading processes. Users can immediately observe a loading indicator upon visiting, signaling ongoing processing.
  • Manage loading states effectively by encapsulating widget activation within a try/finally block. This ensures widgets are always reactivated upon completion or in the event of errors.
  • Utilize pn.Param or from_param classmethod for converting class parameters to widgets, with the latter particularly useful for handling nested dictionaries.
  • Renaming widget names can be achieved using label when utilizing pn.Param or from_param.
  • Ensure proper param watching/binding by using self.param.NAME_OF_PARAM instead of self.NAME_OF_PARAM, noting the additional .param..
  • Optimize runtime and reduce flickers by updating object and value on pre-initialized placeholders instead of recreating the panel object every time pn.bind runs.
  • Preserve plot zoom ranges during updates by wrapping hv.DynamicMap with pn.bind. This prevents the plot from resetting zoom, although some bugs may necessitate workarounds for issues like title/ylabel updating.
  • Enhance app speed using @pn.cache, but remember that pn.cache activation depends on input kwargs.
  • Employ pn.depends with watch=True when a method doesn’t return anything.
  • Utilize a template’s modal (pop-up container) to optimize screen estate if unsure where else to place content.
  • Bind to HoloViews streams, noting similarities and differences between hv.DynamicMap streams and pn.bind.
  • Prevent text overlapping by setting opposites with text align and baseline.

My approach typically involves:

  1. Starting with small iterations, gradually building up functionality. The panel serve app.py --autoreload command proves handy in this regard.
  2. Focusing initially on layout, ensuring the core structure looks correct.
  3. Introducing interactivity with pn.bind or pn.depends once the layout is satisfactory.

I continuously iterate through these steps when implementing new features, beginning with creating placeholder widgets/panes, verifying visual correctness, and finally adding interactivity. If any of these concepts require clarification, feel free to ask!
“”"

3 Likes