Token导航 LogoToken导航

Agent Skill · 研究检索

panel(panel 搜索)

panel 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

panel 是研究检索类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为调用外部服务;许可证信息还不明确,第三方扫描已通过,按安装量在研究检索类的 73,675 个 Skill 里排第 65,351。

总安装 282周安装 12GitHub Stars 32下载 99核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
unknown

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:panel(panel 搜索)
来源仓库:https://github.com/marcskovmadsen/holoviz-mcp
仓库路径:skills/panel
安装命令:
npx skills add https://github.com/marcskovmadsen/holoviz-mcp --skill panel
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/marcskovmadsen/holoviz-mcp --skill panel

这个 Skill 是做什么的

研究检索类 Skill 主要解决「找资料、核对事实、把来源整理清楚」的问题,通常会让助手先检索再总结。

panel 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。适用于动态仪表盘搭建、实时监控面板设计及交互式可视化展示等场景。通过 npx skills add 命令从指定 GitHub 仓库安装并使用该技能。

安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。panel 属于研究检索类 Skill,可作为该场景下的辅助能力补充。

来源仓库内路径:skills/panel

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/marcskovmadsen/holoviz-mcp --skill panel;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要调用外部服务,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

panel 怎么安装?

在终端执行 npx skills add https://github.com/marcskovmadsen/holoviz-mcp --skill panel。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

panel 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

panel 需要什么权限?

权限级别是调用外部服务。该 Skill 可能调用第三方服务、云服务或外部模型 API,使用前需要确认账号、额度、数据发送范围和服务条款。

panel 是免费的吗?

公开资料没有标注明确许可证,收费和商用限制都无法确认。正式使用前请到来源仓库核对授权说明。

panel 用的人多吗?

公开数据是累计安装 282 次,近一周安装 12 次,下载 99 次,GitHub 32 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

panel 安全吗?

第三方扫描结果为通过,但这只覆盖已知的静态检查项,不能替代自己读一遍源码和安装命令。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。
  • 第三方扫描已通过,常见的高风险行为没有命中。

先想清楚的地方

  • 许可证没有明确标注,能不能商用、能不能再分发都不确定。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理研究检索类任务、又不想每次都手写提示词的人。

不太适合

  • 需要明确授权才能用到公司项目里的场景。
  • 需要厂商级技术支持和 SLA 的生产系统。

研究检索类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
find-skills

寻找技能 · Codex、Claude

31,199,81316,486操作浏览器MIT有提醒
self-improving-agent

自我改进 Agent · OpenClaw

16,464,0023,396接触敏感数据MIT-0通过
soultrace

灵魂追踪 · Codex、Claude

7,588,94412需要联网未明确有提醒
self-improving

自我完善 · OpenClaw

6,829,2841,046需要联网MIT-0通过
microsoft-foundry

微软代工厂 · Codex、Claude

6,614,144764调用外部服务未明确有提醒
panel

panel 搜索 · 本页

28232调用外部服务未明确通过

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

Panel Development Skills

This document provides best practices for developing dashboards and data apps with HoloViz Panel in Python.py files.

Please develop as an Expert Python and Panel Developer developing advanced data-driven, analytics and testable dashboards and analytics apps would do. Keep the code short, concise, documented, testable and professional.

Dependencies

Core dependencies provided with the panel Python package:

  • panel: Core application framework
  • param: A declarative approach to creating classes with typed, validated, and documented parameters. Fundamental to Panel's reactive programming model.

Optional panel-extensions:

  • panel-material-ui: Modern Material UI components. To replace the panel native widgets within the next two years.
  • panel-graphic-walker: Modern Tableau like interface. Can offload computations to the server and thus scale to large datasets.

Optional dependencies from the HoloViz Ecosystem:

  • colorcet: Perceptually uniform colormaps collection. Best for: scientific visualization requiring accurate color representation, avoiding rainbow colormaps, accessible color schemes. Integrates with hvPlot, HoloViews, Matplotlib, Bokeh.
  • 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.
  • 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.
  • 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.
  • holoviz-mcp: Model Context Protocol server for HoloViz ecosystem. Provides access to detailed documentation, component search and agent skills.
  • hvplot: High-level plotting API with Pandas .plot()-like syntax. Best for: quick exploratory visualizations, interactive plots from DataFrames/Xarray, when you want interactivity without verbose code. Built on HoloViews.
  • hvsampledata: Shared datasets for the HoloViz projects.

