Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pyplot - copy an axes content and show it in a new figure

Tags:

matplotlib

let say I have this code:

num_rows = 10 num_cols = 1 fig, axs = plt.subplots(num_rows, num_cols, sharex=True) for i in xrange(num_rows):      ax = axs[i]      ax.plot(np.arange(10), np.arange(10)**i) plt.show() 

the result figure has too much info and now I want to pick 1 of the axes and draw it alone in a new figure

I tried doing something like this

def on_click(event):     axes = event.inaxes.get_axes()     fig2 = plt.figure(15)     fig2.axes.append(axes)     fig2.show()  fig.canvas.mpl_connect('button_press_event', on_click) 

but it didn't quite work. what would be the correct way to do it? searching through the docs and throw SE gave hardly any useful result

edit:

I don't mind redrawing the chosen axes, but I'm not sure how can I tell which of the axes was chosen so if that information is available somehow then it is a valid solution for me

edit #2:

so I've managed to do something like this:

def on_click(event):     fig2 = plt.figure(15)     fig2.clf()     for line in event.inaxes.axes.get_lines():          xydata = line.get_xydata()          plt.plot(xydata[:, 0], xydata[:, 1])     fig2.show() 

which seems to be "working" (all the other information is lost - labels, lines colors, lines style, lines width, xlim, ylim, etc...) but I feel like there must be a nicer way to do it

thanks

like image 454
user2717954 Avatar asked Aug 22 '17 06:08

user2717954


People also ask

Can an axes belong to multiple figures Python?

An axes object can only belong to one figure.

What is Pyplot CLF ()?

The clf() function in pyplot module of matplotlib library is used to clear the current figure.

How do you show Axessubplot?

To show an axes subplot in Python, we can use show() method. When multiple figures are created, then those images are displayed using show() method.

What does PLT Tight_layout () do?

The tight_layout() function in pyplot module of matplotlib library is used to automatically adjust subplot parameters to give specified padding.


1 Answers

Copying the axes

The inital answer here does not work, we keep it for future reference and also to see why a more sophisticated approach is needed.

#There are some pitfalls on the way with the initial approach.   #Adding an `axes` to a figure can be done via `fig.add_axes(axes)`. However, at this point,   #the axes' figure needs to be the figure the axes should be added to.   #This may sound a bit like running in circles but we can actually set the axes'   #figure as `axes.figure = fig2` and hence break out of this.    #One might then also position the axes in the new figure to take the usual dimensions.   #For this a dummy axes can be added first, the axes can change its position to the position   #of the dummy axes and then the dummy axes is removed again. In total, this would look as follows.    import matplotlib.pyplot as plt  import numpy as np    num_rows = 10  num_cols = 1  fig, axs = plt.subplots(num_rows, num_cols, sharex=True)  for i in xrange(num_rows):       ax = axs[i]       ax.plot(np.arange(10), np.arange(10)**i)                def on_click(event):      axes = event.inaxes      if not axes: return         fig2 = plt.figure()      axes.figure=fig2      fig2.axes.append(axes)      fig2.add_axes(axes)            dummy = fig2.add_subplot(111)      axes.set_position(dummy.get_position())      dummy.remove()      fig2.show()    fig.canvas.mpl_connect('button_press_event', on_click)      plt.show()    #So far so good, however, be aware that now after a click the axes is somehow   #residing in both figures, which can cause all sorts of problems, e.g. if you  # want to resize or save the initial figure.

Instead, the following will work:

Pickling the figure

The problem is that axes cannot be copied (even deepcopy will fail). Hence to obtain a true copy of an axes, you may need to use pickle. The following will work. It pickles the complete figure and removes all but the one axes to show.

import matplotlib.pyplot as plt import numpy as np import pickle import io  num_rows = 10 num_cols = 1 fig, axs = plt.subplots(num_rows, num_cols, sharex=True) for i in range(num_rows):      ax = axs[i]      ax.plot(np.arange(10), np.arange(10)**i)  def on_click(event):      if not event.inaxes: return     inx = list(fig.axes).index(event.inaxes)     buf = io.BytesIO()     pickle.dump(fig, buf)     buf.seek(0)     fig2 = pickle.load(buf)       for i, ax in enumerate(fig2.axes):         if i != inx:             fig2.delaxes(ax)         else:             axes=ax      axes.change_geometry(1,1,1)     fig2.show()  fig.canvas.mpl_connect('button_press_event', on_click)  plt.show() 

Recreate plots

The alternative to the above is of course to recreate the plot in a new figure each time the axes is clicked. To this end one may use a function that creates a plot on a specified axes and with a specified index as input. Using this function during figure creation as well as later for replicating the plot in another figure ensures to have the same plot in all cases.

import matplotlib.pyplot as plt import numpy as np  num_rows = 10 num_cols = 1 colors = plt.rcParams["axes.prop_cycle"].by_key()["color"] labels = ["Label {}".format(i+1) for i in range(num_rows)]  def myplot(i, ax):     ax.plot(np.arange(10), np.arange(10)**i, color=colors[i])     ax.set_ylabel(labels[i])   fig, axs = plt.subplots(num_rows, num_cols, sharex=True) for i in xrange(num_rows):      myplot(i, axs[i])   def on_click(event):     axes = event.inaxes     if not axes: return     inx = list(fig.axes).index(axes)     fig2 = plt.figure()     ax = fig2.add_subplot(111)     myplot(inx, ax)     fig2.show()  fig.canvas.mpl_connect('button_press_event', on_click)  plt.show() 
like image 139
ImportanceOfBeingErnest Avatar answered Sep 23 '22 13:09

ImportanceOfBeingErnest