How to set xlim and ylim for a subplot [duplicate] - python

This question already has answers here:
How to set the subplot axis range
(5 answers)
Closed 7 years ago.
I would like to limit the X and Y axis in matplotlib for a specific subplot.
The subplot figure itself doesn't have any axis property. I want for example to change only the limits for the second plot:
import matplotlib.pyplot as plt
fig=plt.subplot(131)
plt.scatter([1,2],[3,4])
fig=plt.subplot(132)
plt.scatter([10,20],[30,40])
fig=plt.subplot(133)
plt.scatter([15,23],[35,43])
plt.show()

You should use the OO interface to matplotlib, rather than the state machine interface. Almost all of the plt.* function are thin wrappers that basically do gca().*.
plt.subplot returns an axes object. Once you have a reference to the axes object you can plot directly to it, change its limits, etc.
import matplotlib.pyplot as plt
ax1 = plt.subplot(131)
ax1.scatter([1, 2], [3, 4])
ax1.set_xlim([0, 5])
ax1.set_ylim([0, 5])
ax2 = plt.subplot(132)
ax2.scatter([1, 2],[3, 4])
ax2.set_xlim([0, 5])
ax2.set_ylim([0, 5])
and so on for as many axes as you want.
or better, wrap it all up in a loop:
import matplotlib.pyplot as plt
DATA_x = ([1, 2],
[2, 3],
[3, 4])
DATA_y = DATA_x[::-1]
XLIMS = [[0, 10]] * 3
YLIMS = [[0, 10]] * 3
for j, (x, y, xlim, ylim) in enumerate(zip(DATA_x, DATA_y, XLIMS, YLIMS)):
ax = plt.subplot(1, 3, j + 1)
ax.scatter(x, y)
ax.set_xlim(xlim)
ax.set_ylim(ylim)

Related

How to group subplots by adjusting spaces in between

I have a subplots that look as follows:
import matplotlib.pyplot as plt
x = [1, 2, 3]
y = [4, 5, 6]
fig_shape, axs_shape = plt.subplots(2, 6, figsize=(6, 6))
for i in range(2):
for j in range(6):
axs_shape[i, j].xaxis.set_major_locator(plt.NullLocator())
axs_shape[i, j].yaxis.set_major_locator(plt.NullLocator())
for i in range(6):
axs_shape[int(i / 3), 2 * (i % 3)].plot(x, y)
axs_shape[int(i / 3), 2 * (i % 3) + 1].plot(x, y)
What I want is, that the subplots are grouped in pairs of two. That means, in each row, I want plot 0 and 1 to be right next to each other (no space in between). Then a small space and followed by plot 2 and 3 right next to each other. Then a space and plot 4 and 5 right next to each other. I read, that you can adjust sizes with .tight_layout() and subplots_adjust, but I couldn't figure out a solution for this particular behavior. Thanks a lot for your help!
You can use nested gridspecs:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
x = [1, 2, 3]
y = [4, 5, 6]
fig = plt.figure(figsize=(12, 5))
outer = gridspec.GridSpec(nrows=2, ncols=3)
axs = []
for row in range(2):
for col in range(3):
inner = gridspec.GridSpecFromSubplotSpec(nrows=1, ncols=2, subplot_spec=outer[row, col], wspace=0)
axs += [plt.subplot(cell) for cell in inner]
for ax in axs:
ax.plot(x, y)
ax.set_yticks([])
ax.set_xticks([])
plt.tight_layout()
plt.show()
PS: As mentioned in the other answer, matplotlib has implemented subfigures as a new feature. If I understand correctly, the above example would be more or less as follows:
import matplotlib.pyplot as plt
x = [1, 2, 3]
y = [4, 5, 6]
fig = plt.figure(figsize=(12, 5), constrained_layout=True)
subfigs = fig.subfigures(nrows=2, ncols=3, wspace=0.07)
axs = [subfig.subplots(nrows=1, ncols=2, gridspec_kw={'wspace': 0}) for subfig in subfigs.ravel()]
for subax in axs:
for ax in subax:
ax.plot(x, y)
ax.set_yticks([])
ax.set_xticks([])
plt.show()
With the current matplotlib 3.4.1, I don't seem to be able to have the inner plots without a gap. Setting constrained_layout=False even makes that the 4 rightmost subplots disappear. Now it looks like:
This is the goal of the new subfigure functionality: https://matplotlib.org/stable/gallery/subplots_axes_and_figures/subfigures.html?highlight=subfigure

