How to enlarge the x, y or z axis of a 3d diagramm in matplotlib? - matplotlib

How can I set the diagramm to enlarge(!) and show all the ticks in one or more of the axis? See picture below
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import axes3d
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ys = np.linspace(0, 30, 30)
xs = np.linspace(0, 10, 10)
X, Y = np.meshgrid(xs, ys)
ax.plot_wireframe(X, Y, X * Y)
plt.show()
I don't want square axis. I guess that the default plots square axis, i.e. the axis x, y, and z have all the same length. The default looks like the following (without the red arrow!).
I need to "enlarge", "stretch" or "scale" (sorry, I don't know how it is called) the axis. For example, when the x, y axis have 30x30 values, then it is ok to have square axies like the default figuer above or the next first figure. But if they have 30x10 or 10x30 values, I would like to plot them like the next second and third figure respectively:
The suggested plt.figure(figsize=(6,2)) or plt.figure(figsize=(2,6)) has no good results for 3d diagramms. The following is not what I'm looking for:

Related

Surface Plot of a function B(x,y,z)

I have to plot a surface plot which has axes x,y,z and a colormap set by a function of x,y,z [B(x,y,z)].
I have the coordinate arrays:
x=np.arange(-100,100,1)
y=np.arange(-100,100,1)
z=np.arange(-100,100,1)
Moreover, my to-be-colormap function B(x,y,z) is a 3D array, whose B(x,y,z)[i] elements are the (x,y) coordinates at z.
I have tried something like:
Z,X,Y=np.meshgrid(z,x,y) # Z is the first one since B(x,y,z)[i] are the (x,y) coordinates at z.
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
img = ax.scatter(Z, X, Y, c=B(x,y,z), cmap=plt.hot())
fig.colorbar(img)
plt.show()
However, it unsurprisingly plots dots, which is not what I want. Rather, I need a surface plot.
The figure I have obtained:
The kind of figure I want:
where the colors are determined by B(x,y,z) for my case.
You have to:
use plot_surface to create a surface plot.
your function B(x, y, z) will be used to compute the color parameter, a number assigned to each face of the surface.
the color parameter must be normalized between 0, 1. We use matplotlib's Normalize to achieve that.
then, you create the colors by applying the colormap to the normalized color parameter.
finally, you create the plot.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from matplotlib.colors import Normalize
t = np.linspace(0, 2*np.pi)
p = np.linspace(0, 2*np.pi)
t, p = np.meshgrid(t, p)
r1, r2 = 1, 3
x = (r2 + r1 * np.cos(t)) * np.cos(p)
y = (r2 + r1 * np.cos(t)) * np.sin(p)
z = r1 * np.sin(t)
color_param = np.sin(x / 2) * np.cos(y) + z
cmap = cm.jet
norm = Normalize(vmin=color_param.min(), vmax=color_param.max())
norm_color_param = norm(color_param)
colors = cmap(norm_color_param)
fig = plt.figure()
ax = fig.add_subplot(projection="3d")
ax.plot_surface(x, y, z, facecolors=colors)
ax.set_zlim(-4, 4)
plt.show()

Matplotlib 3d barplot failing to draw just one face

import numpy as np
import matplotlib.pyplot as plt
x, y = np.array([[x, y] for x in range(5) for y in range(x+1)]).T
z = 1/ (5*x + 5)
fig = plt.figure()
ax = fig.gca(projection = '3d')
ax.bar3d(x, y, np.zeros_like(z), dx = 1, dy = 1, dz = z)
yields
How do I get the face at (1,0) to display properly?
There is currently no good solution to this. Fortunately though, it happens only for some viewing angles. So you can choose an angle where it plots fine, e.g.
ax.view_init(azim=-60, elev=25)

Errorbar variable marker size

I want to plot some data x and y in which I need the marker size to depend on a third array z. I could plot them separately (i.e., scatter x and y with size = z, and errorbar without marker, fmc = 'none') and this solves it. The problem is that I need the legend to show the errorbar AND the dot, together:
and not
Code is here with some made-up data:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(1,10,100)
y = 2*x
yerr = np.random(0.5,1.0,100)
z = np.random(1,10,100)
fig, ax = plt.subplots()
plt.scatter(x, y, s=z, facecolors='', edgecolors='red', label='Scatter')
ax.errorbar(x, y, yerr=yerr, xerr=0, fmt='none', mfc='o', color='red', capthick=1, label='Error bar')
plt.legend()
plt.show()
which produces the legend I want to avoid:
In errorbar the argumentmarkersizedoes not accept arrays asscatter` does.
The idea is usually to use a proxy to put into the legend. So while the errorbar in the plot may have no marker, the one in the legend has a marker set.
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(1,10,11)
y = 2*x
yerr = np.random.rand(11)*5
z = np.random.rand(11)*2+5
fig, ax = plt.subplots()
sc = ax.scatter(x, y, s=z**2, facecolors='', edgecolors='red')
errb = ax.errorbar(x, y, yerr=yerr, xerr=0, fmt='none',
color='red', capthick=1, label="errorbar")
proxy = ax.errorbar([], [], yerr=[], xerr=[], marker='o', mfc="none", mec="red",
color='red', capthick=1, label="errorbar")
ax.legend(handles=[proxy], labels=["errorbar"])
plt.show()

Why is my y-axis inverted when using meshgrid?

I'm trying to run the following:
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
x = np.linspace(-15, 15, 10)
y = np.linspace(-15, 15, 10)
X, Y = np.meshgrid(x, y)
Z = Y;
# Z = X;
cmap = mpl.colors.ListedColormap(['r', 'b'])
bounds = [-300, 0, 300]
norm = mpl.colors.BoundaryNorm(bounds, cmap.N)
plt.figure();
plt.xlabel('x');
plt.ylabel('y');
im = plt.imshow(Z,cmap= cmap, norm = norm)
plt.show();
If I try to do Z = X, it works fine. But if I do Z = Y, the y-axis is inverted, i.e. red (negative) at the top, and blue (positive) at the bottom. Why is this happening?
Inverted compared to what?
The plot you have is working fine in both cases, as expected. The value of Z[0,0], which is -15 in this case, is plotted in red at the coordinate 0,0.
If you want the y axis to start at the bottom instead of the top, use the origin="lower" keyword argument to imshow.

How to set set the marker size of a 3D scatter plot fixed to the axis?

I've asked a similar question before (How to set a fixed/static size of circle marker on a scatter plot?), but now I wanna do it in 3D. How can I do that?
thanks
As in the 2D case, you need to draw the spheres yourself. If you want nicely shaped spheres this means to draw many patches and thus gets slow quite quickly.
Here's a basic way of doing it:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
def plot_shere(ax, x, y, z, r, resolution=100, **kwargs):
""" simple function to plot a sphere to a 3d axes """
u = np.linspace(0, 2 * np.pi, resolution)
v = np.linspace(0, np.pi, resolution)
xx = r * np.outer(np.cos(u), np.sin(v)) + x
yy = r * np.outer(np.sin(u), np.sin(v)) + y
zz = r * np.outer(np.ones(np.size(u)), np.cos(v)) + z
ax.plot_surface(xx, yy, zz, rstride=4, cstride=4, **kwargs)
# create some random data (set seed to make it reproducable)
np.random.seed(0)
(x,y,z) = np.random.randint(0,10,(3,5))
r = np.random.randint(2,4,(5,))
# set up the figure
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
# loop through the data and plot the spheres
for p in zip(x,y,z,r):
plot_shere(ax, *p, edgecolor='none', color=np.random.rand(3))
# set the axes limits and show the plot
ax.set_ylim([-4,14])
ax.set_xlim([-4,14])
ax.set_zlim([-4,14])
plt.show()
Result: