1

My goal is to create three subplots in same window. Those subplots should be aligned in one column, each one under another. The first subplot should not use the slider widget, other two should, so if I will move slider then two bottom subplots should scroll. I've ended up with following two codes. I've modified a bit the code from answer to my another question. The tricky part is plotting part, which was mainly created as trial and error:

#!/usr/bin/python import numpy as np import matplotlib.pyplot as plt from matplotlib.widgets import Slider fig, ax = plt.subplots(nrows=2, ncols=1, sharex=True, sharey=False) # 1. On which (sub)plots this option is apply to # (already existed or also for subplots created in future)? plt.subplots_adjust(bottom=0.25) x_time = np.arange(0.0, 100.0, 0.1) sin_s = np.sin(x_time) cos_s = np.cos(x_time) oscil = np.cos(2 * np.pi * x_time) * np.exp(-x_time) sin_l, = plt.plot(x_time, sin_s, "bo-", label="sin") cos_l, = plt.plot(x_time, cos_s, "r.-", label="cos") # 2. On which plots this option is apply to # (already existed or also for subplots created in future)? plt.axis([0, 10, -1, 1]) #################################### # HERE COMES THE TRICKY PART WITH # # TWO ALTERNATIVES - THE RESULT OF # # TRIAL AND ERROR. PLEASE SEE CODE # # SNIPPETS BELLOW # #################################### axcolor = 'lightgoldenrodyellow' axpos = plt.axes([0.2, 0.1, 0.65, 0.03], axisbg=axcolor) spos = Slider(axpos, 'Pos', 0.1, 90.0) def update(val): pos = spos.val # 3. No matter which index is chosen (0 or 1), # it behaves exactly the same in both alternatives. # How is this possible? ax[0].axis([pos,pos+10,-1,1]) # ax[1].axis([pos,pos+10,-1,1]) fig.canvas.draw_idle() spos.on_changed(update) plt.show() 

Here are two different parts of code that I use for plotting, this is the trial and error part of code that I do not understand:

# 1st alternative - this plot is scrollable: ax[0].plot(x_time, oscil, "k-", label="oscilation") ax[0].legend() # 2nd alternative - this plot is not scrollable: plt.subplot(211) plt.plot(x_time, oscil, "k-", label="oscilation") plt.title('A tale of 2 subplots') plt.ylabel('Damped oscillation') 

I've tried to combine those examples into my final solution (having three plots from which the two are scrollable). So I've changed nrows=2 to nrows=3 in following line:

fig, ax = plt.subplots(nrows=2, ncols=1, sharex=True, sharey=False)

But if I use 1st alternative then all three subplots are scrollable, instead of two. And if I use 2nd alternative then I get just two subplots instead of three, where one is scrollable and another is not.

Can you please answer following questions:

  1. comment regarding: plt.subplots_adjust(bottom=0.25)
  2. comment regarding: plt.axis([0, 10, -1, 1])
  3. comment regarding: ax[0].axis([pos,pos+10,-1,1]) vs ax[1].axis([pos,pos+10,-1,1])
  4. The most important: how to make it work for three subplots?
  5. And finally the difference between 1st and 2nd alternative?

Edit, working version:

#!/usr/bin/python import numpy as np import matplotlib.pyplot as plt from matplotlib.widgets import Slider plt.close('all') fig, ax = plt.subplots(nrows=3, ncols=1) plt.subplots_adjust(bottom=0.25) ######################################## x_time = np.arange(0.0, 100.0, 0.1) oscil = np.cos(2 * np.pi * x_time) * np.exp(-x_time) sin_s = 2*np.sin(x_time) cos_s = np.cos(x_time) ######################################## ax[0].plot(x_time, oscil, "k-", label="oscilation") ax[1].plot(x_time, sin_s, "bo-", label="sin") ax[2].plot(x_time, cos_s, "r.-", label="cos") ######################################## ax[0].set_xlim([0, 10]) ax[1].set_ylim([-2, 2]) ax[2].set_ylim([-1, 1]) ######################################## axcolor = 'lightgoldenrodyellow' axpos = plt.axes([0.2, 0.1, 0.65, 0.03], axisbg=axcolor) spos = Slider(axpos, 'Pos', 0.1, 90.0) def update(val): pos = spos.val ax[1].axis([pos,pos+10,-2,2]) ax[2].axis([pos,pos+10,-1,1]) fig.canvas.draw_idle() spos.on_changed(update) plt.show() 

