I wonder how to set the size of the subplot when figure contains multiple subplots (5 × 2 in my case). No matter how big I allow the whole figure to be, the subplots always seem to be small. I would like to have direct control of the size of the subplot in this figure. The simplified version of the code is pasted below.
import numpy as np
import matplotlib.pyplot as plt
x = np.random.randn(20)
y = np.random.randn(20)
fig = plt.figure(figsize=(20, 8))
for i in range(0,10):
ax = fig.add_subplot(5, 2, i+1)
plt.plot(x, y, 'o')
ax.xaxis.set_visible(False)
ax.yaxis.set_visible(False)
# x and y axis should be equal length
x0,x1 = ax.get_xlim()
y0,y1 = ax.get_ylim()
ax.set_aspect(abs(x1-x0)/abs(y1-y0))
plt.show()
fig.savefig('plot.pdf', bbox_inches='tight')
Just switch figure size width and height from:
fig = plt.figure(figsize=(20, 8))
to:
fig = plt.figure(figsize=(8, 20))
to use the whole page for your plots.
This will change your plot from:
to:
Related
I have 2 sets of rectangular patches in a plot. I want to name them separately. "Layer-1" for the bottom part and similarly "Layer-2" for the upper part. I wanted to set coordinates for the Y-axis but it did not work. Moreover i was not able to add the "Layer-2" text into the label. Please help.
I tried with the below mentioned code but it did not work.
plt.ylabel("LAYER-1", loc='bottom')
yaxis.labellocation(bottom)
One solution is to create a second axis, so called twin axis that shares the same x axis. Then it is possbile to label them separately. Furthermore, you can adjust the location of the label via
axis.yaxis.set_label_coords(-0.1, 0.75)
Here is an example that you can adjust to your desires. The result can be found here: https://i.stack.imgur.com/1o2xl.png
%matplotlib notebook
%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import numpy as np
plt.rcParams['figure.dpi'] = 100
import matplotlib.pyplot as plt
x = np.arange(0, 10, 0.1)
y1 = 0.05 * x**2
y2 = -1 *y1
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
ax1.plot(x, y1, 'g-')
ax2.plot(x, y2, 'b-')
# common x axis
ax1.set_xlabel('X data')
# First y axis label
ax1.set_ylabel('LAYER-1', color='g')
# Second y [enter image description here][1]axis label
ax2.set_ylabel('LAYER-2', color='b')
# Adjust the label location
ax1.yaxis.set_label_coords(-0.075, 0.25)
ax2.yaxis.set_label_coords(-0.1, 0.75)
plt.show()
I'm not sure my wording is correct, but what I am trying to do is create a figure of two subplots, where the two plots have different limits, but their size is such that the physical scale (as in, y-distance per centimeter of figure height) is the same. To clarify, lets say subplot 1 shows data from -3 to 3 and subplot 2 shows data from -1 to 1. I want to have them below one another in such a way that the height of subplot2 (excluding ticks, just everything inside the frame) is exactly one third of subplot 1.
My attempt was as follows:
from matplotlib import gridspec
from matplotlib import pyplot as plt
import numpy as np
x = np.linspace(0,2, 101)
y1 = 3*np.cos(x*np.pi)
y2 = np.cos(x*np.pi)
fig = plt.figure(figsize=(4, 6))
gs = gridspec.GridSpec(8, 1)
ax1 = plt.subplot(gs[0:6,0])
ax1.plot(x, y1, c='orange')
ax1.set_ylim(-3, 3)
ax1.set_xticks([], [])
ax2 = plt.subplot(gs[6:,0])
ax2.plot(x, y2, c='green')
ax2.set_ylim(-1,1)
ax2.set_xticks([0, 1, 2])
ax2.set_xticklabels([r'0', r'0.5', r'1'])
ax2.set_xlabel(r'$n_g$ (2e)')
plt.tight_layout()
fig.text(-0.025, 0.5, 'Frequency (GHz)', ha='center', va='center', rotation='vertical', size=18)
which produces the figure below, but as you can see (although you have to look closely) the range -1 to 1 in the second subplot is compressed (takes up less height) than the range -1 to 1 in subplot 1. I'm guessing this is because of the space between the two subplots.
Note that I'm using gridspec because I plan on adding another column of subplots with interesting aspect ratio's and its own labels and limits. I didn't know how to add a global ylabel in a more elegant way, if someone was wondering.
You can set the height_ratios of the gridspec to match the range of the limits.
from matplotlib import gridspec
from matplotlib import pyplot as plt
import numpy as np
x = np.linspace(0,2, 101)
y1 = 3*np.cos(x*np.pi)
y2 = np.cos(x*np.pi)
ylim1 = -3,3
ylim2 = -1,1
fig = plt.figure(figsize=(4, 6), constrained_layout=True)
gs = gridspec.GridSpec(2, 1, height_ratios=[np.diff(ylim1)[0],
np.diff(ylim2)[0]], figure=fig)
ax1 = plt.subplot(gs[0,0])
ax1.plot(x, y1, c='orange')
ax1.set_ylim(ylim1)
ax1.set_xticks([], [])
ax2 = plt.subplot(gs[1,0])
ax2.plot(x, y2, c='green')
ax2.set_ylim(ylim2)
ax2.set_xticks([0, 1, 2])
ax2.set_xticklabels([r'0', r'0.5', r'1'])
ax2.set_xlabel(r'$n_g$ (2e)')
plt.show()
I am trying to achieve generate plot made of subplots: plt.plot() and plt.matshow(), in which two plots had exactly the same size. What I mean is that lower border of one plot and lower borders of second plots were located on same "height". Similarly with the top border line. Current effect is presented on the plot below.
I haven't found any way in the available resources which would help me to achieve this effect. I would be grateful if you could help me.
shape=(2500, 2500)
matrix=np.zeros(shape)
print "Start of computing"
for x in range(shape[0]) :
for y in range(shape[1]) :
matrix[x, y]=shapeFuction((x-shape[0]/2)/13.0, (y-shape[1]/2)/13.0, 2.0e-4, 9e-5, 1.0)
print "Start of plotting"
fig=plt.figure()
ax = fig.add_subplot(1,2,2, aspect=1)
ax.matshow(matrix, cmap="autumn") #data[250:501,150:351])
ax.set(adjustable='datalim', aspect=1)
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.xaxis.set_ticks_position('bottom')
ax.set(adjustable='box-forced') #adjustable='datalim'
ax.grid(b=False)
print "Start of plotting part 2"
ax = fig.add_subplot(1,2,1)
phase=(9.0e-5*np.power(np.arange(0, shape[1])-shape[1]/2,3 ))/7
g=ax.get_ylim()
asp=shape[1]/float(abs(g[0]-g[1]))
ax.plot(phase) #data[250:501,150:351])
ax.set(adjustable='box-forced')#, aspect=1.06/6.0) #adjustable='datalim''box-forced'
ax.set_xlabel("x")
ax.set_ylabel("Phase")
plt.savefig('testData-x3.png')
# plt.show()
One option you have is to set the aspect of the imshow plot (which is usually 1, such that pixels are squared), to "auto", ax2.imshow(z, cmap="autumn", aspect="auto").
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-3,3)
y = np.tan(x)
z = np.random.rand(30,30)
fig, (ax, ax2) = plt.subplots(ncols=2)
ax.plot(x,y)
ax2.imshow(z, cmap="autumn", aspect="auto")
plt.show()
If instead you want to keep the aspect ratio of the image plot, you can change the aspect of the line plot by comparing the different axis limits,
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-3,3)
y = np.tan(x)
z = np.random.rand(30,30)
fig, (ax, ax2) = plt.subplots(ncols=2)
ax.plot(x,y)
ax2.imshow(z, cmap="autumn")
ratio = np.diff(ax.get_ylim())[0]/np.diff(ax.get_xlim())[0]
ratio2 = np.diff(ax2.get_ylim())[0]/np.diff(ax2.get_xlim())[0]
aspect = ratio2/ratio
ax.set_aspect(float(np.abs(aspect)))
plt.show()
I have some code to plot a grid, with the data in each cell being distinct and having a very specific position. The easiest way I found to do this was to create the grid with gridspec and use it to precisely position my subplots, however I'm having a problem where the overall grid is labelled from 0 to 1 along each axis. This happens every time, even when the dimensions of the grid are changed. Obviously these numbers have no relevance to my data, and as what I am aiming to display is qualitative rather than quantitative I would like to remove all labels from this plot entirely.
Here is a link to an image with an example of my problem
And here is the MWE that I used to create that image:
import numpy as np
import matplotlib.gridspec as gridspec
import matplotlib.pyplot as plt
# mock-up of data being used
x = 6
y = 7
table = np.zeros((x, y))
# plotting
fig = plt.figure(1)
gs = gridspec.GridSpec(x, y, wspace=0, hspace=0)
plt.title('Example Plot')
for (j, k), img in np.ndenumerate(table):
ax = fig.add_subplot(gs[x - j - 1, k])
ax.set_xticklabels('')
ax.set_yticklabels('')
plt.show()
I have not been able to find note of anything like this problem, so any help would be greatly appreciated.
If you just want to draw a grid over the plot, use this code:
import numpy as np
import matplotlib.pyplot as plt
# mock-up of data being used
x = 6
y = 7
table = np.zeros((x, y))
# plotting
fig = plt.figure(1)
plt.title('Example Plot')
plt.gca().xaxis.grid(True, color='darkgrey', linestyle='-')
plt.gca().yaxis.grid(True, color='darkgrey', linestyle='-')
plt.show()
Another variant is used gridspec:
...
# hide ticks of main axes
ax0 = plt.gca()
ax0.get_xaxis().set_ticks([])
ax0.get_yaxis().set_ticks([])
gs = gridspec.GridSpec(x, y, wspace=0, hspace=0)
plt.title('Example Plot')
for (j, k), img in np.ndenumerate(table):
ax = fig.add_subplot(gs[x - j - 1, k])
# hide ticks of gribspec axes
ax.get_xaxis().set_ticks([])
ax.get_yaxis().set_ticks([])
I am using GridSpec to plot two plots one below the other without a gap in between with
gs = gridspec.GridSpec(3, 1)
gs.update(hspace=0., wspace=0.)
ax1 = plt.subplot(gs[0:2, 0])
ax2 = plt.subplot(gs[2, 0], sharex=ax1)
which works fine. However, I want to get rid of each subplot's top and bottom tick label.
For that I use
nbins = len(ax1.get_yticklabels())
ax1.yaxis.set_major_locator(MaxNLocator(nbins=nbins, prune='both'))
nbins = len(ax2.get_yticklabels())
ax2.yaxis.set_major_locator(MaxNLocator(nbins=nbins, prune='both'))
which in many cases works fine. In some plots, however, one or more of the 4 labels to prune are still there. I looked at e.g. ax1.get_ylim() and noticed that instead of for example the upper limit being 10 (as it is shown in the plot itself), it is actually 10.000000000000002, which I suspect is the reason why it is not pruned. How does that happen and how can I get rid of that?
Here is an example: Note that in the figure the y axis is inverted and no label is pruned, altough it should be. Also note that for some reason the lowest y-label is set to a negative position, which I don't see. The y-tick positions are shown in in axis coordinates in the text within the plots. In the image below, the label at 10.6 should not be there!
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
from matplotlib.ticker import MaxNLocator
import numpy as np
x1 = 1
y1 = 10.53839
err1 = 0.00865
x2 = 2
y2 = 9.43045
err2 = 0.00658
plt.clf()
fig = plt.figure(figsize=(6, 6))
gs = gridspec.GridSpec(3, 1)
gs.update(hspace=0., wspace=0.)
ax1 = plt.subplot(gs[0:2, 0])
ax1.errorbar(x1, y1, yerr=err1)
ax1.errorbar(x2, y2, yerr=err2)
ax1.invert_yaxis()
plt.setp(ax1.get_xticklabels(), visible=False) # Remove x-labels between the plots
plt.xlim(0, 3)
ax2 = plt.subplot(gs[2, 0], sharex=ax1)
nbins = len(ax1.get_yticklabels())
ax1.yaxis.set_major_locator(MaxNLocator(nbins=8, prune='both'))
nbins = len(ax2.get_yticklabels())
ax2.yaxis.set_major_locator(MaxNLocator(nbins=6, prune='both'))
plt.savefig('prune.png')
plt.close()
Could it be, that you are looking at the left most label on the x axis of the upper plot? If so, this should do the trick:
ax1.set_xticklabels([])
EDIT: If you use sharex, you have to use this, otherwise the tick labels are removed on both axes.
plt.setp(ax1.get_xticklabels(), visible=False)
You can try to use this:
import matplotlib.ticker as mticker
ax2.yaxis.set_major_locator(mticker.MaxNLocator(nbins=7, prune='upper'))
I found the above command only works for the y-axis.
Does someone know how to set up the maximum limits of x-axis tickers' number?