holoviz-mcp 0.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. holoviz_mcp/__init__.py +18 -0
  2. holoviz_mcp/apps/__init__.py +1 -0
  3. holoviz_mcp/apps/configuration_viewer.py +116 -0
  4. holoviz_mcp/apps/holoviz_get_best_practices.py +173 -0
  5. holoviz_mcp/apps/holoviz_search.py +319 -0
  6. holoviz_mcp/apps/hvplot_get_docstring.py +255 -0
  7. holoviz_mcp/apps/hvplot_get_signature.py +252 -0
  8. holoviz_mcp/apps/hvplot_list_plot_types.py +83 -0
  9. holoviz_mcp/apps/panel_get_component.py +496 -0
  10. holoviz_mcp/apps/panel_get_component_parameters.py +467 -0
  11. holoviz_mcp/apps/panel_list_components.py +311 -0
  12. holoviz_mcp/apps/panel_list_packages.py +71 -0
  13. holoviz_mcp/apps/panel_search_components.py +312 -0
  14. holoviz_mcp/cli.py +75 -0
  15. holoviz_mcp/client.py +94 -0
  16. holoviz_mcp/config/__init__.py +29 -0
  17. holoviz_mcp/config/config.yaml +178 -0
  18. holoviz_mcp/config/loader.py +316 -0
  19. holoviz_mcp/config/models.py +208 -0
  20. holoviz_mcp/config/resources/best-practices/holoviews.md +423 -0
  21. holoviz_mcp/config/resources/best-practices/hvplot.md +465 -0
  22. holoviz_mcp/config/resources/best-practices/panel-material-ui.md +318 -0
  23. holoviz_mcp/config/resources/best-practices/panel.md +562 -0
  24. holoviz_mcp/config/schema.json +228 -0
  25. holoviz_mcp/holoviz_mcp/__init__.py +1 -0
  26. holoviz_mcp/holoviz_mcp/data.py +970 -0
  27. holoviz_mcp/holoviz_mcp/models.py +21 -0
  28. holoviz_mcp/holoviz_mcp/pages_design.md +407 -0
  29. holoviz_mcp/holoviz_mcp/server.py +220 -0
  30. holoviz_mcp/hvplot_mcp/__init__.py +1 -0
  31. holoviz_mcp/hvplot_mcp/server.py +146 -0
  32. holoviz_mcp/panel_mcp/__init__.py +17 -0
  33. holoviz_mcp/panel_mcp/data.py +319 -0
  34. holoviz_mcp/panel_mcp/models.py +124 -0
  35. holoviz_mcp/panel_mcp/server.py +443 -0
  36. holoviz_mcp/py.typed +0 -0
  37. holoviz_mcp/serve.py +36 -0
  38. holoviz_mcp/server.py +86 -0
  39. holoviz_mcp/shared/__init__.py +1 -0
  40. holoviz_mcp/shared/extract_tools.py +74 -0
  41. holoviz_mcp/thumbnails/configuration_viewer.png +0 -0
  42. holoviz_mcp/thumbnails/holoviz_get_best_practices.png +0 -0
  43. holoviz_mcp/thumbnails/holoviz_search.png +0 -0
  44. holoviz_mcp/thumbnails/hvplot_get_docstring.png +0 -0
  45. holoviz_mcp/thumbnails/hvplot_get_signature.png +0 -0
  46. holoviz_mcp/thumbnails/hvplot_list_plot_types.png +0 -0
  47. holoviz_mcp/thumbnails/panel_get_component.png +0 -0
  48. holoviz_mcp/thumbnails/panel_get_component_parameters.png +0 -0
  49. holoviz_mcp/thumbnails/panel_list_components.png +0 -0
  50. holoviz_mcp/thumbnails/panel_list_packages.png +0 -0
  51. holoviz_mcp/thumbnails/panel_search_components.png +0 -0
  52. holoviz_mcp-0.4.0.dist-info/METADATA +216 -0
  53. holoviz_mcp-0.4.0.dist-info/RECORD +56 -0
  54. holoviz_mcp-0.4.0.dist-info/WHEEL +4 -0
  55. holoviz_mcp-0.4.0.dist-info/entry_points.txt +2 -0
  56. holoviz_mcp-0.4.0.dist-info/licenses/LICENSE.txt +30 -0