Optional dependencies from the wider PyData Ecosystem:

  • altair: Declarative, grammar-of-graphics visualization library. Best for: statistical visualizations, interactive exploratory charts, when you need Vega-Lite's extensive chart gallery. Works well with Pandas/Polars DataFrames.
  • 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.
  • 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.
  • 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.
  • 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.
  • 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.
  • 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.
  • 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.
  • watchfiles: Enables high performance file watching and autoreload for the panel server.

Common Use Cases

  1. Real-time Monitoring Dashboards: Live metrics and KPI displays
  2. Data Exploration Tools: Interactive data analysis applications
  3. Configuration Interfaces: Complex multi-step configuration UIs
  4. Data Input Applications: Validated form-based data collection
  5. Report Viewers: Interactive report generation and browsing
  6. Administrative Interfaces: Internal tools for data management

Installation

pip install panel watchfiles hvplot hvsampledata

For development in.py files DO always include watchfiles for hotreload.

Best Practice Hello World App

Let's describe our best practices via a basic Hello World App:

# DO import panel as pn
import panel as pn
import param

# DO always run pn.extension
# DO remember to add any imports needed by panes, e.g. pn.extension("tabulator", "plotly", ...)
# DON'T add "bokeh" as an extension. It is not needed.
# Do use throttled=True when using slider unless you have a specific reason not to
pn.extension(throttled=True)

# DO organize functions to extract data separately as your app grows. Eventually in a separate data.py file.
# DO use caching to speed up the app, e.g. for expensive data loading or processing that would return the same result given same input arguments.
# DO add a ttl (time to live argument) for expensive data loading that changes over time
@pn.cache(max_items=3)
def extract(n=5):
    return "Hello World" + "⭐" * n

text = extract()
text_len = len(text)

# DO organize functions to transform data separately as your app grows. Eventually in a separate transformations.py file
# DO add caching to speed up expensive data transformations
@pn.cache(max_items=3)
def transform(data: str, count: int=5)->str:
    count = min(count, len(data))
    return data[:count]

# DO organize functions to create plots separately as your app grows. Eventually in a separate plots.py file.
# DO organize custom components and views separately as your app grows. Eventually in separate components.py or views.py file(s).
# DO use param.Parameterized, pn.viewable.Viewer or similar approach to create new components and apps with state and reactivity
class HelloWorld(pn.viewable.Viewer):
    # DO define parameters to hold state and drive the reactivity
    characters = param.Integer(default=text_len, bounds=(0, text_len), doc="Number of characters to display")

    def __init__(self, **params):
        super().__init__(**params)

        # DO use sizing_mode="stretch_width" for components unless "fixed" or other sizing_mode is specifically needed
        with pn.config.set(sizing_mode="stretch_width"):
            # DO create widgets using `.from_param` method
            self._characters_input = pn.widgets.IntSlider.from_param(self.param.characters, margin=(10,20))

            # DO Collect input widgets into horizontal, columnar layout unless other layout is specifically needed
            self._inputs = pn.Column(self._characters_input, max_width=300)

            # CRITICAL: Create panes ONCE with reactive content
            # DON'T recreate panes and layouts in @param.depends methods - causes flickering!
            # DO bind reactive methods/functions to panes for smooth updates
            self._output_pane = pn.pane.Markdown(
                self.model,  # Reactive method reference
                sizing_mode="stretch_width"
            )

            # DO collect output components into some layout like Column, Row, FlexBox or Grid depending on use case
            self._outputs = pn.Column(self._output_pane)

            # DO collect all of your components into a combined layout useful for displaying in notebooks etc.
            self._panel = pn.Row(self._inputs, self._outputs)

    # DO use caching to speed up bound methods that are expensive to compute or load data and return the same result for a given state of the class.
    # DO add a ttl (time to live argument) for expensive data loading that changes over time.
    @pn.cache(max_items=3)
    # DO prefer .depends over .bind over .rx for reactivity methods on Parameterized classes as it can be typed and documented
    # DON'T use `watch=True` or `.watch(...)` methods to update UI components directly.
    # DO use `watch=True` or `.watch(...)` for updating the state parameters or triggering side effects like saving files or sending email.
    @param.depends("characters")
    def model(self):
        # CRITICAL: Return ONLY the content, NOT the layout/pane
        # The pane was created once in __init__, this just updates its content
        return transform(text, self.characters)

    # DO use `watch=True` or `.watch(...)` for updating the state parameters or triggering side effects like saving files or sending email.
    @param.depends("characters", watch=True)
    def _inform_user(self):
        print(f"User selected to show {self.characters} characters.")

    # DO provide a method for displaying the component in a notebook setting, i.e. without using a Template or other element that cannot be displayed in a notebook setting.
    def __panel__(self):
        return self._panel

    # DO provide a method to create a .servable app
    @classmethod
    def create_app(cls, **params):
        instance = cls(**params)
        # DO use a Template or similar page layout for served apps
        template = pn.template.FastListTemplate(
            # DO provide a title for the app
            title="Hello World App",
            # DO provide optional image, optional app description, optional navigation menu, input widgets, optional documentation and optional links in the sidebar
            # DO provide as list of components or a list of single horizontal layout like Column as the sidebar by default is 300 px wide
            sidebar=[instance._inputs],
            # DO provide a list of layouts and output components in the main area of the app.
            # DO use Grid or FlexBox layouts for complex dashboard layouts instead of combination Rows and Columns.
            main=[instance._outputs],
            # DO set main_layout=None for modern layout
            main_layout=None,
        )
        return template

