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').
Related
I'm having issues with a scatter plot legend: I need the size of the legend dots to be bigger, but I don't know how to do it. I tried to multiply 'sizes' * 100 but then in the legend the dots overlap. Thanks for your help.
here's my code:
x = np.array([1,2,3,4,5,6,7,8,9,10])
y = np.array([13,27,36,9,10,22,62,77,42,46])
sizes = np.array([1,2,3,4,5,1,3,9,5,2])
fig, ax = plt.subplots(figsize=(12, 8))
scatter = ax.scatter(x, y, s=sizes)
handles, labels = scatter.legend_elements(prop="sizes",
alpha=0.6)
ax.legend(
handles,
labels,
loc="lower right",
bbox_to_anchor=(1.27, 0.5),
ncol=2, frameon=False
);
The legend has a keyword markerscale= to scale the markers up or down compared to how they look in the plot. Note that this scale is linear (0.5 means half as wide, while the s= parameter of plt.scatter() is relative to the area of the marker).
Here is an example, scaling the markers on the plot by 100 and halving the dots in the legend:
import matplotlib.pyplot as plt
import numpy as np
x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
y = np.array([13, 27, 36, 9, 10, 22, 62, 77, 42, 46])
sizes = np.array([1, 2, 3, 4, 5, 1, 3, 9, 5, 2])
fig, ax = plt.subplots(figsize=(12, 8))
scatter = ax.scatter(x, y, s=sizes * 100)
handles, labels = scatter.legend_elements(prop="sizes", alpha=0.6)
ax.legend(handles, labels,
loc="center left", bbox_to_anchor=(1.01, 0.5),
markerscale=0.5,
ncol=2, frameon=False)
plt.tight_layout()
plt.plot()
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
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()
I have an errorbar plot where the xaxis is a list of datetime objects. The standard plotting method will put the first and last point so that they are right on the bounding box of the plot. I would like to offset by a half tick so that the first and last point can be seen clearly.
ax.axis(xmin=-0.5,xmax=len(dates)-0.5)
does not work for obvious reasons. It would be nice to be able to do this without hardcoding any dates.
The following will produce a plot which has ten points but you can really only see 8.
import datetime
import matplotlib.pyplot as plt
dates = [datetime.date(2002, 3, 11) - datetime.timedelta(days=x) for x in range(0, 10)]
yvalues = [2, 4, 1,7,9,2, 4, 1,7,9]
errorvalues = [0.4, 0.1, 0.3,0.4, 0.1,.4, 0.1, 0.3,0.4, 0.1]
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.errorbar(dates,yvalues,yerr=errorvalues,fmt='.')
fig.autofmt_xdate()
plt.show()
An ugly fix for this could be the following
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.errorbar(range(len(dates)),yvalues,yerr=errorvalues)
ax.set_xticks(range(len(dates))
ax.set_xticklabels(dates, fontsize=8)
ax.axis(xmin=-0.5,xmax=len(dates)-0.5)
fig.autofmt_xdate()
The downside to this is that the axis objects are not of the datetime type so you can't use many functions.
You can use ax.margins to get what you want.
Without seeing your data, it's hard to know how big of a margin you actually want. If you're plotting with python datetime-types, a margin of 1 corresponds to a pretty big margin:
fig, ax = plt.subplots()
ax.bar(x, y)
[t.set_ha('right') for t in ax.get_xticklabels()]
[t.set_rotation_mode('anchor') for t in ax.get_xticklabels()]
[t.set_rotation(45) for t in ax.get_xticklabels()]
ax.margins(x=1)
But again, it's hard to get too specific without seeing your existing data and plots.
You can set spacing with margins()
import datetime
import matplotlib.pyplot as plt
dates = [datetime.date(2002, 3, 11) - datetime.timedelta(days=x) for x in range(0, 10)]
yvalues = [2, 4, 1,7,9,2, 4, 1,7,9]
errorvalues = [0.4, 0.1, 0.3,0.4, 0.1,.4, 0.1, 0.3,0.4, 0.1]
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.errorbar(dates,yvalues,yerr=errorvalues,fmt='.')
ax.margins(x=0.05)
fig.autofmt_xdate()
plt.show()
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)