1 Answer 1

1

Your questions can all be answered from the matplotlib.figure API documentation or the matplotlib.pyplot API documentation.

1. On which (sub)plots this option is apply to (already existed or also for subplots created in future)?

plt.subplots_adjust(bottom=0.25)

All possible parameters are:

subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None, hspace=None)

These all update the subplot parameters, which are all documented here:

All dimensions are fraction of the figure width or height [...] bottom: The bottom of the subplots of the figure.

So, calling plt.subplots_adjust(bottom=0.25) makes the bottom margin of the whole plot (area containing both subplots) 25% of the figure height.

In this example, this is necessary to prevent the slider from colliding with the rest of the figure. Comment out that line to see what I mean.

2. On which plots this option is apply to (already existed or also for subplots created in future)?

plt.axis([0, 10, -1, 1])

This sets the plot's axis limits, in the form [xmin, xmax, ymin, ymax]. See this portion of the documentation.

It's a little weird that you're setting the axis of the plt object - but, doing so sets the axis once-only on the last subplot.

3. No matter which index is chosen (0 or 1), it behaves exactly the same in both alternatives. How is this possible? ax[0].axis([pos,pos+10,-1,1])

ax[1].axis([pos,pos+10,-1,1])

You created the subplots with the kwargs sharex=True and sharey=False. Since the axes were originally created with a ymin of -1 and a ymax of 1, calling update doesn't change the axes in either case.

You are only updating the xmin and xmax in any case, since you initialized ymin=-1 and ymax=1 (see 2.). In that case, it doesn't matter which axis you update, since the sharex behavior will update this value for both axes.

But, try updating the y min and max - updating axis properties won't be the same in that case.

4. The most important: how to make it work for three subplots?

5. And finally the difference between 1st and 2nd alternative?

It's not completely clear to me what you want to do here, so I'll start with 5. first.

# 1st alternative - this plot is scrollable: ax[0].plot(x_time, oscil, "k-", label="oscilation") ax[0].legend() 

This plots the your oscillations into the first subplot that you created when you called plt.subplots, since you're calling plot on ax[0]. Calling ax[0].legend() draws the legend based on the label and stroke you provided.

# 2nd alternative - this plot is not scrollable: plt.subplot(211) plt.plot(x_time, oscil, "k-", label="oscilation") plt.title('A tale of 2 subplots') plt.ylabel('Damped oscillation') 

This creates a new subplot in the first position - see the subplot documentation. It won't share the axis with the plots you previously created.

I'll leave #4 to you, but let me know if you have any specific questions.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you, I've edited the code based your assumption, I'm still not sure if it follows best practices, can you please check? Regarding 1st question: does the command apply to subplots created so far or also on subplots created in future? Regarding 2nd: if I understand correct then it is applied only for last subplot? Regarding 5th: calling plt.subplot(211) is not switching me to ax[0] but ratter overwriting it? I've read somewhere that calling plt.subplot(211) either create (if does not exists) or switch (if exists) subplot. Thank you
1: From what I understand, it should also apply to future subplots - why not try it out and check? 2: That's what it seems to be doing. Frankly, it looks weird to me to call that on plt rather than one of the objects in the ax collection. 5: That's my understanding from this documentation (as well as some testing): "Creating a new subplot with a position which is entirely inside a pre-existing axes will trigger the larger axes to be deleted"

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.