# DON'T provide a `if __name__ == "__main__":` method to serve the app with `python`
# DO provide a method to serve the app with `panel serve`
if pn.state.served:
    # Mark components to be displayed in the app with .servable()
    HelloWorld.create_app().servable()

DO serve the app with

panel serve path_to_this_file.py --show --dev

DON'T serve with python path_to_this_file.py.

Best Practice Hello World Tests

With panel you can easily create tests to test user behaviour without having to write client side tests.

DO always create separate tests in the tests folder:

# DO put tests in a separate test file.
# DO always test that the reactivity works as expected
def test_characters_reactivity():
    """
    Test characters reactivity.
    """
    # DO test the default values of bound
    hello_world = HelloWorld()
    # DO test the reactivity of bound methods when parameters change
    assert hello_world.model() == text[:hello_world.characters]
    hello_world.characters = 5
    assert hello_world.model() == text[:5]
    hello_world.characters = 3
    assert hello_world.model() == text[:3]

DO run the tests with:

pytest tests/path/to/test_file.py

DO fix any errors identified.

Key Patterns

Parameter-Driven Architecture

  • DO use param.Parameterized or pn.viewable.Viewer classes to organize and manage state
  • DO create widgets with .from_param() method. DON'T do this for panes, i.e. pn.pane.Str has no from_param method.
  • DO use @param.depends() for reactive methods
  • DO use @param.depends(..., watch=True) to update parameter/ state values and for side-effects like sending an email.
  • DO group related parameters in separate Parameterized or Viewable classes
# ❌ AVOID: Updating panes and other components directly. This makes it hard to reason about application flow and state
@param.depends('value', watch=True)
def update_plot(self):
    self.output_pane.object = transform(text, self.characters)

Create Static Layout with Reactive Content (CRITICAL)

The Golden Rule: Create layout structure ONCE, update content REACTIVELY

This pattern eliminates flickering and creates professional Panel applications:

# ✅ CORRECT: Create panes ONCE in __init__, bind reactive content
class Dashboard(pn.viewable.Viewer):
    filter_value = param.String(default="all")

    chart = param.Parameter()

    def __init__(self, **params):
        super().__init__(**params)

        # 1. Create static panes with reactive content
        self._summary_pane = pn.pane.Markdown(self._summary_text)
        self._chart_pane = pn.pane.HoloViews(self.param.chart)

        # 2. Create static layout structure
        self._layout = pn.Column(
            "# Dashboard",    # Static title
            self._summary_pane,  # Reactive content
            self._chart_pane,    # Reactive content
        )

    # ✅ Good: Reactive content method
    # Will be run multiple times when filter_value updates if multiple panes or reactive functions depend on the _summary_text method
    @param.depends("filter_value")
    def _summary_text(self):
        # Returns string content only, NOT a pane
        return f"**Count**: {len(self._get_data())}"

    # ✅ Good: Reactive update of chart parameter
    # Will be run only one time when filter_value updates - even if multiple panes or reactive functions depend on the chart value
    @param.depends("filter_value", watch=True, on_init=True)
    def _update_chart(self):
        # updates the chart object only, NOT a pane
        self.chart = self._get_data().hvplot.bar()

    def __panel__(self):
        return self._layout

# ❌ WRONG: Recreating layout in @param.depends - causes flickering!
class BadDashboard(pn.viewable.Viewer):
    filter_value = param.String(default="all")

    @param.depends("filter_value")
    def view(self):
        # DON'T recreate panes/layouts on every parameter change!
        return pn.Column(
            "# Dashboard",
            pn.pane.Markdown(f"**Count**: {len(self._get_data())}"),
            pn.pane.HoloViews(self._get_data().hvplot.bar()),
        )

