How to overlay one pyplot figure on another - matplotlib

Searching easily reveals how to plot multiple charts on one figure, whether using the same plotting axes, a second y axis or subplots. Much harder to uncover is how to overlay one figure onto another, something like this:
That image was prepared using a bitmap editor to overlay the images. I have no difficulty creating the individual plots, but cannot figure out how to combine them. I expect a single line of code will suffice, but what is it? Here is how I imagine it:
bigFig = plt.figure(1, figsize=[5,25])
...
ltlFig = plt.figure(2)
...
bigFig.overlay(ltlFig, pos=[x,y], size=[1,1])
I've established that I can use figure.add_axes, but it is quite challenging getting the position of the overlaid plot correct, since the parameters are fractions, not x,y values from the first plot. It also [it seems to me - am I wrong?] places constraints on the order in which the charts are plotted, since the main plot must be completed before the other plots are added in turn.
What is the pyplot method that achieves this?

To create an inset axes you may use mpl_toolkits.axes_grid1.inset_locator.inset_axes.
Position of inset axes in axes coordinates
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
fig, ax= plt.subplots()
inset_axes = inset_axes(ax,
width=1, # inch
height=1, # inch
bbox_transform=ax.transAxes, # relative axes coordinates
bbox_to_anchor=(0.5,0.5), # relative axes coordinates
loc=3) # loc=lower left corner
ax.axis([0,500,-.1,.1])
plt.show()
Position of inset axes in data coordinates
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
fig, ax= plt.subplots()
inset_axes = inset_axes(ax,
width=1, # inch
height=1, # inch
bbox_transform=ax.transData, # data coordinates
bbox_to_anchor=(250,0.0), # data coordinates
loc=3) # loc=lower left corner
ax.axis([0,500,-.1,.1])
plt.show()
Both of the above produce the same plot
(For a possible drawback of this solution see specific location for inset axes)

Related

plot_surface reduces density of points

Trying to plot a surface using matplotlib. However, the plotted surface has lower grid density than the meshgrid.
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
xgrid = np.arange(0,1,1/100)
ygrid = xgrid.copy()
xx, yy = np.meshgrid(xgrid,ygrid)
fig = plt.figure()
ax = fig.add_subplot(111,projection='3d')
ax.plot_surface(xx,yy,np.square(xx)+np.square(yy))
The meshgrid was defined to have 100 segments in each direction. However, the surface in the figure doesn't have 100 segments. Is there anyway to render the surface with the same density?
Don't worry, you don't have to count the number of segments, so I overlap the plot with a scatter plot with the same points
ax.scatter3D(xx,yy,np.square(xx)+np.square(yy))
Upon zooming in, you can see that each grid of the surface plot has a scatter point in the middle, which shows that the plot_surface changed the density of the points.
Usually it doesn't matter for smooth plots such as these, but I have singular points in my data which sometimes disappear in the surface plot because of this

how to change color of axis in 3d matplotlib figure?

The color of the axis (x, y, z) in a 3d plot using matplotlib is black by default. How do you change the color of the axis? Or better yet, how do you make them invisible?
%matplotlib inline
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.xaxis.set_visible(False) # doesn't do anything
And there doesn't seem to be a ax.xaxis.set_color function. Any thoughts on how to make the axis invisible or change the color?
You can combine your method with the approach provided here. I am showing an example that affects all three axes. In Jupyter Notebook, using tab completion after ax.w_xaxis.line., you can discover other possible options
ax.w_xaxis.line.set_visible(False)
ax.w_yaxis.line.set_color("red")
ax.w_zaxis.line.set_color("blue")
To change the tick colors, you can use
ax.xaxis._axinfo['tick']['color']='r'
ax.yaxis._axinfo['tick']['color']='g'
ax.zaxis._axinfo['tick']['color']='b'
To hide the ticks
for line in ax.xaxis.get_ticklines():
line.set_visible(False)

Matplotlib issue x and y label for multi axes figure

