Skip to content

Feature: properly route multi-variable StateMonitors to subplots#64

Open
Utkarsha2811 wants to merge 5 commits intobrian-team:masterfrom
Utkarsha2811:feature-multivar-plotting
Open

Feature: properly route multi-variable StateMonitors to subplots#64
Utkarsha2811 wants to merge 5 commits intobrian-team:masterfrom
Utkarsha2811:feature-multivar-plotting

Conversation

@Utkarsha2811
Copy link
Copy Markdown
Contributor

@Utkarsha2811 Utkarsha2811 commented Mar 14, 2026

Closes #8

Summary

1. brian_plot() now supports StateMonitor objects that record multiple variables. Instead of raising a TypeError, it creates stacked subplots with a shared time axis — one subplot per variable — and returns a list of Axes.
2. var_name and var_unit accept per-variable dicts for custom labelling, e.g. var_name={'v': 'membrane potential', 'I': 'input current'}.
3. The multi-variable logic is shared between the StateMonitor and StateMonitorView code paths via two private helpers (_resolve_var_kwds and _plot_state_variables), eliminating the previous code duplication.
4. Users may still pass pre-created axes (one per variable); a clear TypeError is raised if the count doesn't match.

Changes

1. brian2tools/plotting/base.py — extracted _resolve_var_kwds and _plot_state_variables helpers; simplified brian_plot's StateMonitor / StateMonitorView branches to two-line delegates; updated docstring.
2. brian2tools/tests/test_plotting.py — added test_plot_multivar_monitors (auto-subplot, pre-created axes, wrong-length axes, StateMonitorView).
3. docs_sphinx/user/plotting.rst — added "Multiple state variables" subsection with usage examples.

Copy link
Copy Markdown
Member

@mstimberg mstimberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the PR, I've left a few comments. Could you also add a test (only testing whether it works at all and returns the correct thing) and mention the feature in the documentation?

Comment thread brian2tools/plotting/base.py Outdated
Comment on lines +95 to +100
try:
axes_arr = np.asarray(axes).ravel()
assert len(axes_arr) == n_vars
except Exception:
raise TypeError("If multiple variables are recorded, 'axes' must "
"be an iterable of matching length.")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not to happy about the except Exception – maybe just check if len(axes_arr) == n_vars? If something fails during the conversion to an array, this itself should already raise a meaningful error, I think.

Comment thread brian2tools/plotting/base.py Outdated
Comment on lines +105 to +108
if 'var_name' not in kwds_var:
kwds_var['var_name'] = var_name
if 'var_unit' not in kwds_var and isinstance(values, Quantity):
kwds_var['var_unit'] = _get_best_unit(values)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder whether we wouldn't need to allow for a slightly more complex syntax here, since a single var_name or var_unit argument doesn't make much sense when a user recorded several variables. Maybe a mapping? Something along the lines of:

mon = StateMonitor(group, ["I", "v"], record=True)
# ...
brian_plot(mon,
           var_name={"I": "input current",
                     "v": "membrane potential"},
           var_unit={"I": nA, "v", mV})

Comment thread brian2tools/plotting/base.py Outdated
Comment on lines +114 to +123
n_vars = len(monitor.record_variables)
if n_vars == 1:
var_name = monitor.record_variables[0]
values = getattr(brian_obj, var_name).T
if 'var_name' not in kwds:
kwds['var_name'] = var_name
if 'var_unit' not in kwds and isinstance(values, Quantity):
kwds['var_unit'] = _get_best_unit(values)
return plot_state(brian_obj.t, values, axes=axes, **kwds)
else:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part is not quite correct: if you hand over a StateMonitorView, you only have a single variable. The situation here is code like:

mon = StateMonitor(group, ["I", "v"], record=True)
brian_plot(mon.I)  # mon.i is a StateMonitorView

The check verifies whether the monitor recorded several variables, but this doesn't matter here.

…sts & docsAddress review comments: extract helpers, support dict kwargs, add tests & docs
@Utkarsha2811
Copy link
Copy Markdown
Contributor Author

Test results (all passing):

brian2tools/tests/test_plotting.py::test_plot_monitors PASSED [ 20%]
brian2tools/tests/test_plotting.py::test_plot_multivar_monitors PASSED [ 40%]
brian2tools/tests/test_plotting.py::test_plot_synapses PASSED [ 60%]
brian2tools/tests/test_plotting.py::test_plot_morphology PASSED [ 80%]
brian2tools/tests/test_plotting.py::test_plot_morphology_values PASSED [100%]
======================= 5 passed, 110 warnings in 4.47s =======================

@Utkarsha2811 Utkarsha2811 marked this pull request as ready for review March 29, 2026 20:29
@Utkarsha2811 Utkarsha2811 requested a review from mstimberg March 29, 2026 20:33
@mstimberg
Copy link
Copy Markdown
Member

Thanks for the changes, I won't be able to review this right away – please be patient 🙏

@Utkarsha2811
Copy link
Copy Markdown
Contributor Author

Thanks for the changes, I won't be able to review this right away – please be patient 🙏

Hey @mstimberg, I’ve rebased the PR on top of master. Could you take a look when you get a chance? Tried to address issues mentioned previously.

@mstimberg
Copy link
Copy Markdown
Member

Hi @Utkarsha2811 Sorry for the very late reply, I was down with a cold recently and am very much behind with PR reviews… I'll hopefully find some time to review/test in detail tomorrow, but one thing I already saw: could you please include an image demonstrating this new feature in the documentation?

Copy link
Copy Markdown
Member

@mstimberg mstimberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @Utkarsha2811, this looks all very good to me now. I made a few nitpicking comments below, but those are not essential. The only important missing thing is a picture in the documentation IMO.

Comment thread brian2tools/plotting/base.py Outdated
Comment on lines +77 to +80
raise TypeError(
"If multiple variables are recorded, 'axes' must be an "
"array-like of Axes with length %d (got %d)."
% (n_vars, len(axes_arr)))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very minor detail, but I'd prefer an f-string over the old-school formatting used here.

Comment thread brian2tools/plotting/base.py Outdated
% (n_vars, len(axes_arr)))

ret_axes = []
for i, var_name in enumerate(record_variables):
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again a nitpicking detail, but I'd prefer the more Pythonic

for ax, var_name in zip(axes_arr, record_variables):

plt.close()

# StateMonitorView of a multi-variable monitor
axes = brian_plot(state_mon[3])
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually realized that an earlier comment of mine was incorrect – I thought e.g. state_mon.v would return a StateMonitorView (in the same way that for a NeuronGroup group, the access group.v would return a VariableView), but you are right that in StateMonitor, a "view" is used when you index into the group. I wonder whether it would make sense to change something on the Brian side so that you could call e.g. brian_plot(state_mon.v) (which currently does not work, since state_mon.v is a simple Quantity without information about the variable name). But this is outside the scope of this PR, of course.

@Utkarsha2811 Utkarsha2811 requested a review from mstimberg April 28, 2026 19:24
@Utkarsha2811
Copy link
Copy Markdown
Contributor Author

Changes made as requested, @mstimberg. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow plotting multiple variables of StateMonitor

2 participants