I have an image in a nonuniform grid, and want to plot it with one of the axes scaled logarithmically. This is possible for imshow, however that requires regularly spaced data. I can plot my irregularly gridded data with NonUniformImage, however setting ax.set_xscale('log') only has an effect on the axis, not the image itself.
Is this possible to achieve with NonUniformImage, or even possible at all? Here is some code that shows what I mean (top row is imshow, bottom is NonUniformImage).
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.image import NonUniformImage
# Linear x array for cell centers:
x = np.linspace(1, 10, 10)
# Highly nonlinear x array:
x2 = x**3
# Linear y-array
y = np.linspace(1, 10, 10)
z = np.sqrt(x[np.newaxis, :]**2 + y[:, np.newaxis]**2)
fig, axs = plt.subplots(nrows=2, ncols=2)
fig.subplots_adjust(bottom=0.07, hspace=0.3)
# Uniform Grid, linear x-axis
ax = axs[0, 0]
im = ax.imshow(z, extent=(1, 10, 1, 10), aspect='auto',origin='lower')
ax.set_title("Uniform Grid, linear x-axis")
# Uniform Grid, log x-axis (image changes)
ax = axs[0, 1]
im = ax.imshow(z, extent=(1, 10, 1, 10),aspect='auto',origin='lower')
ax.set_xscale('log')
ax.set_title('Uniform Grid, log x-axis')
# Correct ticklabel formatting
from matplotlib.ticker import StrMethodFormatter, NullFormatter
ax.xaxis.set_major_formatter(StrMethodFormatter('{x:.0f}'))
ax.xaxis.set_minor_formatter(NullFormatter())
# NonUniform Grid, linear x-axis
ax = axs[1, 0]
im = NonUniformImage(ax, interpolation='nearest', extent=(1, 1000, 1, 10))
im.set_data(x2, y, z)
ax.images.append(im)
ax.set_xlim(1, 1000)
ax.set_ylim(1, 10)
ax.set_title('NonUniform Grid, lin x-axis')
# NonUniform Grid, logarithmic x-axis (this doesn't work as intended)
ax = axs[1, 1]
im = NonUniformImage(ax, interpolation='nearest', extent=(1, 1000, 1, 10))
im.set_data(x2, y, z)
ax.images.append(im)
ax.set_xlim(1, 1000)
ax.set_ylim(1, 10)
ax.set_xscale('log')
ax.set_title('NonUniform Grid, log x-axis')
plt.show()
Related
My code is the following and I believe should produce a chart where a scatter plot is superimposed on a contourf plot (i.e. appears on the foreground)
But that does not happen.
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.scatter(examples[:,0], examples[:, 1])
ax.contourf(x, y, Z)
I expected that the scatter plot below would be superimposed on the contourf plot:
plt.scatter(x = examples[:,0], y = examples[:, 1])
Why is this and how the code should be changed?
Just swap contourf and scatter order:
import numpy as np
import matplotlib.pyplot as plt
N = 1000
xl = np.linspace(0, 10, N)
yl = np.linspace(0, 10, N)
x, y = np.meshgrid(xl, yl)
Z = x**2 + y**2
examples = np.random.uniform(low = 0, high = 10, size = (10, 2))
fig, ax = plt.subplots()
ax.contourf(x, y, Z)
ax.scatter(examples[:,0], examples[:, 1], color = 'red')
plt.show()
The last plot line you write overlaps the previous one.
I was trying to plot a time series and its differentiation.
However, I have two problems with the x axis label:
it's not rotating;
there is too many months and too little space in the canvas.
How can I rotate all labels and hide a few dates?
I can't show the data because of confidentiality. But it's basically a (numeric) column with the series and the (date) index.
This is what I've done so far:
import numpy as np, pandas as pd
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
import matplotlib.pyplot as plt
plt.rcParams.update({'figure.figsize':(9,7), 'figure.dpi':120})
# Original Series
fig, axes = plt.subplots(3, 2, sharex=True);
axes[0, 0].plot(df.teste);
axes[0, 0].set_title('Original Series');
axes[0,0].set_xticklabels(df.index,rotation=90)
plot_acf(df.teste, ax=axes[0, 1]);
# 1st Differencing
axes[1, 0].plot(df.teste.diff());
axes[1, 0].set_title('1st Order Differencing');
plot_acf(df.teste.diff().dropna(), ax=axes[1, 1]);
# 2nd Differencing
axes[2, 0].plot(df.teste.diff().diff());
axes[2, 0].set_title('2nd Order Differencing');
axes[2,0].set_xticklabels(df.index,rotation=90)
plot_acf(df.teste.diff().diff().dropna(), ax=axes[2, 1]);
This is the output:
Check this code:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 1000)
y = np.sin(x)
fig, ax = plt.subplots(1, 2, figsize = (8, 4))
ax[0].plot(x, y, 'r-', lw = 2)
ax[0].set_xticks(np.arange(0, 10, 0.25))
ax[1].plot(x, y, 'r-', lw = 2)
ax[1].set_xticks(np.arange(0, 10, 1))
locs, labels = plt.xticks()
plt.setp(labels, rotation = 90)
plt.show()
which gives me this plot as an example:
As you can see, both graph have the same options, but in the second one (on the right side) I set:
ax[1].set_xticks(np.arange(0, 10, 1))
to space the xticks in order to remove some of them, and
locs, labels = plt.xticks()
plt.setp(labels, rotation = 90)
to rotate their orientations.
I'd like to be able to rotate the view of a hemisphere in a 3D matplotlib plot and have the shape show correctly,
Answers to set matplotlib 3d plot aspect ratio? used in the first example don't help as they address the aspect ratio of the plot window.
Question: In the second example I show that if I make the scales equal lengths (-1, 1), (-1, 1), (-0.5, 1.5) I can preserve the shape as I rotate the view, but is this the only way to preserve the shape under view rotation?
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
points = np.random.random((3, 1000)) - 0.5
points /= np.sqrt((points**2).sum(axis=0))
x, y, z = points[:, points[2] > 0.] # upper hemisphere
fig = plt.figure(figsize=plt.figaspect(0.5)) # https://stackoverflow.com/a/12371373/3904031
ax1 = fig.add_subplot(2, 1, 1, projection='3d')
ax1.plot(x, y, z, '.k')
ax1.view_init(0, 90)
ax1.set_title('view_init(0, 90)', fontsize=16)
ax2 = fig.add_subplot(2, 1, 2, projection='3d')
ax2.plot(x, y, z, '.k')
ax2.view_init(90, 0)
ax2.set_title('view_init(90, 0)', fontsize=16)
plt.show()
fig = plt.figure()
ax1 = fig.add_subplot(1, 2, 1, projection='3d')
ax1.plot(x, y, z, '.k')
ax1.view_init(0, 90)
ax1.set_title('view_init(0, 90)', fontsize=16)
ax1.set_xlim(-1.0, 1.0)
ax1.set_ylim(-1.0, 1.0)
ax1.set_zlim(-0.5, 1.5)
ax2 = fig.add_subplot(1, 2, 2, projection='3d')
ax2.plot(x, y, z, '.k')
ax2.view_init(90, 0)
ax2.set_title('view_init(90, 0)', fontsize=16)
ax2.set_xlim(-1.0, 1.0)
ax2.set_ylim(-1.0, 1.0)
ax2.set_zlim(-0.5, 1.5)
plt.show()
Finally, per this answer:
Simple fix!
I've managed to get this working in version 3.3.1.
It looks like this issue has perhaps been resolved in PR#17172; You can use the ax.set_box_aspect([1,1,1]) function to ensure the aspect is correct (see the notes for the set_aspect function).
You first make the limits in all three axes the same either by adding bounding points (invisible dots beyond your data) to define a cube of equal dimensions, or just use set_xlim, set_ylim, set_zlim as I've done here.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
points = np.random.random((3, 1000)) - 0.5
points /= np.sqrt((points**2).sum(axis=0))
x, y, z = points[:, points[2] > 0.] # upper hemisphere
fig = plt.figure(figsize=plt.figaspect(0.5)) # https://stackoverflow.com/a/12371373/3904031
ax1 = fig.add_subplot(1, 2, 1, projection='3d')
ax1.plot(x, y, z, '.k')
ax1.view_init(0, 90)
ax1.set_title('view_init(0, 90)', fontsize=16)
ax2 = fig.add_subplot(1, 2, 2, projection='3d')
ax2.plot(x, y, z, '.k')
ax2.view_init(90, 0)
ax2.set_title('view_init(90, 0)', fontsize=16)
for ax in (ax1, ax2):
ax.set_xlim(-1, 1)
ax.set_ylim(-1, 1)
ax.set_zlim(-0.5, 1.5)
ax.set_box_aspect([1,1,1])
plt.show()
Is there a way of specifying the position of axis labels?
labelpad sets the space between tick labels and the axis label.
Since the width of tick labels is unknown it appears to thus be impossible to precisely position axis labels.
Here is a MWE where I would like to have the ylabels of both subplots to be vertically aligned:
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
np.random.seed(19680801)
mu, sigma = 100, 15
x = mu + sigma * np.random.randn(10000)
fig, axs = plt.subplots(2,1)
for ax in axs:
n, bins, patches = ax.hist(x, 50, normed=1, facecolor='g', alpha=0.75)
ax.set_ylabel('Probability $y$')
ax.grid(True)
ax.set_yticklabels([ r'\$\num{{{:g}}}\$'.format(item) for item in ax.get_yticks().tolist() ])
fig.show()
I tried this, but it does not work:
fig.canvas.draw()
ylabelposition = ax.yaxis.label.get_position()
ax.set_yticklabels([ r'\$\num{{{:g}}}\$'.format(item) for item in ax.get_yticks().tolist() ])
ax.yaxis.label.set_position(ylabelposition)
In the reference, they are described as:
axis('equal')
changes limits of x or y axis so that equal increments of x and y have the same length; a circle is
circular.:
axis('scaled')
achieves the same result by changing the dimensions of the plot box instead of the axis data limits.:
But I did not understand the part 'by changing the dimensions of the plot box'.
So I compared directly
import numpy as np
import matplotlib.pyplot as plt
plt.close('all')
x = np.array(np.linspace(-np.pi, np.pi))
y = np.sin(x)
ax1 = plt.subplot(2, 1, 1)
ax1 = plt.plot(x, y)
plt.axis('scaled')
ax1 = plt.subplot(2, 1, 2)
plt.plot(x, y)
plt.axis('equal')
There is only a slight difference that the width is shorter when plotted with plt.axis('scaled').
How can I know the difference better?
I think the difference becomes more apparent, if you use different data.
import numpy as np
import matplotlib.pyplot as plt
x = np.array(np.linspace(-np.pi, np.pi))
y = np.sin(x)*np.pi
ax1 = plt.subplot(2, 1, 1)
ax1 = plt.plot(x, y)
plt.axis('scaled')
ax1 = plt.subplot(2, 1, 2)
plt.plot(x, y)
plt.axis('equal')
plt.show()
So the difference is if the axes around the plot are changed according to the aspect, or if they stay the same as in a usual subplot and are scaled such, that the aspect of the plot data is equal.