1

There are several related questions (here, here, and here), but the suggested solutions don't work in my case.

I'm creating subplots iteratively, so I don't know ahead of time the width of each one (it gets calculated AFTER plt.subplots() is called), which means I can't set the size of each subplot when I initially create them. I would like to set the size of the subplot x axis after it has already been created.

Imagine something like:

items = [A,B,C]  #this could have any number of items in it
f,ax = plt.subplots(len(items),1, figsize=(10,10)) #figsize is arbitrary and could be anything

for i in range(len(items)):
    #calculate x and y data for current item
    #calculate width of x axis for current item
    plt.sca(ax[i])
    cax = plt.gca()
    cax.plot(x,y)
    #here is where I would like to set the x axis size
    #something like cax.set_xlim(), but for the size, not the limit

Note 1: The units don't matter, but the relative size does, so it could be size in pixels, or centimeters, or even a ratio calculated based on the relative widths.

Note 2: The width of the x axis is NOT related in this case to the x limit, so I can't just set the x limit and expect the axis to scale correctly.

Also, I'm trying to keep this code short, since it's to be shared with people unfamiliar with Python, so if the only solution involves adding a bunch of lines, it's not worth it and I'll live with incorrectly scaled axes. This is an aesthetic preference but not a requirement. Thanks!

EDIT: Here's what I'm aiming for desired subplots

Takver
  • 172
  • 1
  • 3
  • 13
  • Are you talking about the relative or absolute size of the subplots? – ImportanceOfBeingErnest Nov 28 '18 at 15:34
  • Doesn't matter - what I want is for them to be scaled appropriately relative to each other (they're geologic cross-sections, so the x axis size is based on the distance between point A and point B of the cross-section on a map), but if the easiest way to do that is to fix an absolute size for each one, that works too. – Takver Nov 29 '18 at 08:57
  • 1
    Relavtive size is easy as shown in the answer by @Felix. – ImportanceOfBeingErnest Nov 29 '18 at 13:16
  • Did you see my response? That approach seems to require knowing what relative size each subplot should be ahead of time. My problem is that I don't know what the size should be until AFTER I'm already in the loop. Am I misunderstanding something in the answer? – Takver Nov 29 '18 at 13:38
  • 2
    The answer sets the `height_ratios` *after* the plotting. So by then you will know what they need to be. – ImportanceOfBeingErnest Nov 29 '18 at 13:41

2 Answers2

1

You can create a new GridSpec specifying the height_ratios and then updating each axs position:

import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec

# create figure
f, ax = plt.subplots(3, 1, figsize=(10,10))

# plot some data
ax[0].plot([1, 2, 3])
ax[1].plot([1, 0, 1])
ax[2].plot([1, 2, 20])

# adjust subplot sizes
gs = GridSpec(3, 1, height_ratios=[5, 2, 1])
for i in range(3):
    ax[i].set_position(gs[i].get_position(f))

plt.show()

I asked a similar question before here. The use case was slightly different, but it might still be helpful.

Felix
  • 6,131
  • 4
  • 24
  • 44
  • The problem with this approach (if I understand correctly) is that you set the gridspec ratios BEFORE the loop, whereas I don't know the ratios until I'm inside the loop, so I need to be able to modify the axes after they're created. – Takver Nov 29 '18 at 09:01
  • 1
    That's exactly what you can do using the code above. Your loop would go below the "plot some data" block. Once its finished and you know the ratios, create the `Gridspec` and update the positions/sizes of the existing axes (see the "adjust subplot sizes" block). – Felix Nov 29 '18 at 13:46
  • Ah got it sorry - I thought gridspec needed to be set before plotting. So there are two loops, one to plot each subplot, and one to update them afterwards. That works great! Thanks! – Takver Nov 29 '18 at 14:01
  • Yeah it took me a while to get that, too. You're welcome ;-) – Felix Nov 29 '18 at 14:02
  • Ah actually - a problem. GridSpec works great to change the height ratios if you have one column, but it doesn't work to change the width ratios if the subplots are all in the same column - I think it can only change the width ratios if each subplot is in its own column. :( – Takver Nov 29 '18 at 14:37
  • All subplots within a column have the same width (which is the width of the column). I'm not sure I understand your problem?! – Felix Nov 29 '18 at 14:55
  • Right, so I'm trying to get a stack of subplots, all in the same column, but with different x axis sizes, because they represent spatial cross-sections that are not all the same length. I could do it by making a new figure for each cross-section, but then exporting them all is a pain. Changing the height ratios would have been perfect if I wanted the y axis to be different for each, or if I wanted one row of subplots (still super useful to know though, so thank you!). Having the subplots in a row instead of a column is too wide to be visually practical. Does that help explain at all? – Takver Nov 30 '18 at 15:41
1

Surely now you got the answer or this problem is deprecated but if someone else is searching, I solved this problem using "Bbox". The idea is something like this:

from matplotlib.transforms import Bbox

fig, ax = plt.subplots(3,1, figsize = (11,15))
ax[0].set_position(Bbox([[0.125, 0.6579411764705883], [0.745, 0.88]]))
ax[2].set_position(Bbox([[0.125, 0.125], [0.745, 0.34705882352941175]]))

For more information, check https://matplotlib.org/api/transformations.html#matplotlib.transforms.Bbox