Key Takeaways: Plotly Graph Objects


  1. Graph Objects is the power-user API. Plotly Express produces most standard charts in one line; Graph Objects (plotly.graph_objects) exposes every property of every trace and every element of the layout. When Plotly Express runs out of flexibility, Graph Objects is the next step.

  2. Figures are data structures, not canvases. A Plotly Figure is a nested dictionary (or equivalent object hierarchy) with data (a list of traces), layout (everything else), and optional frames for animation. This is a fundamentally different mental model from matplotlib's imperative drawing. Describe what you want; plotly.js renders it.

  3. make_subplots handles complex grid layouts. For anything beyond Plotly Express's facet_col, make_subplots provides row/column spanning, shared axes, mixed subplot types, and secondary y-axes via the specs parameter. The API parallels matplotlib's GridSpec.

  4. The update_layout / update_traces / add_trace pattern is idiomatic. Build figures incrementally: start with a base (either go.Figure() or px.*), add traces, and chain updates to customize. The selector argument of update_traces is a small superpower for modifying specific subsets of traces without looping.

  5. Dual y-axes are powerful and ethically fraught. Use them only when the two variables have a genuine physical relationship, disclose the scales clearly, and prefer alternatives (scatter plots, stacked charts) when the audience is general. The ethical warning from Chapter 4 applies in full force.

  6. updatemenus adds custom interactive controls. Buttons and dropdowns are layout objects that modify the figure when clicked. Each button specifies a method ("update", "restyle", "relayout", "animate") and args that describe the change. The API is verbose but flexible.

  7. Annotations, reference lines, and regions are built-in. add_annotation, add_hline, add_vline, add_hrect, and add_vrect provide convenience methods for the most common overlays. Under the hood, they all manipulate the layout.annotations and layout.shapes lists.

  8. to_dict() is the debugging tool of choice. When a figure does not render as expected, call fig.to_dict() and inspect the nested dict. The answer is almost always visible once you see the full spec — usually a misspelled property name or a property on the wrong object (trace vs. layout).

  9. Scattergl handles the large-data case. For scatter plots with more than ~50,000 points, switch from go.Scatter to go.Scattergl to use WebGL rendering. Plotly Express exposes this via render_mode="webgl". Beyond about 1 million points, pre-aggregate (bin, sample, summarize) before plotting.

  10. Templates enable organizational consistency. pio.templates is the Plotly equivalent of matplotlib style sheets. Define a custom template with your brand colors, fonts, and default margins; set it as the default with pio.templates.default = "simple_white+brand". Subsequent figures inherit the styling automatically.


Chapter 22 introduces Altair, which takes a fundamentally different approach to declarative interactive visualization. Where Plotly describes figures as traces + layout, Altair describes them as data + marks + encodings — the grammar of graphics made explicit. Both approaches are valid, and knowing both gives you more tools to reach for when a specific chart demands a specific philosophy.