Python matplotlib y axis is not working properly [duplicate]

This question already has an answer here:
Prevent scientific notation
(1 answer)
Closed 1 year ago.
I have a problem with y axis. It works fine until I put too high number into axis function. Here's the code.
import matplotlib.pyplot as plt
plt.style.available
input_values = [1, 2, 3, 4, 5]
squares = [1, 4, 9, 16, 25]
x_values = range(1, 1001)
y_values = [x**2 for x in x_values]
plt.style.use('seaborn')
fig, ax = plt.subplots()
ax.scatter(x_values, y_values, s=100, c=y_values, cmap=plt.cm.Blues)
ax.set_title("Kwadraty liczb", fontsize=24)
ax.set_xlabel("Wartość", fontsize=14)
ax.set_ylabel("Kwadraty wartości", fontsize=14)
ax.axis([0, 1100, 0, 1100000])
plt.show()
When i was trying to figure out why it's not working I typed different values into ymax in ax.axis and for example it works for ax.axis([0, 1100, 0 , 10000]) but when I want to get 1100000 this happens https://i.stack.imgur.com/6gSOE.png
If you mean that the y axis tick labels are automatically divided by one million (indicated by the "1e6" above the tick labels), you can configure this by creating a custom ScalarFormatter object and turning scientific notation off. For more details, see the matplotlib documentation pages on tick formatters and on ScalarFormatter.
import matplotlib.pyplot as plt
from matplotlib import ticker
plt.style.available
input_values = [1, 2, 3, 4, 5]
squares = [1, 4, 9, 16, 25]
x_values = range(1, 1001)
y_values = [x**2 for x in x_values]
plt.style.use('seaborn')
fig, ax = plt.subplots()
ax.scatter(x_values, y_values, s=100, c=y_values, cmap=plt.cm.Blues)
ax.set_title("Kwadraty liczb", fontsize=24)
ax.set_xlabel("Wartość", fontsize=14)
ax.set_ylabel("Kwadraty wartości", fontsize=14)
ax.axis([0, 1100, 0, 1100000])
formatter = ticker.ScalarFormatter()
formatter.set_scientific(False)
ax.yaxis.set_major_formatter(formatter)
plt.show()
Note that I have added a new import statement (from matplotlib import ticker) and the three lines above plt.show(). If you want this to also apply to the x axis (in case you enlarge this axis), just add a similar line of code: ax.xaxis.set_major_formatter(formatter).
While you can go through all the extra steps of creating a custom ScalarFormatter object as luuk suggested, you could achieve the same thing by simply configuring what is already provided with ax.ticklabel_format(style='plain'):
import matplotlib.pyplot as plt
#plt.style.available
input_values = [1, 2, 3, 4, 5]
squares = [1, 4, 9, 16, 25]
x_values = range(1, 1001)
y_values = [x**2 for x in x_values]
plt.style.use('seaborn')
fig, ax = plt.subplots()
ax.ticklabel_format(style='plain')
ax.scatter(x_values, y_values, s=100, c=y_values,cmap=plt.cm.Blues)
ax.set_title("Kwadraty liczb", fontsize=24)
ax.set_xlabel("Wartość", fontsize=14)
ax.set_ylabel("Kwadraty wartości", fontsize=14)
ax.axis([0, 1100, 0, 1100000])
plt.show()
Still results in the same chart desired
Also, you'll notice I commented out plt.style.available because it's useless, being overwritten by plt.style.use('seaborn').

Unable to reverse xticks inside matplotlib subplot