Why This Matters:

  • ✅ Smooth updates without layout reconstruction
  • ✅ No flickering - seamless transitions
  • ✅ Better performance - avoids unnecessary DOM updates
  • ✅ Professional UX

Key Rules:

  1. DO create main layout structure and panes ONCE in __init__
  2. DO bind panes to reactive methods or parameters (DON'T recreate them)
  3. Reactive methods should return CONTENT only (strings, plots, dataframes), NOT panes/layouts
  4. Use @param.depends for reactive methods that update pane content

Widgets

Use

  • pn.widgets.IntSlider, pn.widgets.Select, pn.widgets.DateRangeSlider and other widgets for input
  • pn.widgets.Tabulator to display tabular data like DataFrames

Panes

Use panes to display data:

  • pn.pane.Markdown and pn.pane.HTML to display strings
  • pn.pane.HoloViews, pn.pane.Plotly, pn.pane.Matplotlib or pn.pane.ECharts to display plots

Layouts

Use layouts to layout components:

  • DO use pn.Column, pn.Row, pn.Tabs, pn.Accordion for layouts

Templates

  • DO use pn.template.FastListTemplate or other templates for served apps:
template = pn.template.FastListTemplate(
    title="Hello World App",
    sidebar=[instance._inputs],
    main=[instance._outputs],
    main_layout=None,
)
  • In the sidebar, DO use the order: 1) optional logo, 2) description, 3) input widgets, 4) documentation
  • In the sidebar, DO make sure components stretch width.
  • Do set main_layout=None for a modern styling.

Responsive Design

  • DO use sizing_mode="stretch_width" by default:
with pn.config.set(sizing_mode="stretch_width"):
    character_input = pn.widgets...
    output_pane = pn.pane....
  • DO use FlexBox, GridSpec or GridBox for complex, responsive grid layouts
  • DO set appropriate min_width, min_height, max_width and max_height to prevent layout collapse

Extensions

DO remember to add extensions like "tabulator", "plotly" etc. to pn.extension to make sure their Javascript is loaded:

# ✅ Good
pn.extension("tabulator", "plotly")

DON'T add "bokeh". It's already loaded:

# ❌ Bad
pn.extension("bokeh")

Servable()

DO make the main component .servable() to include it in the served app and use pn.state.served to run the main method when the app is panel serve'd.

# ✅ Correct:
if pn.state.served:
    main().servable()

# ❌ Incorrect:
if __name__ == "__main__":
    main().servable()

# ❌ Don't: Works, but not how we want to serve the app:
if __name__ == "__main__":
    main().show()

Performance Optimization

  • Defer load: Defer load to after the app is shown to the user: pn.extension(defer_load=True, loading_indicator=True,...)
  • Lazy-load components using Tabs or Accordion for heavy content
  • Use caching with @pn.cache decorator for expensive computations
  • Use async/await: Implement asynchronous patterns for I/O operations
  • Use faster frameworks: Replace slower Pandas with faster Polars or DuckDB
  • Offload to threads: Consider using threading for CPU-intensive tasks
  • Offload to external processes: Consider offloading heavy computations to external processes like databases, scheduled (airflow) jobs, REST apis etc.
  • Profile callbacks with @pn.io.profiler to identify bottlenecks

If you experience memory issues, make sure to:

  • Limit history: Cap data history sizes in streaming applications
  • Clear caches: Periodically call pn.state.clear_caches()
  • Restart periodically: Schedule application restarts for long-running production apps
  • Profile memory: Use memory profilers (memory_profiler, tracemalloc) to identify leaks

Code Organization

  • Separate concerns: Keep UI code separate from business logic using Param classes
  • Create reusable components: Extract common patterns into functions or classes
  • Use templates for consistent application structure across pages
  • Organize modules: Group related components and utilities
  • Document parameters: Add clear docstrings to Parameterized classes

Workflows

Lookup additional information

  • If the HoloViz MCP server tools are available, DO use them to look up documentation and component details. Useful tools: search (documentation), pn_search (find components), pn_get (component details), pn_params (parameter info), ref_get (reference guides), skill_get (best-practice skills).
  • If MCP tools are not available but the holoviz-mcp CLI is installed (also available as hv), use the equivalent CLI commands: holoviz-mcp search, holoviz-mcp pn search, holoviz-mcp pn get, holoviz-mcp pn params, holoviz-mcp ref get, holoviz-mcp skill get.
  • If neither is available, DO search the web. For example searching the Panel website for Tabulator related information via https://panel.holoviz.org/search.html?q=Tabulator url.

