Quiz: Plotly Graph Objects
Answer all 20 questions. Answers and explanations are hidden below each question.
Part I: Multiple Choice (10 questions)
Q1. Which of the following is the lower-level Plotly API that Plotly Express wraps?
A) plotly.core
B) plotly.graph_objects
C) plotly.figure_factory
D) plotly.io
Answer
**B.** `plotly.graph_objects` (conventionally imported as `go`) is the lower-level API. `plotly.figure_factory` is a separate module for niche chart types. `plotly.io` is for input/output (write_html, write_image).Q2. The three top-level components of a Plotly Figure are:
A) data, style, config B) traces, axes, legend C) data, layout, frames D) x, y, z
Answer
**C.** A Figure has `data` (a list of traces), `layout` (everything non-trace), and optional `frames` for animation.Q3. Which function creates a subplot figure with a secondary y-axis?
A) go.Figure(secondary_y=True)
B) make_subplots(specs=[[{"secondary_y": True}]])
C) go.Layout(secondary_y=True)
D) fig.add_secondary_y()
Answer
**B.** The `make_subplots` function with `specs=[[{"secondary_y": True}]]` creates a single subplot that has a secondary y-axis. Traces added with `secondary_y=True` use the right axis.Q4. Which method modifies only traces that match a specific condition?
A) fig.update_traces(..., selector=dict(mode="markers"))
B) fig.filter_traces(...)
C) fig.match_traces(...)
D) fig.where(...)
Answer
**A.** `update_traces` accepts a `selector` argument (a dict, int, or callable) that restricts the update to matching traces. Without a selector, it updates all traces.Q5. Which hovermode shows a single unified tooltip listing all trace values at the hovered x?
A) "closest"
B) "x"
C) "x unified"
D) "unified"
Answer
**C.** `"x unified"` shows one tooltip with all traces' values at the hovered x. `"x"` shows separate tooltips per trace at the same x. `"closest"` (the default) shows only the nearest point.Q6. Which trace type should you use for a scatter plot with 200,000 points?
A) go.Scatter
B) go.Scattergl
C) go.ScatterLarge
D) go.HistContour
Answer
**B.** `Scattergl` uses WebGL rendering (GPU-accelerated) and handles hundreds of thousands of points. `Scatter` uses SVG and becomes sluggish past ~50k points.Q7. What does fig.to_dict() return?
A) A CSV export of the figure's data B) The full figure as a nested Python dictionary C) A list of trace names D) A JSON string
Answer
**B.** `to_dict()` returns a nested dictionary mirroring the figure's structure. Use it for debugging (inspect what Plotly will render) and for serialization workflows.Q8. Which of the following is NOT added via updatemenus?
A) A dropdown menu B) Toggle buttons C) Animation controls D) A colorbar
Answer
**D.** Colorbars are part of continuous-color traces (set via `showscale=True`, `colorbar=dict(...)`), not updatemenus. Dropdowns, buttons, and animation play controls are all updatemenus types.Q9. To add a horizontal reference line at y=0, the simplest method is:
A) fig.add_trace(go.Line(y=[0, 0]))
B) fig.add_hline(y=0)
C) fig.update_layout(y0=0)
D) fig.add_annotation(y=0)
Answer
**B.** `add_hline` is a convenience method for horizontal lines. Similarly, `add_vline` for vertical lines, `add_hrect` for horizontal bands, and `add_vrect` for vertical bands.Q10. What is the chapter's threshold concept?
A) Interactive is not a gimmick B) Figures are data structures C) Defaults are wrong D) Match the chart to the question
Answer
**B.** The chapter argues that a Plotly figure is a nested data structure (a dict), not a canvas. You describe what you want, and plotly.js renders it. This is fundamentally different from matplotlib's imperative drawing model.Part II: Short Answer (10 questions)
Q11. Describe the difference between fig.update_layout() and fig.update_traces().
Answer
`update_layout` modifies the layout object: title, axes, legend, background, margins, annotations, shapes, updatemenus. `update_traces` modifies traces: marker, line, mode, name, visible, showlegend, hovertemplate. Properties are either on the layout or on a trace — confusing the two produces silent failures.Q12. Explain why dual-y-axis charts are considered ethically fraught, and describe two mitigation strategies.
Answer
The visual correlation (or anti-correlation) between the two series depends on the chosen axis scales, not just on the data. By rescaling, you can make any two series appear to track. **Mitigations**: (1) only use dual-y when the two variables have a genuine physical/mechanistic relationship; (2) clearly disclose the scale choices; (3) prefer alternatives like scatter plots of x vs. y directly, or two stacked charts with a shared x-axis.Q13. Write the code to convert a Plotly Express scatter plot into a figure with an added trendline trace from Graph Objects.
Answer
import plotly.express as px
import plotly.graph_objects as go
import numpy as np
fig = px.scatter(df, x="x", y="y")
slope, intercept = np.polyfit(df["x"], df["y"], 1)
x_line = np.linspace(df["x"].min(), df["x"].max(), 50)
y_line = slope * x_line + intercept
fig.add_trace(go.Scatter(x=x_line, y=y_line, mode="lines", name="Trend"))
Q14. What is the specs argument in make_subplots, and what does it control?
Answer
`specs` is a 2D list (mirroring the grid shape) of dicts that describe each subplot's type and spanning behavior. Each cell can specify `type` (`"xy"`, `"polar"`, `"scene"`, `"mapbox"`, etc.) for mixed subplot types, `colspan`/`rowspan` for spanning cells, and `secondary_y=True` for dual-axis subplots. Cells occupied by a spanning panel from an earlier cell should be `None`.Q15. How do you debug a Plotly figure that is not rendering the way you expect?
Answer
Step 1: call `fig.to_dict()` and inspect the full spec. Look for the property you are trying to set. If it is missing or misspelled, your update call did not land. Step 2: consult the Plotly reference documentation (plotly.com/python/reference) for the correct property name and location (trace vs. layout). Step 3: compare against a working example from the documentation to see what the spec should look like.Q16. Describe the use of add_trace in the context of make_subplots. What additional arguments do you typically pass?
Answer
`add_trace` adds a trace to an existing figure. For subplot figures from `make_subplots`, you pass `row` and `col` to specify which cell the trace belongs to. For dual-axis subplots, you also pass `secondary_y=True` to put the trace on the secondary axis. Example: `fig.add_trace(go.Scatter(...), row=2, col=1, secondary_y=False)`.Q17. What does the magic underscore notation mean in fig.update_layout?
Answer
Plotly allows nested properties to be specified with underscore-separated keys. `fig.update_layout(xaxis_title="Year")` is equivalent to `fig.update_layout(xaxis=dict(title="Year"))`. The magic underscore is more concise and idiomatic for single-value updates; the nested dict form is better when you are setting many sub-properties at once.Q18. Why might a static PNG export with kaleido fail in a containerized environment (Docker, CI), and how do you fix it?
Answer
Kaleido uses a bundled Chromium-like rendering engine that requires certain system libraries at runtime. In minimal Docker images, these libraries are often missing. The fix is to install the required packages (the specific list depends on the base image; `libglib2.0-0`, `libnss3`, `libexpat1`, etc. are common). The kaleido GitHub repo has a FAQ section with the specific commands for common environments.Q19. Describe the workflow of starting with Plotly Express and dropping to Graph Objects for specific customizations.
Answer
Start with a Plotly Express call that produces the base chart (`px.scatter`, `px.line`, etc.). Then apply Graph Objects modifications through `fig.update_layout`, `fig.update_traces`, `fig.add_trace`, `fig.add_annotation`, etc. The Plotly Express figure is already a `go.Figure` object, so all Graph Objects methods are available on it. This hybrid workflow is idiomatic — you get the conciseness of Plotly Express for the bulk of the chart and the power of Graph Objects for specific customizations.Q20. Explain why the chapter says "if your Plotly Express call requires more than three chained fig.update_* calls, consider rewriting with Graph Objects."
Answer
A long chain of post-construction updates buries the figure's intent in incremental patches. The result is hard to read and hard to modify. A direct Graph Objects construction puts the full spec in one place, making the chart's design visible at a glance. The threshold of "three updates" is heuristic — the exact number depends on the updates' complexity — but the principle is that verbose explicit construction is often clearer than patchwork customization on top of a convenience wrapper.Scoring Rubric
| Score | Level | Meaning |
|---|---|---|
| 18–20 | Mastery | You can build complex Plotly figures from scratch and know when to use Plotly Express vs. Graph Objects. |
| 14–17 | Proficient | You know the main APIs; review the subplots and updatemenus sections. |
| 10–13 | Developing | You grasp the architecture; re-read Sections 21.4-21.8 and work all Part B exercises. |
| < 10 | Review | Re-read the full chapter and complete all Part A and Part B exercises before moving on to Chapter 22. |
After this quiz, continue to Chapter 22 (Altair), which introduces the declarative grammar-of-graphics approach to interactive visualization.