Feature Summary
There is no way to plot a result. Add result.plot(), with the drawing behind a renderer so matplotlib is one implementation rather than the only one, and a theme a user can override.
Motivation / Use Case
QProgramResult hands back a bare DataArray and the docs tell you to write matplotlib. xarray's own .plot() does not fill the gap, because a measurement array carries a trailing IQ dimension: a 1-D sweep looks two-dimensional and comes back as a heatmap with IQ on the x axis, and a 2-D sweep comes back as a histogram. The guide's da.sel(IQ="I").plot() works only because it peels that dimension off first, and it stops working the moment you want I and Q on the same axes.
Across the ten example pages there are 17 lines of hand-rolled matplotlib, covering four of the six shapes those pages use. The other six pages embed a figure and show no code at all, including the four-series overlay and the two-panel stack. The script that renders the documentation figures already implements every one of them with a light and a dark theme, and it does not ship in the wheel, so everyone reinvents it.
Depends on #31 for anything better than a bare variable id on an axis.
Proposed Solution
result = qp.simulate(program)
result.plot(m0) # a line per quadrature, kind inferred
result.plot(m0, channels="magnitude") # hypot(I, Q), which two examples hand-roll
result.plot(m0, x="freq", style=Style(theme=dark))
Build a backend-neutral description of the figure first, from numpy and xarray only, then let a renderer draw it. That seam is what makes a second renderer possible, and it is the same move explain already makes by reusing the .qp writer's serializers instead of writing its own. Register renderers the way register_sweep_source registers sweep sources.
kind is inferred from the shape once the trailing IQ and time dims are set aside: one remaining dim gives lines, two give a heatmap. Scatter stays explicit, since I against Q is a choice no shape inspection yields.
Two things to settle. A composed sweep dim should require x=, because coords["gain|freq"] does not raise, it returns a plain integer range, so guessing gives a wrong axis that looks entirely plausible. And whether QProgramResult gets a _repr_html_ the way waveforms have one.
Worth keeping out of the first cut: the two bespoke example layouts, the shared-x stack and the equal-aspect scatter with a threshold from the model. Nothing on the result says those belong in one figure in that arrangement, so returning composable axes and letting those pages keep their own code is the better answer.
Surfaces It Touches
The reference executor's results only. Nothing in .qp, the grammar or the capability protocol.
matplotlib has to stay behind the viz extra, so the model and theme layers must import numpy and xarray only, and pyplot stays inside the renderer. For the same reason themes and styles want to be plain frozen dataclasses.
Feature Summary
There is no way to plot a result. Add
result.plot(), with the drawing behind a renderer so matplotlib is one implementation rather than the only one, and a theme a user can override.Motivation / Use Case
QProgramResulthands back a bareDataArrayand the docs tell you to write matplotlib. xarray's own.plot()does not fill the gap, because a measurement array carries a trailingIQdimension: a 1-D sweep looks two-dimensional and comes back as a heatmap withIQon the x axis, and a 2-D sweep comes back as a histogram. The guide'sda.sel(IQ="I").plot()works only because it peels that dimension off first, and it stops working the moment you want I and Q on the same axes.Across the ten example pages there are 17 lines of hand-rolled matplotlib, covering four of the six shapes those pages use. The other six pages embed a figure and show no code at all, including the four-series overlay and the two-panel stack. The script that renders the documentation figures already implements every one of them with a light and a dark theme, and it does not ship in the wheel, so everyone reinvents it.
Depends on #31 for anything better than a bare variable id on an axis.
Proposed Solution
Build a backend-neutral description of the figure first, from numpy and xarray only, then let a renderer draw it. That seam is what makes a second renderer possible, and it is the same move
explainalready makes by reusing the.qpwriter's serializers instead of writing its own. Register renderers the wayregister_sweep_sourceregisters sweep sources.kindis inferred from the shape once the trailingIQandtimedims are set aside: one remaining dim gives lines, two give a heatmap. Scatter stays explicit, since I against Q is a choice no shape inspection yields.Two things to settle. A composed sweep dim should require
x=, becausecoords["gain|freq"]does not raise, it returns a plain integer range, so guessing gives a wrong axis that looks entirely plausible. And whetherQProgramResultgets a_repr_html_the way waveforms have one.Worth keeping out of the first cut: the two bespoke example layouts, the shared-x stack and the equal-aspect scatter with a threshold from the model. Nothing on the result says those belong in one figure in that arrangement, so returning composable axes and letting those pages keep their own code is the better answer.
Surfaces It Touches
The reference executor's results only. Nothing in
.qp, the grammar or the capability protocol.matplotlib has to stay behind the
vizextra, so the model and theme layers must import numpy and xarray only, and pyplot stays inside the renderer. For the same reason themes and styles want to be plain frozen dataclasses.