FFastero

Connect any database. Ask in plain English.

Try free
Back to blog

Blog article

Plotly vs Bokeh: Which Interactive Python Library for Your Dashboards?

Plotly Express gives you interactive charts in one line with polished defaults. Bokeh gives you lower-level control over widgets, callbacks, and server-side Python logic. Here's how to choose between them for dashboards and data apps.

Fastero Dev TeamFastero Dev Team
2026-08-12
plotlybokehpythoninteractive-chartsdata-visualizationdashboards
Plotly vs Bokeh: Which Interactive Python Library for Your Dashboards?

Plotly and Bokeh both produce interactive, browser-based charts from Python — hover tooltips, zoom, pan, the works. The difference is altitude. Plotly Express gets you a polished interactive chart in one function call with smart defaults. Bokeh gives you granular control over every widget, callback, and DOM element, which pays off when you need interactivity beyond what a charting library normally offers.

How do the rendering architectures differ?

Both generate output that runs in the browser, but the mechanics diverge in an important way.

Plotly creates a JSON spec in Python and hands it to plotly.js for browser-side rendering. Your Python code describes the chart; the browser draws it.

Bokeh also generates JSON, but renders via BokehJS, its own TypeScript runtime. Bokeh's document model maintains a server-side state that mirrors the client — this two-way sync is what makes Bokeh Server possible.

         Plotly                          Bokeh
  ┌──────────────┐              ┌──────────────┐
  │  Python code │              │  Python code │
  │  (Express /  │              │  (figure /   │
  │  graph_objs) │              │  models)     │
  └──────┬───────┘              └──────┬───────┘
         │ JSON spec                   │ JSON doc
         ▼                             ▼
  ┌──────────────┐              ┌──────────────┐
  │  plotly.js   │              │  BokehJS     │
  │  (browser)   │              │  (browser)   │
  └──────────────┘              └──────┬───────┘
                                       │ websocket

                                ┌──────────────┐
                                │ Bokeh Server │
                                │ (Python proc)│
                                └──────────────┘

That websocket is the key architectural difference. Plotly charts are fire-and-forget — Python creates the spec, the browser renders it, done. Bokeh charts can maintain a live connection back to a running Python process, so your callbacks execute in Python, not JavaScript.

How do the APIs feel in practice?

Plotly Express is the fastest path to an interactive chart I've used in Python:

import plotly.express as px
 
fig = px.scatter(df, x="ad_spend", y="conversions",
                 color="channel", size="roas",
                 hover_data=["campaign_name"])
fig.show()

Five lines — interactive scatter plot with color legend, size encoding, hover tooltips. Bokeh's equivalent takes more setup:

from bokeh.plotting import figure, show
from bokeh.models import ColumnDataSource, HoverTool
 
source = ColumnDataSource(df)
p = figure(width=800, height=400, title="Ad Spend vs Conversions")
p.scatter("ad_spend", "conversions", source=source,
          size="roas", color="color_mapped",
          legend_field="channel")
p.add_tools(HoverTool(tooltips=[
    ("Campaign", "@campaign_name"),
    ("ROAS", "@roas{0.2f}")
]))
show(p)

More code, but you get explicit tooltip formatting, direct column references, and the ColumnDataSource pattern that enables cross-filtering and linked selections later. Learning curve reflects the trade-off — Express: 20 minutes to productive. Bokeh: an afternoon, then it clicks.

Fastero

Connect your database. Ask questions. Get dashboards.

Postgres, BigQuery, Snowflake, and 10+ sources — live-connected, AI-powered, no dashboard builder learning curve.

Try free →

What does the feature comparison look like?

Dimension Plotly Bokeh
One-liner charts Plotly Express — genuinely one call No equivalent; always multi-step
Default aesthetics Polished, modern out of the box Functional, needs more styling work
Hover/zoom/pan Built-in on every chart Built-in, with more granular tool config
Custom widgets Via Dash (separate framework) Native — sliders, dropdowns, text inputs
Server-side callbacks Dash (separate process) Bokeh Server (built-in)
JS callbacks Limited (no official API) First-class CustomJS callbacks
Pandas integration Pass DataFrames directly to Express ColumnDataSource wraps DataFrames
3D charts Excellent (WebGL) Limited, not a strength
Statistical charts Box, violin, histogram, density in Express Box, histogram; fewer presets
Streaming data Via Dash intervals Native ColumnDataSource.stream()
Chart types 50+ trace types Fewer presets, flexible glyph primitives
Embedding in web apps HTML export, iframe, Dash HTML export, embed.js, Bokeh Server
Large datasets WebGL mode to ~1M points WebGL + Datashader integration
Docs quality Extensive, well-organized Good, harder to navigate
Community size Larger (Plotly + Dash ecosystem) Smaller, HoloViz-adjacent

When does Bokeh's interactivity model actually matter?

Plotly charts ship with excellent defaults — hover, zoom, pan, box select, lasso select. But if you want a slider that re-queries a database and updates a chart, you need Dash. At that point you're building a web application, not configuring a chart.

