render_pygwalker
render_pygwalker class
Reactively render a PyGWalker data exploration app.
Usage Source
render_pygwalker(
_fn: Optional[ValueFn[ValueT]] = None,
*,
width: Optional[str] = None,
height: Optional[str] = None,
fill: Optional[bool] = None,
fillable: Optional[bool] = None,
rate_policy: Optional[RatePolicy] = None,
rate_delay: Optional[float] = None,
)@render_pygwalker is a decorator that creates a render function – a function that returns the data to explore and re-runs when the reactive values it reads change:
import pandas as pd
import pygwalker
from shinywidgets import render_pygwalker
pygwalker.GlobalVarManager.set_privacy("offline")
df = pd.DataFrame({"a": [1, 2, 3], "b": ["x", "y", "z"]})
@render_pygwalker
def walker():
return dfThe render function may return either a pandas DataFrame (which is coerced to a PyGWalker widget; requires pip install 'shinywidgets[pygwalker]') or a widget created by pygwalker.api.anywidget.walk() (use this to pass options like theme_key). A polars DataFrame is coerced too, but only when the installed pygwalker can read it (pygwalker releases prior to 0.6 can’t read polars >= 1.0); unsupported combinations are rejected with a hint to convert it (df.to_pandas()). Don’t use the top-level pygwalker.walk(): outside of Jupyter, it starts a blocking web server instead of returning a widget.
Note
Accessing the rendered widget: the render function gains two read-only attributes: .value, the value it most recently returned, and .widget, the rendered PyGWalker widget.
Responding to user interaction: the widget has no traits that track the explorer’s state, so there’s nothing to reactive_read().
Mutating the widget: changing the explorer means re-rendering it. Each render sends PyGWalker’s large JavaScript bundle to the browser, so avoid unnecessary re-renders.
Outside of filling layouts, give it a height (e.g., "800px") that fits PyGWalker’s UI.
Privacy: by default, PyGWalker sends usage events and checks for updates, from both the Python process and each visitor’s browser. Call pygwalker.GlobalVarManager.set_privacy("offline") (before rendering) to disable both.
Security: PyGWalker computes charts by running SQL that the browser sends on DuckDB’s process-wide default connection, and any visitor can send arbitrary SQL, including SQL that reads or writes files on the server. So, this renderer requires that connection to be locked down before it renders anything; if it isn’t, rendering raises an error. Do this when the app starts (this also applies to any other code in the process that uses duckdb.sql() and friends without a connection):
import duckdb
# Set first: PyGWalker sets it per query, which a locked configuration refuses
duckdb.execute("SET TimeZone = 'UTC'")
duckdb.execute("SET enable_external_access = false")
duckdb.execute("SET lock_configuration = true")lock_configuration is permanent for the connection, so set anything else you need first (e.g., SET memory_limit = '2GB'). shinywidgets also restricts the SQL the browser can send to single SELECT statements against the widget’s own data (no DDL and no other tables or views, which the connection shared with every other PyGWalker widget in the process would otherwise expose to every visitor), and rejects the browser actions that can’t be made safe: upload_spec_to_cloud with a visitor-supplied Kanaries token (it would overwrite the server’s stored credentials) and open_in_desktop (it launches the server’s gw:// handler).
Even then, the explorer is best suited to trusted users. Every PyGWalker widget in the process shares the one connection and one table name (pygwalker_mid_table), so per-user data is kept apart only by each request re-registering its own data right before it queries – which holds while Shiny handles requests on a single thread, but is not a boundary you can build on. And a visitor can still send expensive queries, which block the Python process (every session, not just theirs) while they run. If different users must explore different, mutually private datasets, prefer a renderer that keeps data apart by design.
Parameters
width : Optional[str] = None-
A CSS length unit (e.g.,
"400px"or"100%") for the output’s width. height : Optional[str] = None-
A CSS length unit for the output’s height. When
None(the default), the output is designed to fill the height of its parent container (seefillandfillable). fill : Optional[bool] = None-
Whether the output should grow or shrink to fit its parent container. When
None(the default), this isTrueifheightis not specified. fillable : Optional[bool] = None-
Whether the output container should fill available space (scrolling its contents on overflow). When
None(the default), this isTrueifheightis not specified.
See also
output_widget(): in Shiny Core, the UI needs this to hold the output (Shiny Express displays it where the render function is defined).