Hiding lines after showing a gun figure

I use pyplot to display a line graph up to 30 lines long. I would like to add a way to quickly show and hide individual lines in the chart. Pyplot has a menu where you can edit the properties of the line to change the color or style, but its pretty awkward when you want to hide the lines to isolate the one you are interested in. Ideally, I would like to use the checkboxes in the legend to show and hide lines. (Similar to showing and hiding layers in image editors such as Paint.Net). I'm not sure if this is possible with pyplot, so I am open to other modules if they are somewhat easy to distribute.

+12
python matplotlib
source share
2 answers

If you want, you can connect a callback to a legend that will show / hide lines when pressed. Here is a simple example: http://matplotlib.org/examples/event_handling/legend_picking.html

Here is a more sophisticated example that should work without the need to manually specify the relationship of the lines and markers of the legend (also has several additional functions).

(The updated version in August 2019 in response to repeated reports of this does not work as expected; now it should be! For the old version, see version history )

import numpy as np import matplotlib.pyplot as plt def main(): x = np.arange(10) fig, ax = plt.subplots() for i in range(1, 31): ax.plot(x, i * x, label=r'$y={}x$'.format(i)) ax.legend(loc='upper left', bbox_to_anchor=(1.05, 1), ncol=2, borderaxespad=0) fig.subplots_adjust(right=0.55) fig.suptitle('Right-click to hide all\nMiddle-click to show all', va='top', size='large') leg = interactive_legend() return fig, ax, leg def interactive_legend(ax=None): if ax is None: ax = plt.gca() if ax.legend_ is None: ax.legend() return InteractiveLegend(ax.get_legend()) class InteractiveLegend(object): def __init__(self, legend): self.legend = legend self.fig = legend.axes.figure self.lookup_artist, self.lookup_handle = self._build_lookups(legend) self._setup_connections() self.update() def _setup_connections(self): for artist in self.legend.texts + self.legend.legendHandles: artist.set_picker(10) # 10 points tolerance self.fig.canvas.mpl_connect('pick_event', self.on_pick) self.fig.canvas.mpl_connect('button_press_event', self.on_click) def _build_lookups(self, legend): labels = [t.get_text() for t in legend.texts] handles = legend.legendHandles label2handle = dict(zip(labels, handles)) handle2text = dict(zip(handles, legend.texts)) lookup_artist = {} lookup_handle = {} for artist in legend.axes.get_children(): if artist.get_label() in labels: handle = label2handle[artist.get_label()] lookup_handle[artist] = handle lookup_artist[handle] = artist lookup_artist[handle2text[handle]] = artist lookup_handle.update(zip(handles, handles)) lookup_handle.update(zip(legend.texts, handles)) return lookup_artist, lookup_handle def on_pick(self, event): handle = event.artist if handle in self.lookup_artist: artist = self.lookup_artist[handle] artist.set_visible(not artist.get_visible()) self.update() def on_click(self, event): if event.button == 3: visible = False elif event.button == 2: visible = True else: return for artist in self.lookup_artist.values(): artist.set_visible(visible) self.update() def update(self): for artist in self.lookup_artist.values(): handle = self.lookup_handle[artist] if artist.get_visible(): handle.set_visible(True) else: handle.set_visible(False) self.fig.canvas.draw() def show(self): plt.show() if __name__ == '__main__': fig, ax, leg = main() plt.show() 

This allows you to click on the legend elements to turn on / off their respective artists. For example, you can go from this:

enter image description here

On this:

enter image description here

+23
source share

Thanks for the post! I expanded the class above so that it can handle several legends - for example, if you use auxiliary plots. (I am sharing this here, since I could not find another example anywhere else ... and it might be convenient for someone else ...)

  class InteractiveLegend(object): def __init__(self): self.legends = [] self.figures = [] self.lookup_artists = [] self.lookup_handles = [] self.host = socket.gethostname() def add_legends(self, legend): self.legends.append(legend) def init_legends(self): for legend in self.legends: self.figures.append(legend.axes.figure) lookup_artist, lookup_handle = self._build_lookups(legend) #print("init", type(lookup)) self.lookup_artists.append(lookup_artist) self.lookup_handles.append(lookup_handle) self._setup_connections() self.update() def _setup_connections(self): for legend in self.legends: for artist in legend.texts + legend.legendHandles: artist.set_picker(10) # 10 points tolerance for figs in self.figures: figs.canvas.mpl_connect('pick_event', self.on_pick) figs.canvas.mpl_connect('button_press_event', self.on_click) def _build_lookups(self, legend): labels = [t.get_text() for t in legend.texts] handles = legend.legendHandles label2handle = dict(zip(labels, handles)) handle2text = dict(zip(handles, legend.texts)) lookup_artist = {} lookup_handle = {} for artist in legend.axes.get_children(): if artist.get_label() in labels: handle = label2handle[artist.get_label()] lookup_handle[artist] = handle lookup_artist[handle] = artist lookup_artist[handle2text[handle]] = artist lookup_handle.update(zip(handles, handles)) lookup_handle.update(zip(legend.texts, handles)) #print("build", type(lookup_handle)) return lookup_artist, lookup_handle def on_pick(self, event): #print event.artist handle = event.artist for lookup_artist in self.lookup_artists: if handle in lookup_artist: artist = lookup_artist[handle] artist.set_visible(not artist.get_visible()) self.update() def on_click(self, event): if event.button == 3: visible = False elif event.button == 2: visible = True else: return for lookup_artist in self.lookup_artists: for artist in lookup_artist.values(): artist.set_visible(visible) self.update() def update(self): for idx, lookup_artist in enumerate(self.lookup_artists): for artist in lookup_artist.values(): handle = self.lookup_handles[idx][artist] if artist.get_visible(): handle.set_visible(True) else: handle.set_visible(False) self.figures[idx].canvas.draw() def show(self): plt.show() 

use it as follows:

 leg1 = ax1.legend(loc='upper left', bbox_to_anchor=(1.05, 1), ncol=2, borderaxespad=0) leg2 = ax2.legend(loc='upper left', bbox_to_anchor=(1.05, 1), ncol=2, borderaxespad=0) fig.subplots_adjust(right=0.7) interactive_legend = InteractiveLegend() interactive_legend.add_legends(leg1) interactive_legend.add_legends(leg2) interactive_legend.init_legends() interactive_legend.show() 
+1
source share

All Articles