Bokeh blurs that line. Widgets go directly into a Bokeh layout, wired to Python callbacks via Bokeh Server, and the chart updates in-place over a websocket:

from bokeh.layouts import column
from bokeh.models import Slider
from bokeh.plotting import figure, curdoc
 
p = figure(width=600, height=300)
line = p.line(x, y)
 
slider = Slider(start=1, end=100, value=10, title="Window")
 
def update(attr, old, new):
    # This runs server-side in Python — full access to pandas, numpy, your DB
    smoothed = df["value"].rolling(slider.value).mean()
    line.data_source.data["y"] = smoothed
 
slider.on_change("value", update)
curdoc().add_root(column(slider, p))

That callback runs in Python on the server — it can query a database, call an API, run NumPy. The result patches the client via websocket. This is Bokeh's genuine advantage: server-side Python callbacks with live chart updates, no Dash required.

How do Dash and Bokeh Server stack up as app frameworks?

           Dash                          Bokeh Server
  ┌─────────────────┐            ┌─────────────────┐
  │  Flask + React   │            │  Tornado server  │
  │  (full SPA)      │            │  + websockets    │
  ├─────────────────┤            ├─────────────────┤
  │  @callback deco  │            │  on_change()     │
  │  HTTP round-trip │            │  live doc sync   │
  └─────────────────┘            └─────────────────┘

Dash is a full web application framework — React, rich components, multi-page apps, auth plugins. Declarative callbacks over HTTP. Bokeh Server is lighter — it syncs a Bokeh document between Python and browser over websockets, great for interactive visualizations with server-side logic, but less suited for full apps with navigation.

Dash wins for production apps. Bokeh Server wins when you just need Python callbacks on charts without a full framework. For the broader comparison, see our Streamlit vs Dash deep dive.

How do they handle large datasets?

Both hit the same browser-side bottleneck: too many data points in the DOM kills performance. Both offer WebGL rendering as the escape hatch.

Plotly's Scattergl and render_mode='webgl' push rendering to the GPU — roughly 500k-1M scatter points. Beyond that, you're downsampling (see Plotly vs Matplotlib). Bokeh's WebGL is comparable, but its edge is Datashader integration via HoloViz — server-side rendering of millions of points into an image, with hover still working on aggregated data.

For datasets under 100k points — most business dashboards — performance is a non-issue with either library.

Which library should you pick?

Pick Plotly when:

  • You want interactive charts with minimal code (Express is unmatched)
  • You're building a data app with Dash or Streamlit
  • You need 3D, geo maps, or statistical charts out of the box
  • You're embedding charts in existing web apps via HTML export

Pick Bokeh when:

  • You need server-side Python callbacks without a full app framework
  • You're building custom interactive tools (linked brushing, streaming, custom selections)
  • You're in the HoloViz ecosystem (Panel, HoloViews, Datashader)
  • You need CustomJS callbacks for client-side interactivity without a server

The honest default: for most data engineers building dashboards from database data, Plotly is the better starting point. Faster to learn, better defaults, and Dash gives you an upgrade path. Bokeh shines in specific niches: streaming data, custom scientific tools, and apps where every interaction needs server-side Python.

Both still require writing Python, managing dependencies, and handling deployment. If what you actually need is interactive dashboards from your database, Fastero skips the code entirely — connect your data source, describe what you want, and get a live dashboard.

FAQ

Can I use Plotly and Bokeh in the same project? Yes, but there's rarely a reason to. They solve the same problem with different trade-offs. If you're using Panel as your app framework, it renders both natively — that's the one scenario where mixing makes sense.

Is Bokeh harder to learn than Plotly? The ColumnDataSource/glyph model takes longer to internalize than px.scatter(), but once it clicks, Bokeh's explicitness makes complex charts easier to debug. Budget 2-3 hours for the fundamentals vs 30 minutes for Plotly Express.

Does Plotly work with Grafana or other dashboard tools? Not directly — Plotly charts are self-contained HTML/JS and don't plug into Grafana's panel system. We covered that trade-off in Grafana vs Python for Data Dashboards.

Can Bokeh Server handle production traffic? For internal tools with a few concurrent users, yes. Each user gets a dedicated Python session, so memory scales linearly with connections. For hundreds of concurrent users, you'll need reverse proxies and session limits.

Which has better pandas integration? Plotly Express accepts DataFrames directly — columns become axis references. Bokeh wraps DataFrames in ColumnDataSource, adding a step but giving explicit control over live updates via .stream() and .patch(). Plotly is more convenient for one-off charts; Bokeh is more capable for live-updating ones.

What about Altair as a third option? Altair is declarative (grammar-of-graphics) and renders via Vega-Lite. Elegant for statistical visualization, but with a lower customization ceiling. Good for exploratory analysis; for dashboards, Plotly or Bokeh give you more control.


Try Fastero free — interactive dashboards from your database, no Python setup or chart library decisions. No credit card required.

Ready to try it yourself?

Connect your database, ask questions in plain English, and get live dashboards — in under 2 minutes. No credit card required.