Test the app with pytest

DO add tests to the tests folder and run them with pytest tests/path/to/test_file.py.

  • DO structure your code with Parameterized components, so that reactivity and user interactions can be tested easily.
  • DO separate UI logic from business logic to enable unit testing
  • DO separate data extraction, data transformation, plots generation, custom components and views, styles etc. to enable unit testing as your app grows
  • DO fix any test errors and rerun the tests
  • DO run the tests and fix errors before serving the app and asking the user to run manual tests

Test the app manually with panel serve

DO always start and keep running a development server panel serve path_to_file.py --dev --show with hot reload while developing!

  • Due to --show flag, a browser tab will automatically open showing your app.
  • Due to --dev flag, the panel server and app will automatically reload if you change the code.
  • The app will be served at http://localhost:5006/.
  • DO make sure the correct virtual environment is activated before serving the app.
  • DO fix any errors that show up in the terminal. Consider adding new tests to ensure they don't happen again.
  • DON'T stop or restart the server after changing the code. The app will automatically reload.
  • 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.
  • DO remind the user to test the application on multiple screen sizes (desktop, tablet, mobile)
  • DON'T use legacy --autoreload flag
  • DON't run python path_to_file.py to test or serve the app.
  • If you close the server to run other commands DO remember to restart it.

Quick Reference

Widget Creation

# ✅ Good: Parameter-driven
widget = pn.widgets.Select.from_param(self.param.model_type, name="Model Type")

# ❌ Avoid: Manual management with links
widget = pn.widgets.Select(options=['A', 'B'], value='A')
widget.link(self, value='model_type')  # Hard to reason about

Reactive Updates Pattern

# ✅ BEST: Static pane with reactive content (for classes)
class MyComponent(pn.viewable.Viewer):
    value = param.Number(default=10)

    def __init__(self, **params):
        super().__init__(**params)
        self._plot_pane = pn.pane.Matplotlib(self._create_plot)

    @param.depends('value')
    def _create_plot(self):
        return create_plot(self.value)  # Returns plot only, not pane

# ✅ GOOD: pn.bind for functions
slider = pn.widgets.IntSlider(value=10)
plot_pane = pn.pane.Matplotlib(pn.bind(create_plot, slider))

# ❌ AVOID: Recreating panes and other components directly. This causes flickering.
@param.depends('value')
def view(self):
    return pn.pane.Matplotlib(create_plot(self.value))  # DON'T!

# ❌ AVOID: Updating panes and other components directly. This makes it hard to reason about application flow and state
@param.depends('value', watch=True)
def update_plot(self):
    self.plot_pane.object = create_plot(self.value)

Static Components Pattern

# DO: Create static layout with reactive content
def _get_kpi_card(self):
    return pn.pane.HTML(
        pn.Column(
            "📊 Key Performance Metrics",
            self.kpi_value  # Reactive reference
        ),
        styles={"padding": "20px", "border": "1px solid #ddd"},
        sizing_mode="stretch_width"
    )

@param.depends("characters")
def kpi_value(self):
    return f"The kpi is {self.characters}"

Other Guidance

CheckButtonGroup

  • DO arrange vertically when displaying CheckButtonGroup in a sidebar CheckButtonGroup(..., vertical=True).
  • DO set button_type="primary" and button_style="outline".

Tabulator

  • DO set Tabulator.disabled=True unless you would like the user to be able to edit the table.
  • DO prefer Tabulator Formatters over Bokeh formatters and Pandas Styling.
  • DO prefer Tabulator Editors over Bokeh Editor types

Markdown

  • DO set Markdown.disable_anchors=True to avoid page flickr when hovering over headers.

Bind

  • DON't bind a function to nothing: pn.bind(some_func). Just run the function instead some_func().

Plotting

  • DO use bar charts over pie Charts.

HoloViews/hvPlot

DO follow the relevant hvplot, holoviews and panel-holoviews skills/ best practice guides!

Matplotlib

CRITICAL: On windows set non-interactive backend before importing matplotlib.pyplot:

Why: The 'agg' backend is required for server-side rendering without display. Panel needs to render plots as images, not interactive GUI windows.

