Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting the same subplot size using matplotlib imshow and scatter

I am trying to plot an image (using matplotlib.imshow) and a scatter plot within the same figure. When trying this, the image appears smaller than the scatter plot. Small example code is shown below:

import matplotlib.pyplot as plt import numpy as np  image = np.random.randint(100,200,(200,200)) x = np.arange(0,10,0.1) y = np.sin(x)  fig, (ax1, ax2) = plt.subplots(1,2) ax1.imshow(image) ax2.scatter(x,y)  plt.show() 

Which gives the following figure:

enter image description here

How can I get the two sublpots to have the same height? (and width I suppose)

I have tried using gridspec as shown in this answer:

fig=plt.figure() gs=GridSpec(1,2)  ax1=fig.add_subplot(gs[0,0]) ax2=fig.add_subplot(gs[0,1]) ax1.imshow(image) ax2.scatter(x,y) 

But this gives the same result. I have also tried to adjust the subplot sizes manually by using:

fig = plt.figure() ax1 = plt.axes([0.05,0.05,0.45,0.9]) ax2 = plt.axes([0.55,0.19,0.45,0.62])  ax1.imshow(image) ax2.scatter(x,y) 

By trial and error I can get the two subplots to the correct size, though any change in the overall figure size will mean that the subplots will no longer be the same size.

Is there a way to make imshow and a scatter plot appear the same size in a figure without manually changing the axes sizes?

I am using Python 2.7 and matplotlib 2.0.0

like image 445
DavidG Avatar asked Jun 20 '17 13:06

DavidG


People also ask

How do you normalize Imshow?

Just specify vmin=0, vmax=1 . By default, imshow normalizes the data to its min and max. You can control this with either the vmin and vmax arguments or with the norm argument (if you want a non-linear scaling).

How do I fit a subplot in Matplotlib?

Use with GridSpectight_layout method (the pyplot api pyplot. tight_layout also works). You may provide an optional rect parameter, which specifies the bounding box that the subplots will be fit inside. The coordinates must be in normalized figure coordinates and the default is (0, 0, 1, 1).

How do I change the subplot size in Matplotlib?

To change figure size of more subplots you can use plt. subplots(2,2,figsize=(10,10)) when creating subplots.

How do I display multiple images in one figure correctly in Matplotlib?

The easiest way to display multiple images in one figure is use figure(), add_subplot(), and imshow() methods of Matplotlib. The approach which is used to follow is first initiating fig object by calling fig=plt. figure() and then add an axes object to the fig by calling add_subplot() method.


2 Answers

It's not perfectly clear what your desired outcome is.

  1. You may use automatic aspect on the image

    ax.imshow(z, aspect="auto") 

    enter image description here

  2. Or you may set the aspect of the line plot depending on its axis limits such that it gets the same size as the image (in case the image has equal x and y sizes)

    asp = np.diff(ax2.get_xlim())[0] / np.diff(ax2.get_ylim())[0] ax2.set_aspect(asp) 

    enter image description here Complete code:

    import numpy as np import matplotlib.pyplot as plt  x = np.linspace(0,10,20) y = np.sin(x) z = np.random.rand(100,100)  fig, (ax, ax2) = plt.subplots(ncols=2)  ax.imshow(z) ax2.plot(x,y, marker=".")  asp = np.diff(ax2.get_xlim())[0] / np.diff(ax2.get_ylim())[0] ax2.set_aspect(asp)  plt.show() 

    If the image does not have equal limits (is not square), one still needs to divide by the aspect of the image:

    asp = np.diff(ax2.get_xlim())[0] / np.diff(ax2.get_ylim())[0] asp /= np.abs(np.diff(ax1.get_xlim())[0] / np.diff(ax1.get_ylim())[0]) ax2.set_aspect(asp) 
  3. More sophisticated solutions:

    • This answer for using the subplot parameters to achieve a certain aspect.

    • If you want to use mpl_toolkits and make your hands dirty, this answer would be a good read.

like image 144
ImportanceOfBeingErnest Avatar answered Oct 23 '22 03:10

ImportanceOfBeingErnest


I had the same problem and asked a very similar question in SO. The solution proposed by @ImportanceOfBeingErnest worked like a charm for me, but for completeness, I'd like to mention a pretty simple workaround I was suggested to apply (credit to @Yilun Zhang) before my question was marked as an exact duplicate of this one:

The problem is that the plot region height is too large and this is leaving empty place in the image.

If you change your code to:

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6)) 

then you get the desired outcome:

Desired outcome

like image 42
Tonechas Avatar answered Oct 23 '22 03:10

Tonechas