@@ -0,0 +1,465 @@
1
+ ---
2
+ name: hvplot-development
3
+ description: hvPlot provides an intuitive, pandas-like API for rapid, interactive visualization and publication-quality plots with minimal code.
4
+ metadata:
5
+ version: "1.0.0"
6
+ author: holoviz
7
+ category: data-visualization
8
+ difficulty: intermediate
9
+ ---
10
+
11
+
12
+ # hvPlot Development Skill
13
+
14
+ This document provides best practices for developing plots and charts with HoloViz hvPlot in notebooks and .py files.
15
+
16
+ Please develop as an **Expert Python Developer** developing advanced data-driven, analytics and testable data visualisations, dashboards and applications would do. Keep the code short, concise, documented, testable and professional.
17
+
18
+ ## Dependencies
19
+
20
+ Core dependencies provided with the `hvplot` Python package:
21
+
22
+ - **hvplot**: Core visualization framework
23
+ - **holoviews**: Declarative data visualization library with composable elements. Best for: complex multi-layered plots, advanced interactivity (linked brushing, selection), when you need fine control over plot composition, scientific visualizations. More powerful but steeper learning curve than hvPlot. hvPlot is built upon holoviews.
24
+ - **colorcet**: Perceptually uniform colormaps
25
+ - **panel**: Provides widgets and layouts enabling tool, dashboard and data app development.
26
+ - **param**: A declarative approach to creating classes with typed, validated, and documented parameters. Fundamental to the reactive programming model of hvPlot and the rest of the HoloViz ecosystem.
27
+ - **pandas**: Industry-standard DataFrame library for tabular data. Best for: data cleaning, transformation, time series analysis, datasets that fit in memory. The default choice for most data work.
28
+
29
+ Optional dependencies from the HoloViz Ecosystem:
30
+
31
+ - **datashader**: Renders large datasets (millions+ points) into images for visualization. Best for: big data visualization, geospatial datasets, scatter plots with millions of points, heatmaps of dense data. Requires hvPlot or HoloViews as frontend.
32
+ - **geoviews**: Geographic data visualization with map projections and tile sources. Best for: geographic/geospatial plots, map-based dashboards, when you need coordinate systems and projections. Built on HoloViews, works seamlessly with hvPlot.
33
+ - **holoviz-mcp**: Model Context Protocol server for HoloViz ecosystem. Provides access to detailed documentation, component search and best practices.
34
+ - **hvsampledata**: Shared datasets for the HoloViz projects.
35
+
36
+ Optional dependencies from the wider PyData Ecosystem:
37
+
38
+ - **dask**: Parallel computing library for scaling Pandas DataFrames beyond memory. Best for: processing datasets larger than RAM, parallel computation across multiple cores/machines, lazy evaluation workflows.
39
+ - **duckdb**: High-performance analytical SQL database. Best for: fast SQL queries on DataFrames, aggregations on large datasets, when you need SQL interface, OLAP-style analytics. Much faster than Pandas for analytical queries.
40
+ - **matplotlib**: Low-level, highly customizable plotting library. Best for: publication-quality static plots, fine-grained control over every aspect of visualization, scientific plots, when you need pixel-perfect control.
41
+ - **Plotly**: Interactive, publication-quality visualization library. Best for: 3D plots, complex interactive charts, animations, when you need hover tooltips and interactivity. Works well with Dash and Panel.
42
+ - **polars**: Modern, fast DataFrame library written in Rust. Best for: high-performance data processing, datasets that fit in memory but need speed, when you need lazy evaluation, better memory efficiency than Pandas.
43
+ - **xarray**: N-dimensional labeled arrays and datasets. Best for: multidimensional scientific data (climate, satellite imagery), data with multiple dimensions and coordinates, NetCDF/HDF5 files, geospatial raster data.
44
+
45
+ ## Installation for Development
46
+
47
+ ```bash
48
+ pip install hvplot hvsampledata panel watchfiles
49
+ ```
50
+
51
+ For development in .py files DO always include watchfiles for Panel hotreload.
52
+
53
+ ## Earthquake Sample Data
54
+
55
+ In the example below we will use the `earthquakes` sample data:
56
+
57
+ ```python
58
+ import hvsampledata
59
+
60
+ hvsampledata.earthquakes("pandas")
61
+ ```
62
+
63
+ ```text
64
+ Tabular record of earthquake events from the USGS Earthquake Catalog that provides detailed
65
+ information including parameters such as time, location as latitude/longitude coordinates
66
+ and place name, depth, and magnitude. The dataset contains 596 events.
67
+
68
+ Note: The columns `depth_class` and `mag_class` were created by categorizing numerical values from
69
+ the `depth` and `mag` columns in the original dataset using custom-defined binning:
70
+
71
+ Depth Classification
72
+
73
+ | depth | depth_class |
74
+ |-----------|--------------|
75
+ | Below 70 | Shallow |
76
+ | 70 - 300 | Intermediate |
77
+ | Above 300 | Deep |
78
+
79
+ Magnitude Classification
80
+
81
+ | mag | mag_class |
82
+ |-------------|-----------|
83
+ | 3.9 - <4.9 | Light |
84
+ | 4.9 - <5.9 | Moderate |
85
+ | 5.9 - <6.9 | Strong |
86
+ | 6.9 - <7.9 | Major |
87
+
88
+
89
+ Schema
90
+ ------
91
+ | name | type | description |
92
+ |:------------|:-----------|:--------------------------------------------------------------------|
93
+ | time | datetime | UTC Time when the event occurred. |
94
+ | lat | float | Decimal degrees latitude. Negative values for southern latitudes. |
95
+ | lon | float | Decimal degrees longitude. Negative values for western longitudes |
96
+ | depth | float | Depth of the event in kilometers. |
97
+ | depth_class | category | The depth category derived from the depth column. |
98
+ | mag | float | The magnitude for the event. |
99
+ | mag_class | category | The magnitude category derived from the mag column. |
100
+ | place | string | Textual description of named geographic region near to the event. |
101
+ ```
102
+
103
+ ## Reference Data Exploration Example
104
+
105
+ Below is a simple reference example for data exploration.
106
+
107
+ ```python
108
+ import hvsampledata
109
+ # DO import panel if working in .py files
110
+ import panel as pn
111
+ # Do importing hvplot.pandas to add .hvplot namespace to Pandas DataFrames and Series
112
+ import hvplot.pandas # noqa: F401
113
+
114
+ # DO always run pn.extension() to load panel javascript extensions
115
+ pn.extension()
116
+
117
+ # Do keep the extraction, transformation and plotting of data clearly separate
118
+ # Extract: earthquakes sample data
119
+ data = hvsampledata.earthquakes("pandas")
120
+
121
+ # Transform: Group by mag_class and count occurrences
122
+ mag_class_counts = data.groupby('mag_class').size().reset_index(name='counts')
123
+
124
+ # Plot: counts by mag_class
125
+ plot = mag_class_counts.hvplot.bar(x='mag_class', y='counts', title='Earthquake Counts by Magnitude Class')
126
+ # If working in notebook DO output to plot:
127
+ plot
128
+ # Else if working in .py file DO:
129
+ # DO provide a method to serve the app with `panel serve`
130
+ if pn.state.served:
131
+ # DO remember to add .servable to the panel components you want to serve with the app
132
+ pn.panel(plot, sizing_mode="stretch_both").servable()
133
+ # DON'T provide a `if __name__ == "__main__":` method to serve the app with `python`
134
+ ```
135
+
136
+ If working in a .py file DO serve the plot with hotreload:
137
+
138
+ ```bash
139
+ panel serve path/to/file.py --dev --show
140
+ ```
141
+
142
+ DONT serve with `python path_to_this_file.py`.
143
+
144
+ ## Reference Publication Quality Bar Chart
145
+
146
+ ```python
147
+ # ============================================================================
148
+ # Publication-Quality Bar Chart - hvPlot Best Practices Example
149
+ # ============================================================================
150
+ # Demonstrates:
151
+ # - Data extraction, transformation, and visualization separation
152
+ # - Custom Bokeh themes for consistent styling
153
+ # - Interactive tooltips with formatted data
154
+ # - Text annotations on bars
155
+ # - Professional fonts, grids, and axis formatting
156
+ # - Panel integration for web serving
157
+ # ============================================================================
158
+
159
+ import hvplot.pandas # noqa: F401
160
+ import panel as pn
161
+ import hvsampledata
162
+ from bokeh.models.formatters import NumeralTickFormatter
163
+ from bokeh.themes import Theme
164
+ import holoviews as hv
165
+ from holoviews.plotting.bokeh import ElementPlot
166
+
167
+ ACCENT_COLOR = '#007ACC' # Professional blue
168
+
169
+ # ============================================================================
170
+ # BOKEH THEME SETUP - Define global styling
171
+ # ============================================================================
172
+
173
+ def create_bokeh_theme(font_family='Roboto', accent_color=ACCENT_COLOR):
174
+ """Create custom theme with specified font. Default: Roboto"""
175
+ return Theme(json={
176
+ 'attrs': {
177
+ 'Title': {
178
+ 'text_font': font_family,
179
+ 'text_font_size': '16pt',
180
+ 'text_font_style': 'bold'
181
+ },
182
+ 'Axis': {
183
+ 'axis_label_text_font': font_family,
184
+ 'axis_label_text_font_size': '12pt',
185
+ 'axis_label_text_font_style': 'bold',
186
+ 'major_label_text_font': font_family,
187
+ 'major_label_text_font_size': '10pt',
188
+ 'major_tick_line_color': "black", # Remove tick marks
189
+ 'minor_tick_line_color': None
190
+ },
191
+ 'Plot': {
192
+ 'background_fill_color': '#fafafa',
193
+ 'border_fill_color': '#fafafa'
194
+ },
195
+ 'Legend': {
196
+ 'label_text_font': font_family,
197
+ 'label_text_font_size': '10pt'
198
+ },
199
+ 'Toolbar': {
200
+ # "autohide": True,
201
+ "logo": None,
202
+ "stylesheets": [
203
+ f"""
204
+ .bk-OnOffButton.bk-active{{
205
+ border-color: {accent_color} !important;
206
+ }}
207
+ """
208
+ ]
209
+ },
210
+ # Does not work via Theme, so added here for reference purposes
211
+ 'Tooltip': {
212
+ "stylesheets": ["""
213
+ .bk-tooltip-row-label {
214
+ color: pink !important;
215
+ }"""]
216
+
217
+ }
218
+ }
219
+ })
220
+
221
+ # Apply theme globally - affects all plots
222
+ hv.renderer('bokeh').theme = create_bokeh_theme()
223
+
224
+ # ============================================================================
225
+ # HOLOVIEWS OPTS SETUP - Define global configuration
226
+ # ============================================================================
227
+
228
+ GLOBAL_BACKEND_OPTS={
229
+ 'plot.xgrid.visible': False, # Only horizontal grid lines
230
+ 'plot.ygrid.visible': True,
231
+ 'plot.ygrid.grid_line_color': "black",
232
+ 'plot.ygrid.grid_line_alpha': 0.1,
233
+ 'plot.min_border_left': 80, # Add padding on left (for y-axis label)
234
+ 'plot.min_border_bottom': 80, # Add padding on bottom (for x-axis label)
235
+ 'plot.min_border_right': 30, # Add padding on right
236
+ 'plot.min_border_top': 80, # Add padding on top
237
+ }
238
+
239
+ ElementPlot.param.backend_opts.default = GLOBAL_BACKEND_OPTS
240
+ ElementPlot.param.yformatter.default = NumeralTickFormatter(format='0a') # 1k,
241
+
242
+ hv.opts.defaults(
243
+ hv.opts.Bars(
244
+ color=ACCENT_COLOR, # Professional blue
245
+ line_color=None, # Remove bar borders
246
+ )
247
+ )
248
+ hv.Cycle.default_cycles["default_colors"] = [ACCENT_COLOR, '#00948A', '#7E59BD', '#FFA20C', '#DA4341', '#D6F1FF', '#DAF5F4', '#F0E8FF', '#FFF8EA', '#FFF1EA', '#001142', '#003336', '#290031', '#371F00', '#3A0C13']
249
+
250
+ # ============================================================================
251
+ # DATA PIPELINE - Separate extraction, transformation, and plotting
252
+ # ============================================================================
253
+
254
+ def get_earthquake_data():
255
+ """Extract raw earthquake data from sample dataset"""
256
+ return hvsampledata.earthquakes("pandas")
257
+
258
+
259
+ def aggregate_by_magnitude(earthquake_data):
260
+ """Transform: Group earthquakes by magnitude class with statistics"""
261
+
262
+ # Aggregate: count events and calculate average depth per magnitude class
263
+ aggregated = (
264
+ earthquake_data
265
+ .groupby('mag_class', observed=True)
266
+ .agg({'mag': 'count', 'depth': 'mean'})
267
+ .reset_index()
268
+ .rename(columns={'mag': 'event_count', 'depth': 'avg_depth'})
269
+ .sort_values('event_count', ascending=False)
270
+ )
271
+
272
+ # Add percentage column for tooltips
273
+ aggregated['percentage'] = (
274
+ aggregated['event_count'] / aggregated['event_count'].sum() * 100
275
+ )
276
+
277
+ return aggregated
278
+
279
+
280
+ def create_bar_chart(aggregated_data):
281
+ """Create publication-quality bar chart with labels and tooltips"""
282
+
283
+ default_tools=['save']
284
+
285
+ # Main bar chart with professional styling
286
+ bar_chart = aggregated_data.hvplot.bar(
287
+ x='mag_class',
288
+ y='event_count',
289
+
290
+ # Titles and labels
291
+ title='Earthquake Distribution by Magnitude',
292
+ xlabel='Magnitude',
293
+ ylabel='Number of Events',
294
+
295
+ # Interactivity
296
+ hover_cols = ["mag_class", "event_count", "percentage", "avg_depth"],
297
+ hover_tooltips=[
298
+ ('Magnitude', '@mag_class'),
299
+ ('Events', '@event_count{0,0}'), # Format: 1,234
300
+ ('Percentage', '@percentage{0 a}%'), # Format: 45.7%
301
+ ('Avg Depth', '@avg_depth{0f} km') # Format: 99 km
302
+ ],
303
+ ).opts(default_tools=default_tools)
304
+
305
+ # Add text labels above bars
306
+ labels_data = aggregated_data.copy()
307
+ labels_data['label_y'] = labels_data['event_count'] + 20 # Offset above bars
308
+
309
+ text_labels = labels_data.hvplot.labels(
310
+ x='mag_class',
311
+ y='label_y',
312
+ text='event_count',
313
+ text_baseline='bottom',
314
+ text_font_size='11pt',
315
+ text_font_style='bold',
316
+ text_color='#333333',
317
+ hover_cols = ["mag_class", "event_count"],
318
+ hover_tooltips=[
319
+ ('Magnitude', '@mag_class'),
320
+ ('Events', '@event_count{0,0}'), # Format: 1,234
321
+ ],
322
+ ).opts(default_tools=default_tools)
323
+
324
+ # Overlay: bar chart * text labels
325
+ return bar_chart * text_labels
326
+
327
+
328
+ def create_plot():
329
+ """Main function: Extract → Transform → Plot"""
330
+ # Extract: Get raw data
331
+ earthquake_data = get_earthquake_data()
332
+
333
+ # Transform: Aggregate and calculate statistics
334
+ aggregated = aggregate_by_magnitude(earthquake_data)
335
+
336
+ # Visualize: Create publication-quality chart
337
+ chart = create_bar_chart(aggregated)
338
+
339
+ return chart
340
+
341
+
342
+ # ============================================================================
343
+ # PANEL APP SETUP
344
+ # ============================================================================
345
+
346
+ # Serve the chart when running with Panel
347
+ if pn.state.served:
348
+ # Load Panel JavaScript extensions
349
+ pn.extension()
350
+
351
+ # Apply custom Bokeh theme (override the global theme)
352
+ # Create and serve the chart
353
+ chart = create_plot()
354
+ pn.panel(chart, sizing_mode="stretch_both", margin=25).servable()
355
+ ```
356
+
357
+ ## General Instructions
358
+
359
+ - Always import hvplot for your data backend:
360
+
361
+ ```python
362
+ import hvplot.pandas # will add .hvplot namespace to Pandas dataframes
363
+ import hvplot.polars # will add .hvplot namespace to Polars dataframes
364
+ ...
365
+ ```
366
+
367
+ - Prefer Bokeh > Plotly > Matplotlib plotting backend for interactivity
368
+ - DO use bar charts over pie Charts. Pie charts are not supported.
369
+ - DO use NumeralTickFormatter and 'a' formatter for axis formatting:
370
+
371
+ ```python
372
+ from bokeh.models.formatters import NumeralTickFormatter
373
+
374
+ df.hvplot(
375
+ ...,
376
+ yformatter=NumeralTickFormatter(format='0.00a'), # Format as 1.00M, 2.50M, etc.
377
+ )
378
+ ```
379
+
380
+
381
+ | Input | Format String | Output |
382
+ | - | - | - |
383
+ | 1230974 | '0.0a' | 1.2m |
384
+ | 1460 | '0 a' | 1 k |
385
+ | -104000 | '0a' | -104k |
386
+
387
+ ## Developing
388
+
389
+ When developing a hvplot please serve it for development using Panel:
390
+
391
+ ```python
392
+ import pandas as pd
393
+ import hvplot.pandas # noqa
394
+ import panel as pn
395
+
396
+ import numpy as np
397
+
398
+ np.random.seed(42)
399
+ dates = pd.date_range("2022-08-01", periods=30, freq="B")
400
+ open_prices = np.cumsum(np.random.normal(100, 2, size=len(dates)))
401
+ high_prices = open_prices + np.random.uniform(1, 5, size=len(dates))
402
+ low_prices = open_prices - np.random.uniform(1, 5, size=len(dates))
403
+ close_prices = open_prices + np.random.uniform(-3, 3, size=len(dates))
404
+
405
+ data = pd.DataFrame({
406
+ "open": open_prices.round(2),
407
+ "high": high_prices.round(2),
408
+ "low": low_prices.round(2),
409
+ "close": close_prices.round(2),
410
+ }, index=dates)
411
+
412
+
413
+ # Create a scatter plot of date vs close price
414
+ scatter_plot = data.hvplot.scatter(x="index", y="close", grid=True, title="Close Price Scatter Plot", xlabel="Date", ylabel="Close Price")
415
+
416
+
417
+ # Create a Panel app
418
+ app = pn.Column("# Close Price Scatter Plot", scatter_plot)
419
+
420
+ if pn.state.served:
421
+ app.servable()
422
+ ```
423
+
424
+ ```bash
425
+ panel serve plot.py --dev
426
+ ```
427
+
428
+ ### Recommended Plot Types
429
+
430
+ line - Line plots for time series and continuous data
431
+ scatter - Scatter plots for exploring relationships between variables
432
+ bar - Bar charts for categorical comparisons
433
+ hist - Histograms for distribution analysis
434
+ area - Area plots for stacked or filled visualizations
435
+
436
+ ## Workflows
437
+
438
+ ### Lookup additional information
439
+
440
+ - If the HoloViz MCP server is available DO use the HoloViz MCP server to access relevant documentation (`holoviz_search`), list of plot types available (`hvplot_list_plot_types`), and detailed docstrings (`hvplot_get_docstring`).
441
+ - If the HoloViz MCP server is not available, DO search the web. For example searching the hvplot website for `streaming` related information via https://hvplot.holoviz.org/en/docs/latest/search.html?q=streaming url.
442
+
443
+ ### Test the app with pytest
444
+
445
+ DO add tests to the `tests` folder and run them with `pytest tests/path/to/test_file.py`.
446
+
447
+ - DO separate data extraction and transformation from plotting code.
448
+ - DO fix any test errors and rerun the tests
449
+ - DO run the tests and fix errors before displaying or serving the plots
450
+
451
+ ### Serve the plot with panel serve
452
+
453
+ DO always start and keep running a development server `panel serve path_to_file.py --dev --show` with hot reload while developing!
454
+
455
+ - Due to `--show` flag, a browser tab will automatically open showing your app.
456
+ - Due to `--dev` flag, the panel server and app will automatically reload if you change the code.
457
+ - The app will be served at http://localhost:5006/.
458
+ - DO make sure the correct virtual environment is activated before serving the app.
459
+ - DO fix any errors that show up in the terminal. Consider adding new tests to ensure they don't happen again.
460
+ - DON'T stop or restart the server after changing the code. The app will automatically reload.
461
+ - If you see 'Cannot start Bokeh server, port 5006 is already in use' in the terminal, DO serve the app on another port with `--port {port-number}` flag.
462
+ - DO remind the user to test the plot on multiple screen sizes (desktop, tablet, mobile)
463
+ - DON'T use legacy `--autoreload` flag
464
+ - DON't run `python path_to_file.py` to test or serve the app.
465
+ - DO use `pn.Column, pn.Tabs, pn.Accordion` to layout multiple plots