Extension: DON'T include 'matplotlib' in pn.extension() - it doesn't require JavaScript loading like Plotly or Bokeh extensions.

# ✅ CORRECT
import matplotlib
matplotlib.use('agg')
import matplotlib.pyplot as plt
import panel as pn

pn.extension()  # No 'matplotlib' needed

# ❌ WRONG
pn.extension('matplotlib')  # Not a Panel extension

Best Practices:

  • DO use matplotlib for publication-quality static plots
  • DO close figures after rendering to prevent memory leaks: plt.close(fig)
  • DO consider hvPlot or Plotly for interactive plots instead

Plotly

Do set the template (theme) depending on the theme of the app.

def create_plot(self) -> go.Figure:
    fig = ...
    template = "plotly_dark" if pn.state.theme=="dark" else "plotly_white"
    fig.update_layout(
        template=template, # Change template to align with the theme
        paper_bgcolor='rgba(0,0,0,0)', # Change to transparent background to align with the app background
        plot_bgcolor='rgba(0,0,0,0)' # Change to transparent background to align with the app background
    )
    return fig

ECharts

DO prefer ECharts dict configuration over of pyecharts CRITICAL: ECharts configurations must be JSON-serializable. Panel uses Bokeh's serialization mechanism which cannot serialize Python functions.

❌ NEVER use Python functions or lambdas in ECharts configuration:

# ❌ WRONG: Lambda functions cause SerializationError
option = {
    "tooltip": {
        "formatter": lambda params: f"Value: {params['value']}"  # DON'T!
    },
    "xAxis": {
        "axisLabel": {
            "formatter": lambda value: f"{value}%"  # DON'T!
        }
    },
    "series": [{
        "animationDelay": lambda idx: idx * 100  # DON'T!
    }]
}

✅ DO use ECharts native string formatters or static values:

# ✅ CORRECT: Use ECharts template strings
option = {
    "tooltip": {
        "formatter": "{b}: {c}"  # Template string
    },
    "xAxis": {
        "axisLabel": {
            "formatter": "{value}%"  # Template string with formatting
        }
    },
    "yAxis": {
        "axisLabel": {
            "formatter": "${value}"  # Dollar sign prefix
        }
    },
    "series": [{
        "animationDelay": 100  # Static numeric value
    }]
}

ECharts Formatter Template Syntax:

  • {a} - series name
  • {b} - data name (category)
  • {c} - data value
  • {d} - percentage (for pie charts)
  • {value} - axis value
  • Supports prefix/suffix: '{value}%', '${value}', '{value} units'

If you need complex formatting logic, pre-process your data in Python before passing to ECharts rather than using formatters.

Reactive Updates with replaceMerge:

When updating ECharts dynamically (e.g., filtering data that changes the number of series), ECharts uses a merge strategy by default. This can cause old series to persist when series are removed.

✅ DO use replaceMerge option when series count can change:

# ✅ CORRECT: Use replaceMerge to fully replace series on updates
chart_pane = pn.pane.ECharts(
    self._chart_config,  # Reactive method or parameter
    options={"replaceMerge": ["series"]},  # Replace series array instead of merging
    sizing_mode="stretch_width",
    height=400,
)

❌ WITHOUT replaceMerge - old series persist:

# ❌ WRONG: Old series remain when filtering reduces series count
chart_pane = pn.pane.ECharts(
    self._chart_config,
    sizing_mode="stretch_width",
)
# If config changes from 4 series to 2, ECharts merges and keeps all 4!

Use replaceMerge for any chart where:

  • Users can filter data (year selectors, category filters)
  • The number of series changes dynamically
  • Data is grouped by categories that may be added/removed

DO make sure the chart title does not overlap with the rest of the plot including legend.

Date time widgets

When comparing to date or time values to Pandas series convert to Timestamp:

start_date, end_date = self.date_range
# DO convert date objects to pandas Timestamp for proper comparison
start_date = pd.Timestamp(start_date)
end_date = pd.Timestamp(end_date)
filtered = filtered[
    (filtered['date'] >= start_date) &
    (filtered['date'] <= end_date)
]

平台分布

Codex

35.07%
按下载量换算35

Claude

30.19%
按下载量换算30

Cursor

18.76%
按下载量换算19

Gemini CLI

10.6%
按下载量换算10

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

调用外部服务

该 Skill 可能调用第三方服务、云服务或外部模型 API,使用前需要确认账号、额度、数据发送范围和服务条款。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。目前只有一个公开来源,建议同时核对源仓库。

继续浏览同类 Skills