Skip to content

Commit aaaff3d

Browse files
Merge pull request #382 from NeuroML/feat/make-generate-plot-clicky
Feat/make generate plot clicky
2 parents 407c9c9 + abe95ac commit aaaff3d

File tree

2 files changed

+44
-9
lines changed

2 files changed

+44
-9
lines changed

pyneuroml/plot/Plot.py

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ def generate_plot(
5252
title_above_plot: bool = False,
5353
verbose: bool = False,
5454
close_plot: bool = False,
55+
interactive_legend: bool = True,
5556
) -> typing.Optional[matplotlib.axes.Axes]:
5657
"""Utility function to generate plots using the Matplotlib library.
5758
@@ -72,6 +73,11 @@ def generate_plot(
7273
- https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.plot.html
7374
- https://matplotlib.org/stable/gallery/index.html
7475
76+
.. versionadded:: 1.2.15
77+
78+
- animate
79+
- interactive_legend
80+
7581
:param xvalues: X values
7682
:type xvalues: list of lists
7783
:param yvalues: Y values
@@ -156,6 +162,9 @@ def generate_plot(
156162
:param close_plot: call :code:`pyplot.close()` to close plot after
157163
plotting, this is always done if using animation
158164
:type close_plot: bool
165+
:param interactive_legend: enable clicking on legend to toggle plot lines
166+
when using the matplotlib UI
167+
:type interactive_legend: bool
159168
:returns: matplotlib.axes.Axes object if plot is not closed, else None
160169
:raises ValueError: if the dimensions of xvalues/yvalues and option
161170
arguments colors/labels/linestyles/linewidths/markers/markersizes do
@@ -242,6 +251,7 @@ def generate_plot(
242251
if not show_yticklabels:
243252
ax.set_yticklabels([])
244253

254+
legend_box = None
245255
artists = []
246256

247257
for i in range(len(xvalues)):
@@ -282,10 +292,10 @@ def generate_plot(
282292
box = ax.get_position()
283293
ax.set_position((box.x0, box.y0, box.width * 0.8, box.height))
284294
# Put a legend to the right of the current axis
285-
ax.legend(loc="center left", bbox_to_anchor=(1, 0.5))
295+
legend_box = ax.legend(loc="center left", bbox_to_anchor=(1, 0.5))
286296

287297
elif legend_position == "bottom center":
288-
plt.legend(
298+
legend_box = plt.legend(
289299
loc="upper center",
290300
# to ensure it does not cover the lower axis label
291301
bbox_to_anchor=(0.5, -0.05),
@@ -294,7 +304,7 @@ def generate_plot(
294304
ncol=cols_in_legend_box,
295305
)
296306
else:
297-
plt.legend(
307+
legend_box = plt.legend(
298308
loc=legend_position,
299309
fancybox=True,
300310
shadow=True,
@@ -381,6 +391,27 @@ def update(frame):
381391
logger.info("Saved image to %s of plot: %s" % (save_figure_to, title))
382392

383393
if show_plot_already:
394+
if interactive_legend is True and legend_box is not None:
395+
map_legend_to_ax = {}
396+
pickradius = 5
397+
for legend_line, ax_line in zip(legend_box.get_lines(), artists):
398+
legend_line.set_picker(pickradius)
399+
map_legend_to_ax[legend_line] = ax_line
400+
401+
def on_pick(event):
402+
legend_line = event.artist
403+
404+
if legend_line not in map_legend_to_ax:
405+
return
406+
407+
ax_line = map_legend_to_ax[legend_line]
408+
visible = not ax_line.get_visible()
409+
ax_line.set_visible(visible)
410+
legend_line.set_alpha(1.0 if visible else 0.2)
411+
fig.canvas.draw()
412+
413+
fig.canvas.mpl_connect("pick_event", on_pick)
414+
384415
plt.show()
385416

386417
if close_plot or animate:

pyneuroml/plot/PlotSpikes.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -386,12 +386,16 @@ def plot_spikes_from_data_files(
386386
:type spiketime_files: List[str]
387387
:param title: optional title for plot, empty string disables it
388388
:type title: str
389-
:param format_: Format of the spike time data in the files. Can be one of the following:
390-
- "id_t": Each line contains a cell ID (int) followed by a spike time (float).
391-
- "id_time_nest_dat": Each line contains a cell ID (int) followed by a spike time (float),
392-
with NEST-style comments allowed.
393-
- "t_id": Each line contains a spike time (float) followed by a cell ID (int).
394-
- "sonata": SONATA-style HDF5 file.
389+
:param format_: Format of the spike time data in the files.
390+
391+
Can be one of the following:
392+
393+
- :code:`id_t`: Each line contains a cell ID (int) followed by a spike time (float).
394+
- :code:`id_time_nest_dat`: Each line contains a cell ID (int) followed by a spike time (float),
395+
with NEST-style comments allowed.
396+
- :code:`t_id`: Each line contains a spike time (float) followed by a cell ID (int).
397+
- :code:`sonata`: SONATA-style HDF5 file.
398+
395399
:type format_: str
396400
:param show_plots_already: Whether to show the plots immediately after they are generated. Defaults to True.
397401
:type show_plots_already: bool

0 commit comments

Comments
 (0)