import matplotlib
import matplotlib.pyplot as plt
import numpy as nm
x = nm.linspace(start=0,stop=20,num=30)
fig=plt.figure()
ax1 = fig.add_axes([0,0.6,0.6,0.4])
ax2 = fig.add_axes([0,0,0.8,0.4])
ax1.plot(x,nm.sin(x))
ax1.set_xlabel('x',fontsize=15,color='r')
ax1.set_ylabel('sin(x)',fontsize=15,color='r')
ax2.plot(x,nm.cos(x))
ax2.set_xlabel('x',fontsize=15,color='r')
ax2.set_ylabel('cos(x)',fontsize=15,color='r')
plt.show()
The output I am not able to see the xlabel for ax2 and not able to see both y label for ax1 and ax2..The image is present below:
enter code hereenter image description here
This is expected as you are asking to create an axes that is aligned with the left edge of the figure by using fig.add_axes([0,...]). Same thing for the bottom axes, which you have aligned to the bottom-left of the figure using fig.add_axes([0,0,...]).
Increase the first value e.g. fig.add_axes([0.125,...]) to leave room for the axes decorations on the left or bottom of the axes.
It is generally recommended to use the subplots functions (such as add_subplot, plt.subplots or GridSpec) so that these details are handled automatically.

changing the size of subplots with matplotlib

I am trying to plot multiple rgb images with matplotlib
the code I am using is:
import numpy as np
import matplotlib.pyplot as plt
for i in range(0, images):
test = np.random.rand(1080, 720,3)
plt.subplot(images,2,i+1)
plt.imshow(test, interpolation='none')
the subplots appear tiny though as thumbnails
How can I make them bigger?
I have seen solutions using
fig, ax = plt.subplots()
syntax before but not with plt.subplot ?
plt.subplots initiates a subplot grid, while plt.subplot adds a subplot. So the difference is whether you want to initiate you plot right away or fill it over time. Since it seems, that you know how many images to plot beforehand, I would also recommend going with subplots.
Also notice, that the way you use plt.subplot you generate empy subplots in between the ones you are actually using, which is another reason they are so small.
import numpy as np
import matplotlib.pyplot as plt
images = 4
fig, axes = plt.subplots(images, 1, # Puts subplots in the axes variable
figsize=(4, 10), # Use figsize to set the size of the whole plot
dpi=200, # Further refine size with dpi setting
tight_layout=True) # Makes enough room between plots for labels
for i, ax in enumerate(axes):
y = np.random.randn(512, 512)
ax.imshow(y)
ax.set_title(str(i), fontweight='bold')

Copying axis limits from one subplot ('equal' aspect) to another

In a figure with 2x2 subplots, I need both the subplots on the right to share the x-axis, but the ones on the left not to share their axis. In addition, I need the subplot that is determining the x-axis limits to have 'equal' aspect ratio. I tried this:
import matplotlib.pyplot as plt
fig, ax = plt.subplots(2, 2, figsize=(12, 9))
# Subplot [0,1]
ax[0,1].axis('equal')
ax[0,1].plot(...)
[xmin01, xmax01, ymin01, ymax01] = self.ax[0,1].axis()
# Subplot [1,1]
ax[1,1].plot(...)
ax[1,1].set_xlim(left=xmin01, right=xmax01)
This is not working: the limits of the x-axis returned by axis() are near the data limits and are not the real limits shown in the graphed subplot. Changing the position of ax[0,1].axis('equal') after the plot command has no effect. Any idea?
Looking into the pyplot source code I discovered that axis('equal') is calling the method set_aspect(). This latter method is modifying the variable self._aspect but it is not further updating anything related! Then, I looked for and found the method that is really updating the aspect ratio: it is named apply_aspect(). So, it doesn't seem very elegant, but at least my problem is solved as shown:
import matplotlib.pyplot as plt
fig, ax = plt.subplots(2, 2, figsize=(12, 9))
# Subplot [0,1]
ax[0,1].axis('equal')
ax[0,1].plot(...)
ax[0,1].apply_aspect()
[xmin01, xmax01, ymin01, ymax01] = self.ax[0,1].axis()
# Subplot [1,1]
ax[1,1].plot(...)
ax[1,1].set_xlim(left=xmin01, right=xmax01)