I have designed a subplot using matplotlib. I am trying to reverse the xticks of the plot. Please see the sample code-
import numpy as np
import matplotlib.pyplot as plt
# generate the data
n = 6
y = np.random.randint(low=0, high=10, size=n)
x = np.arange(n)
# generate the ticks and reverse it
xticks = range(n)
xticks.reverse()
# plot the data
plt.figure()
ax = plt.subplot(111)
ax.bar(x, y)
print xticks # prints [5, 4, 3, 2, 1, 0]
ax.set_xticks(xticks)
plt.show()
Please see below the generated plot-
Please pay attention to the xticks. Even though, ax.set_xticks(xticks) is used but the xticks haven't changed. Am I missing some function call to rerender the plot?
Below is the system information-
matplotlib.__version__
'2.1.1'
matplotlib.__version__numpy__
'1.7.1'
python --version
Python 2.7.15rc1
Please note that I just want to reverse the ticks and do not want to invert axis.
With ax.set_xticks, you are currently specifying tick positions which is invariant to the order of the list. Either you pass [0, 1, 2, 3, 4, 5] or you pass [5, 4, 3, 2, 1, 0]. The difference will not be noticed in the ticks. What you instead want is to have reversed ticklabels for which you should do set_xticklabels(xticks[::-1]). There are two ways to do it:
Way 1
Use plt.xticks where the first argument specifies the location of the ticks and the second arguments specifies the respective ticklabels. Specifically, xticks will provide the tick positions and xticks[::-1] will label your plot with reversed ticklabels.
xticks = range(n)
# plot the data
plt.figure()
ax = plt.subplot(111)
ax.bar(x, y)
plt.xticks(xticks, xticks[::-1])
Way 2 using ax where you need set_xticklabels to get what you want
ax.set_xticks(xticks)
ax.set_xticklabels(xticks[::-1])
Use:
# generate the data
n = 6
y = np.random.randint(low=0, high=10, size=n)
x = np.arange(n)
# generate the ticks and reverse it
xticks = range(n)
# xticks.reverse()
# plot the data
plt.figure()
ax = plt.subplot(111)
ax.bar(x, y)
# print xticks # prints [5, 4, 3, 2, 1, 0]
ax.set_xticklabels(xticks[::-1]) # <- Changed
plt.show()
You can also reverse the order of the axis ax.set_xlim([5.5, -0.5])
import numpy as np
import matplotlib.pyplot as plt
n = 6
x = np.arange(n)
y = (x+1) **(1/2)
fig, axs = plt.subplots(1, 3, constrained_layout=True)
axs[0].bar(x, y)
axs[0].set_title('Original data')
axs[1].bar(x[::-1], y)
axs[1].set_xlim(5.5, -0.5)
axs[1].set_title('x index reversed\nand axis reversed')
axs[2].bar(x, y)
axs[2].set_xlim(5.5, -0.5)
axs[2].set_title('just axis reversed')
plt.show()

Breaking a plot into subplots [duplicate]

I need to add two subplots to a figure. One subplot needs to be about three times as wide as the second (same height). I accomplished this using GridSpec and the colspan argument but I would like to do this using figure so I can save to PDF. I can adjust the first figure using the figsize argument in the constructor, but how do I change the size of the second plot?
As of matplotlib 3.6.0, width_ratios and height_ratios can now be passed directly as keyword arguments to plt.subplots and subplot_mosaic, as per What's new in Matplotlib 3.6.0 (Sep 15, 2022).
f, (a0, a1) = plt.subplots(1, 2, width_ratios=[3, 1])
f, (a0, a1, a2) = plt.subplots(3, 1, height_ratios=[1, 1, 3])
Another way is to use the subplots function and pass the width ratio with gridspec_kw
matplotlib Tutorial: Customizing Figure Layouts Using GridSpec and Other Functions
matplotlib.gridspec.GridSpec has available gridspect_kw options
import numpy as np
import matplotlib.pyplot as plt
# generate some data
x = np.arange(0, 10, 0.2)
y = np.sin(x)
# plot it
f, (a0, a1) = plt.subplots(1, 2, gridspec_kw={'width_ratios': [3, 1]})
a0.plot(x, y)
a1.plot(y, x)
f.tight_layout()
f.savefig('grid_figure.pdf')
Because the question is canonical, here is an example with vertical subplots.
# plot it
f, (a0, a1, a2) = plt.subplots(3, 1, gridspec_kw={'height_ratios': [1, 1, 3]})
a0.plot(x, y)
a1.plot(x, y)
a2.plot(x, y)
f.tight_layout()
You can use gridspec and figure:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import gridspec
# generate some data
x = np.arange(0, 10, 0.2)
y = np.sin(x)
# plot it
fig = plt.figure(figsize=(8, 6))
gs = gridspec.GridSpec(1, 2, width_ratios=[3, 1])
ax0 = plt.subplot(gs[0])
ax0.plot(x, y)
ax1 = plt.subplot(gs[1])
ax1.plot(y, x)
plt.tight_layout()
plt.savefig('grid_figure.pdf')
I used pyplot's axes object to manually adjust the sizes without using GridSpec:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.2)
y = np.sin(x)
# definitions for the axes
left, width = 0.07, 0.65
bottom, height = 0.1, .8
bottom_h = left_h = left+width+0.02
rect_cones = [left, bottom, width, height]
rect_box = [left_h, bottom, 0.17, height]
fig = plt.figure()
cones = plt.axes(rect_cones)
box = plt.axes(rect_box)
cones.plot(x, y)
box.plot(y, x)
plt.show()
Probably the simplest way is using subplot2grid, described in Customizing Location of Subplot Using GridSpec.
ax = plt.subplot2grid((2, 2), (0, 0))
is equal to
import matplotlib.gridspec as gridspec
gs = gridspec.GridSpec(2, 2)
ax = plt.subplot(gs[0, 0])
so bmu's example becomes:
import numpy as np
import matplotlib.pyplot as plt
# generate some data
x = np.arange(0, 10, 0.2)
y = np.sin(x)
# plot it
fig = plt.figure(figsize=(8, 6))
ax0 = plt.subplot2grid((1, 3), (0, 0), colspan=2)
ax0.plot(x, y)
ax1 = plt.subplot2grid((1, 3), (0, 2))
ax1.plot(y, x)
plt.tight_layout()
plt.savefig('grid_figure.pdf')
In a simple way, different size sub plotting can also be done without gridspec:
plt.figure(figsize=(12, 6))
ax1 = plt.subplot(2,3,1)
ax2 = plt.subplot(2,3,2)
ax3 = plt.subplot(2,3,3)
ax4 = plt.subplot(2,1,2)
axes = [ax1, ax2, ax3, ax4]
A nice way of doing this was added in matplotlib 3.3.0, subplot_mosaic.
You can make a nice layout using an "ASCII art" style.
For example
fig, axes = plt.subplot_mosaic("ABC;DDD")
will give you three axes on the top row and one spanning the full width on the bottom row like below
A nice thing about this method is that the axes returned from the function is a dictionary with the names you define, making it easier to keep track of what is what e.g.
axes["A"].plot([1, 2, 3], [1, 2, 3])
You can also pass a list of lists to subplot_mosaic if you want to use longer names
fig, axes = plt.subplot_mosaic(
[["top left", "top centre", "top right"],
["bottom row", "bottom row", "bottom row"]]
)
axes["top left"].plot([1, 2, 3], [1, 2, 3])
will produce the same figure

Change axis in mapltolib figure

Usually matplotlib uses this axis:
Y
|
|
|_______X
But I need to plot my data using:
_________Y
|
|
|
X
How can I do it? I will prefer not modify my data (i.e. transposing). I need to be able of use the coordinates always and matplotlib changes the axis.
One of the variations:
import matplotlib.pyplot as plt
def Scatter(x, y):
ax.scatter(y, x)
#Data preparation part:
x=[1, 2, 3, 4, 5]
y=[2, 3, 4, 5, 6]
#Plotting and axis inverting part
fig, ax = plt.subplots(figsize=(10,8))
plt.ylabel('X', fontsize=15)
plt.xlabel('Y', fontsize=15)
ax.xaxis.set_label_position('top') #This send label to top
plt.gca().invert_yaxis() #This inverts y axis
ax.xaxis.tick_top() #This send xticks to top
#User defined function Scatter
Scatter(x,y)
ax.grid()
ax.axis('scaled')
plt.show()
Output:

Categories