Python legend in 3dplot - python

I am plotting a 3d plot in python 2.7
When I try to plot a 3d plot with color and marker as in 2D plot() function. I come across an error.
So I tried to plot line separately and measured points with markers separately using scatter() function.
When I create legend entries my legend looks like this
But I don't want to have duplicate legend entries instead
I want my legend entries to group with colour, or
Is it possible have both marker and line as a single entry so that there are only 5 entries in my legend
I found a similar question to this (How to make custom legend in matplotlib) but it does not solve my problem
I am appending a code similar to my problem
import matplotlib as mpl
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
mpl.rcParams['legend.fontsize'] = 10
fig = plt.figure()
ax = fig.gca(projection='3d')
theta = np.linspace(-4 * np.pi, 4 * np.pi, 100)
z = np.linspace(-2, 2, 100)
r = z**2 + 1
x = r * np.sin(theta)
y = r * np.cos(theta)
ax.plot(x, y, z, label='parametric curve 1')
ax.scatter(x, y, z, label='parametric curve 1',marker = 'o')
x = r * np.sin(theta + 1)
y = r * np.cos(theta + 1)
ax.plot(x, y, z, label='parametric curve 2')
ax.scatter(x, y, z, label='parametric curve 2',marker = 'o')
ax.legend()
plt.show()
The above code gives me a plot shown below
Plot
But I want my legend to have only two entries

Are you using the standard Matplotlib library to generate these 3D plots? If so, starting from the example in the documentation (http://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html#line-plots) it seems to work fine:
import matplotlib as mpl
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
mpl.rcParams['legend.fontsize'] = 10
fig = plt.figure()
ax = fig.gca(projection='3d')
theta = np.linspace(-4 * np.pi, 4 * np.pi, 100)
z = np.linspace(-2, 2, 100)
r = z**2 + 1
x = r * np.sin(theta)
y = r * np.cos(theta)
ax.plot(x, y, z, label='parametric curve 1', marker='o')
x = r * np.sin(theta + 1)
y = r * np.cos(theta + 1)
ax.plot(x, y, z, label='parametric curve 2', marker='o')
ax.legend()
plt.show()

Related

Good-looking sphere in Matplotlib

I've been trying to plot a (3d) sphere with some curves on it using Matplotlib, but so far the my results are disappointing.
I've tried with several RGB colors, opacities and colormaps, but the output is similar.
How could I do something like this Bloch Sphere? That's just what I'm looking for.
Thanks in advance!
To get a 3d plot more similar to the one you're showing, you can add some circular curves and lines along each axis. For example:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
# Make data
r = 10
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)
x = r * np.outer(np.cos(u), np.sin(v))
y = r * np.outer(np.sin(u), np.sin(v))
z = r * np.outer(np.ones(np.size(u)), np.cos(v))
# Plot the surface
ax.plot_surface(x, y, z, color='linen', alpha=0.5)
# plot circular curves over the surface
theta = np.linspace(0, 2 * np.pi, 100)
z = np.zeros(100)
x = r * np.sin(theta)
y = r * np.cos(theta)
ax.plot(x, y, z, color='black', alpha=0.75)
ax.plot(z, x, y, color='black', alpha=0.75)
## add axis lines
zeros = np.zeros(1000)
line = np.linspace(-10,10,1000)
ax.plot(line, zeros, zeros, color='black', alpha=0.75)
ax.plot(zeros, line, zeros, color='black', alpha=0.75)
ax.plot(zeros, zeros, line, color='black', alpha=0.75)
plt.show()

Multiple 2D contour plots in one 3D figure in python

Is there any way available in python to plot multiple 2D contour plots in one 3D plot in python. I am currently using matplotlib for contouring, but not finding any option for what I am searching for. A sample image I have added. But I want to do it on Z-axis.
You can try this.
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.path import Path
import matplotlib.patches as patches
fig = plt.figure()
ax = fig.gca(projection='3d')
x = np.linspace(0, 1, 100)
X, Y = np.meshgrid(x, x)
levels = np.linspace(-0.1, 0.4, 100) #(z_min,z_max,number of contour),
a=0
b=1
c=2
Z1 = a+.1*np.sin(2*X)*np.sin(4*Y)
Z2 = b+.1*np.sin(3*X)*np.sin(4*Y)
Z3 = c+.1*np.sin(4*X)*np.sin(5*Y)
plt.contourf(X, Y,Z1, levels=a+levels,cmap=plt.get_cmap('rainbow'))
plt.contourf(X, Y,Z2, levels=b+levels,cmap=plt.get_cmap('rainbow'))
plt.contourf(X, Y,Z3, levels=c+levels,cmap=plt.get_cmap('rainbow'))
ax.set_xlim3d(0, 1)
ax.set_ylim3d(0, 1)
ax.set_zlim3d(0, 2)
plt.show()
In order to plot true 2-D contour plots in one 3D plot, try this:
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.gca(projection='3d')
x = np.linspace(0, 1, 100)
X, Y = np.meshgrid(x, x)
Z1 = .1*np.sin(2*X)*np.sin(4*Y)
Z2 = .1*np.sin(3*X)*np.sin(4*Y)
Z3 = .1*np.sin(4*X)*np.sin(5*Y)
levels=np.linspace(Z1.min(), Z1.max(), 100)
ax.contourf(X, Y,Z1, levels=levels, zdir='z', offset=0, cmap=plt.get_cmap('rainbow'))
levels=np.linspace(Z2.min(), Z2.max(), 100)
ax.contourf(X, Y,Z2, levels=levels, zdir='z', offset=1, cmap=plt.get_cmap('rainbow'))
levels=np.linspace(Z3.min(), Z3.max(), 100)
ax.contourf(X, Y,Z3, levels=levels, zdir='z', offset=2, cmap=plt.get_cmap('rainbow'))
ax.set_xlim3d(0, 1)
ax.set_ylim3d(0, 1)
ax.set_zlim3d(0, 2)
plt.show()
enter image description here

