4

I have a figure containing three subplots. The first subplot is an image (imshow), while the other two are distributions (plot).

Here's the code:

# collects data
imgdata = ...      # img of shape  (800, 1600, 3)    
x = ...            # one 1600-dimensional vector
y = ...            # one  800-dimensional vector

# create the figure 
f = plt.figure()    

# create subplots   
subplot_dim = (1, 3)
p_img = plt.subplot2grid(subplot_dim, (0, 0), aspect="auto")
p_x = plt.subplot2grid(subplot_dim, (0, 1), aspect="auto")
p_y = plt.subplot2grid(subplot_dim, (0, 2), aspect="auto")

p_img.imshow(imgdata, interpolation="None")
p_x.plot(x)         
p_y.plot(y)         


# save figure       
f.set_size_inches(21.0, 12.0)
f.savefig("some/path/image.pdf", dpi=80)

My problem is, that the two subplots p_x, p_y always have a greater height than the image subplot p_img.

Thus, the result always looks like this:

                  ###############   ###############   
                  #             #   #  *****      #
                  #        *****#   # *     *     #
###############   #     ***     #   # *      *    #
#             #   #    *        #   # *        *  #
#    image    #   #   *         #   #*           *#
#             #   #***          #   #*           *#
###############   ###############   ###############
     p_img              p_x               p_y

How can I enforce an equal size (or at least height) of p_img, p_x and p_y?

EDIT: Here is a simple example code that generates random data and uses plt.show() instead of saving a figure. However, one can easily see the same behaviour there: the image is much smaller (height) than the other subplots:

from matplotlib import pyplot as plt 
from matplotlib import image as mpimg
import numpy as np

imgdata = np.random.rand(200, 400, 3)  
x = np.random.normal(loc=100.0, scale=20.0, size=400)
y = np.random.normal(loc=150.0, scale=15.0, size=200) 

# create the figure
f = plt.figure()

# create subplots
subplot_dim = (1, 3)
p_img = plt.subplot2grid(subplot_dim, (0, 0), aspect="auto")
p_x = plt.subplot2grid(subplot_dim, (0, 1), aspect="auto")
p_y = plt.subplot2grid(subplot_dim, (0, 2), aspect="auto")

p_img.imshow(imgdata, interpolation="None")
p_x.plot(x)
p_y.plot(y)


# save figure
plt.show()
daniel451
  • 10,626
  • 19
  • 67
  • 125
  • Try `plt.axis()` function to set axis dimensions – SvbZ3r0 Jun 11 '16 at 18:14
  • That did not change anything :( btw: isn't `axis()` taking a list of `[xmin, xmax, ymin, ymax]`? The `p_img`, `p_x` and `p_y` have a (pairwise) different y-axis. `800` for `p_img` (height of the image) and normally something in the interval [1, 10] for `y_max` of `p_x` and `p_y`. Therefore they never share the y-axis (scaling). – daniel451 Jun 11 '16 at 18:21
  • `gridspec`? Check [this](http://stackoverflow.com/questions/10388462/matplotlib-different-size-subplots) question to see if its of any help – SvbZ3r0 Jun 11 '16 at 18:43
  • I've tested my example code with `gridspec` (created axes with `gridspec` instead of `subplot2grid` and added `height_ratios` to gridspec). This seems to enforce a certain width/height. However, I do not understand the scaling and it looks like the values are somehow absolute? Doesn't matplotlib have some method to make the height of subplots fixed? This looks like a huge design flaw to me...do one really has to determine every subplots width/height and then rescale it manually to get equal size subplots? – daniel451 Jun 11 '16 at 18:55

1 Answers1

1

You can do it by specifying it directly in the subplots like this:

from matplotlib import pyplot as plt
from matplotlib import image as mpimg
import numpy as np

imgdata = np.random.rand(200, 400, 3)
x = np.random.normal(loc=100.0, scale=20.0, size=400)
y = np.random.normal(loc=150.0, scale=15.0, size=200)

# create the figure
f = plt.figure()

# create subplots
subplot_dim = (1, 3)
p_img = plt.subplot2grid(subplot_dim, (0, 0), aspect="auto")
p_x = plt.subplot2grid(subplot_dim, (0, 1), aspect="auto", adjustable='box-forced', sharex=p_img, sharey=p_img)
p_y = plt.subplot2grid(subplot_dim, (0, 2), aspect="auto", adjustable='box-forced', sharex=p_img, sharey=p_img)

p_img.imshow(imgdata, interpolation="None")
p_x.plot(x)
p_y.plot(y)

, which results in this:

Same height for all matplotlib subplots

The problem is your data does not have the same limits. So you'll have to make adjustments with set_xlim and set_ylim. I would also recommend testing other combinations for sharey, since they might provide better results.

armatita
  • 12,825
  • 8
  • 48
  • 49
  • Matplotlib 3.4 gives this error: `ValueError: 'box-forced' is not a valid value for adjustable; supported values are 'box', 'datalim'` – Greenonline May 12 '21 at 22:25