This repository powers the Bokeh example gallery. It contains a static landing page and Python applications served through Bokeh's ASGI adapter. The examples are grouped by use case and domain, and the catalog records how each one runs.
catalog.pyis the source of truth for routes and gallery metadata.apps/contains self-contained applications using public datasets or clearly labeled computed data.site/contains the shared visual system, landing-page template, Bokeh document template, and deployed error page.framework-demos/builds the unlisted BokehJS framework examples as static pages, independently of the Python applications.asgi.pyserves the landing page, assets, health endpoint, and Bokeh routes.deploy/ecs-task-definition.jsonis the application-owned deployment template.
The explicit runtime metadata leaves room for BokehJS framework examples and Pyodide or PyScript examples without putting them through the Python server application lifecycle.
Most examples combine several Bokeh features around a practical problem. The vehicle demo recomputes a linked histogram from the current selection. The market simulator connects a seeded, unlimited OHLC stream to volume and MACD. The oscillator demo combines MathText and streaming with three views of the same simulation. The terrain demo links filled contours to a transect that can be moved and rotated.
Other applications map regional airport access over CARTO tiles, use NetworkX for graph analysis, and combine Xarray, Numba, and scikit-image for image processing. Public inputs come with the installed libraries. Computed examples say when their data is synthetic. The container needs no external data service at runtime, although the browser fetches basemap tiles for the airport map.
Gallery previews are crops of Bokeh output from the corresponding application. The Hubble preview and application both use the public-domain NASA/STScI Hubble Deep Field image.
The palette and footer match the Bokeh marketing site. Layouts vary with the example, and toolbars appear only where navigation or selection is useful.
Each container runs one Uvicorn worker and one BokehASGI instance. Because
Bokeh session state is local to the process, ECS tasks provide horizontal
concurrency. ALB cookie affinity keeps each browser on the same task for the
life of its session.
The production image runs free-threaded Python 3.14 with the GIL disabled. CI checks the active GIL state after importing every application, and the deployment workflow builds the image for ARM64 Fargate tasks.
The public endpoints are:
/: generated gallery/404.html: shared Bokeh 404 page/healthz: runtime health and active Python GIL state/robots.txt: crawler policy and sitemap discovery/sitemap.xml: homepage and listed demo routes generated from the catalog/.well-known/security.txt: private vulnerability-reporting contact and policy/monitor: directly accessible, sanitized view of the whole demo service and the task serving the session; it is not listed in the gallery yet/assets/*: shared site CSS- every route declared in
catalog.DEMOS
All HTTP responses carry the same browser security policy. Stateful Bokeh
documents are explicitly non-cacheable; static site assets, crawler files, and
the security contact can be cached for one hour. Catalog and application pages
also provide canonical, Open Graph, and large-card metadata using the shared
site/social-preview.png image. Regenerate that PNG from the maintainable SVG
with:
rsvg-convert --width 1200 --height 630 \
--output site/social-preview.png site/social-preview.svgsite/404.html is an exact copy of the page introduced by
bokeh/infra#6 and maintained at
components/error-pages/404/404.html in that repository. Update it from the
infra source instead of editing the local copy. The ASGI wrapper also returns
this page, with status 404, for missing application routes and assets.
The image uses free-threaded Python 3.14, the checked-in uv lockfile, and Bokeh
3.10.0. It loads the matching BokehJS bundles from Bokeh's CDN.
docker build --tag bokeh-demo .
docker run --rm --publish 5006:5006 bokeh-demoOpen http://localhost:5006.
Install uv, then run the ASGI server. uv creates
and syncs the locked environment automatically:
uv run --locked uvicorn asgi:applicationOpen http://127.0.0.1:8000.
The biomass explorer uses the subscribed Arraylake Icechunk repository for
native 100 m detail when ARRAYLAKE_API_TOKEN is set. Keep that service-account
token in the runtime environment or deployment secret store, never in this
repository. Without it, the application remains usable through the public CTrees
COG source; broad world views always use COG overviews to avoid scanning the
26 TB native Icechunk array. At service startup, the app caches all 26 annual
windows for its initial Pará footprint (about 16.5 MB), making every initial
year comparison immediate without preloading arbitrary locations.
Measure that user-visible speedup against a cold query with:
ARRAYLAKE_API_TOKEN=... uv run --locked python scripts/benchmark_biomass.pyThe benchmark exits unsuccessfully unless startup warming makes the same native-detail comparison at least five times faster.
Outside ECS, the monitor uses real current-process measurements and an in-memory service registry. For deterministic screenshots or UI development, run it with three clearly labeled simulated task reports:
DEMO_MONITOR_SOURCE=deterministic uv run --locked uvicorn asgi:application/healthz returns {"status":"ok","python_gil":"disabled"} in the production
runtime. If PYTHON_GIL=0 was requested but an imported extension turns the GIL
back on, the endpoint remains HTTP 200 and reports
{"status":"degraded","reason":"python_gil_enabled","python_gil":"enabled"}.
The container stays available while the response explains the degraded state.
Install the Git hooks once after cloning:
uv run --locked pre-commit installRun the same hooks across the checkout at any time:
uv run --locked pre-commit run --all-filesThe unlisted pages at /react, /vue, /svelte, /components, and /nextjs
show the same wave interference lab through the BokehJS framework adapters. /next.js is an alias for /nextjs.
They share the site's header, footer, and visual styles, but run entirely in
the browser. Each page links to its full source directory and shows a short
adapter embedding snippet. Each source link opens a complete, independently
runnable app: React, Vue,
Svelte, Web Components,
and Next.js. Every app includes its own dependencies,
lockfile, build configuration, plotting code, styles, and README. Its BokehJS
4.0 development packages are pinned independently. The existing Python applications continue to
use Bokeh 3.10.0 and its matching CDN resources.
With Node.js 24 or newer (which includes npm), copy any one app directory and run
npm ci followed by npm run dev there. It does not need
the parent project or another example. Each app also provides check, build,
and preview scripts; see its README for details.
To build all five pages for the demo site, run from the repository root:
cd framework-demos
npm ci
npm run install:apps
npm run build
npm run previewOpen http://localhost:4173/react (or another framework route). To serve the
pages alongside the Python gallery, build them first, then run the usual
uv run --locked uvicorn asgi:application command from the repository root.
Without a frontend build, the Python gallery still works and framework routes
return the shared 404 page. Docker builds the framework pages automatically;
Node.js is only used in the build stage.
The site build sets each app's BOKEH_DEMO_BASE asset prefix and copies its
output into site/frameworks/. The app directories include snapshots of the
site chrome and styles so they remain independently runnable; keep these
snapshots in sync when changing the demo site's visual design. Generated files
are not committed. Framework
pages are omitted from the gallery and sitemap. The Next.js example uses a
static export with browser-side interactive components, so it needs no Node.js
server at runtime.
Check types and run the browser tests from framework-demos/:
npm run check
npm run build
npm exec -- playwright install chromium
npm test
npm run test:standaloneThe standalone check copies each app outside the repository, installs from its own lockfile, checks types, builds it, and runs the same browser interactions against its local preview. CI verifies both these copies and the combined site.
The tests use the complete dependency set pinned in uv.lock:
uv run --locked pytestPass a test module or node ID to narrow the run:
uv run --locked pytest tests/test_cellular_automata.py
uv run --locked pytest tests/test_cellular_automata.py::test_cellular_automata_compares_rules_from_the_same_stateThe CI workflow installs the pinned 3.10 dependency, constructs every Bokeh document, exercises static ASGI responses, and checks the container build.
The bokeh/infra repository owns the AWS resources under
terraform/stacks/aws-demo. This repository contains no Terraform.
The Publish and deploy workflow runs for every push to main and may also
be started manually. It uses GitHub OIDC to build a Linux ARM64 image natively
on GitHub's ARM64 runner, push it to ECR under an immutable sha-* tag,
register a new ECS task definition, update the worker service, wait for
stability, and verify the production health endpoint.
Pull requests run all checks and build the container without publishing or
deploying it. Merging to main is therefore the normal release action; no
Terraform command is needed for an application-only change. The workflow
summary records the immutable image digest used by ECS.
To roll back an application release, rerun the workflow for the desired commit
or revert the change on main. ECR retains the twenty most recent immutable
release images. Infrastructure operations are documented in the bokeh/infra
AWS demo stack README.
See Production operations for rollout verification, CloudWatch callback timings, event-loop lag queries, and smoke-test guidance. The monitor data-source and privacy note documents its public contract, DynamoDB exchange, measurement scopes, local behavior, deployment order, and cost boundary.