not all scatter points are shown on plot_surface

I am trying to visualize points on 3d surface.
For some reason only some points are shown in the plot.
When I start to move the plot around, some points suddenly appear. Is there a way to visualize points on a 3d surface?
This is the result I am getting right now:
And below the code used to generate it:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
# Make data.
X = np.arange(-5, 5, 0.1)
Y = np.arange(-5, 5, 0.1)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X ** 2 + Y ** 2)
Z = np.sin(R)
# Plot the surface.
surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm, linewidth=0, antialiased=False)
X = np.arange(-5, 5, 1)
Y = np.arange(-5, 5, 1)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X ** 2 + Y ** 2)
Z = np.sin(R)
ax.scatter(X, Y, Z, c='r', marker='o')
# Customize the z axis.
ax.set_zlim(-1.01, 1.01)
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
# Add a color bar which maps values to colors.
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()

Matplotlib color 3D gridlines

I was looking for a way to change the color of a 3D plots gridlines and was unable to find a clean and easy way to do so. The only answer I found was here and it came off as a bit complex. I was wondering if there was an easier way to color the gridlines of a 3D plot in matplotlib using mpl_toolkits.mplot3d
simple example found here
import matplotlib as mpl
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
mpl.rcParams['legend.fontsize'] = 10
fig = plt.figure()
ax = fig.gca(projection='3d')
theta = np.linspace(-4 * np.pi, 4 * np.pi, 100)
z = np.linspace(-2, 2, 100)
r = z**2 + 1
x = r * np.sin(theta)
y = r * np.cos(theta)
ax.plot(x, y, z, label='parametric curve')
ax.legend()
plt.show()
The code from the question you found is so complex because it colorizes single lines of the grid.
If the aim is to colorize all gridlines simulatneously, you may just use
plt.rcParams['grid.color'] = "deeppink"

Matplotlib colored sphere

I have a data set which maps a tuple of phi and theta to
a value which represents the strength of the signal.
I want to plot these on a sphere. I simply followed
a demo from matplotlib and adjusted the code to my
use case.
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
u = phi
v = theta
vals =vals/vals.max()
Map = cm.coolwarm
facecolors = Map(vals[:])
x = 10 * np.outer(np.cos(u), np.sin(v))
y = 10 * np.outer(np.sin(u), np.sin(v))
z = 10 * np.outer(np.ones(np.size(u)), np.cos(v))
ax.plot_surface(x, y, z, rstride=1, cstride=1, cmap=cm.coolwarm,
linewidth=0, antialiased=False, facecolors=facecolors)
plt.show()
This generates an error message IndexError: index 4 is out of bounds for axis 0 with size 4. I also looked into the source code, which seems
to indicate to me that facecolors isn't formatted correctly, but I'm
struggling to figure out, what formatting is needed exactly.
Any help or other ways to achieve this goal would be greatly
appreciated.
Greetings
If your question is: "How to get rid of this IndexError?", I modified your code and now it works. plot_surface takes X,Y,Z and facecolors as 2D arrays of corresponding values on a 2D grid. Facecolors in your case weren't and this was the source of your error.
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm, colors
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
u, v = np.mgrid[0:np.pi:50j, 0:2*np.pi:50j]
strength = u
norm=colors.Normalize(vmin = np.min(strength),
vmax = np.max(strength), clip = False)
x = 10 * np.sin(u) * np.cos(v)
y = 10 * np.sin(u) * np.sin(v)
z = 10 * np.cos(u)
ax.plot_surface(x, y, z, rstride=1, cstride=1, cmap=cm.coolwarm,
linewidth=0, antialiased=False,
facecolors=cm.coolwarm(norm(strength)))
plt.show()
Result is this image of a sphere.
However, if your data is not on a 2D grid you are in trouble. Additionally if your grid is not regular the sphere you plot will look irregular as well. So if your question is: "How to plot a heatmap on a sphere?", there is already such a question and solution here using Basemap package produces this result:

Categories