I was unsuccessful browsing web for a solution for the following simple question:
How to draw 3D polygon (say a filled rectangle or triangle) using vertices values?
I have tried many ideas but all failed, see:
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.collections import PolyCollection
import matplotlib.pyplot as plt
fig = plt.figure()
ax = Axes3D(fig)
x = [0,1,1,0]
y = [0,0,1,1]
z = [0,1,0,1]
verts = [zip(x, y,z)]
ax.add_collection3d(PolyCollection(verts),zs=z)
plt.show()
I appreciate in advance any idea/comment.
Updates based on the accepted answer:
import mpl_toolkits.mplot3d as a3
import matplotlib.colors as colors
import pylab as pl
import numpy as np
ax = a3.Axes3D(pl.figure())
for i in range(10000):
vtx = np.random.rand(3,3)
tri = a3.art3d.Poly3DCollection([vtx])
tri.set_color(colors.rgb2hex(np.random.rand(3)))
tri.set_edgecolor('k')
ax.add_collection3d(tri)
pl.show()
Here is the result:
I think you've almost got it. Is this what you want?
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
import matplotlib.pyplot as plt
fig = plt.figure()
ax = Axes3D(fig, auto_add_to_figure=False)
fig.add_axes(ax)
x = [0,1,1,0]
y = [0,0,1,1]
z = [0,1,0,1]
verts = [list(zip(x,y,z))]
ax.add_collection3d(Poly3DCollection(verts))
plt.show()
You might also be interested in art3d.pathpatch_2d_to_3d.
The above solution is for Python 2, and gives an error 'TypeError: object of type 'zip' has no len()' when run with python 3.
See Plotting 3D Polygons in Python 3 for discussion on updating this to Python 3.
Here's some working code from there:
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
import matplotlib.pyplot as plt
fig = plt.figure()
ax = Axes3D(fig)
x = [0, 1, 1, 0]
y = [0, 0, 1, 1]
z = [0, 1, 0, 1]
verts = [list(zip(x, y, z))]
print(verts)
ax.add_collection3d(Poly3DCollection(verts), zs='z')
plt.show()
Related
I had pretty nice plots looking like this created a while ago in python 2.7.
Now it appears that LogNorm does not work anymore.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
fig = plt.figure()
ax = fig.add_subplot(111)
# creating logspaced values for colorbar
x = np.logspace(-8,-3,6)
yarr = np.vstack((x,))
print(yarr)
# check if yarr is really logspaced
ax.plot(yarr, [1e1]*len(yarr), 'w.-')
# fill box with colorbar - this does not work anymore
ax.imshow(yarr, extent=(1e-8, 1e-3, 1, 1e4), norm=LogNorm(vmin=1e-8, vmax=1e-3))
ax.set_xscale("log")
ax.set_yscale("log")
Output now
Thanks in advance.
It was pointed out to me that it is a problem of matplotlib:
https://github.com/matplotlib/matplotlib/issues/7661/
import numpy as np
import matplotlib.pyplot as plt
tmp = np.arange(199).reshape(1, 199)
y = np.logspace(0, -4, 2)
x = np.logspace(-8, -3, 200)
fig, ax = plt.subplots()
ax.set_xscale('log')
ax.set_yscale('log')
ax.pcolormesh(x, y, tmp)
plt.show()
This solves the problem.
I need to plot a family of parametric curves in a single figure for each alpha values as mentioned in the code
import numpy as np
from sympy import *
from sympy.plotting import plot_parametric
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
a=45
t = symbols('t')
for alpha in np.arange(0.5,3,.1):
M=a*sqrt(cos(2*t)+sqrt(pow(alpha,4)+pow(sin(2*t),2)))
x = M*cos(t)
y = M*sin(t)
plot_parametric(x, y, (t, 0, 2*pi))
The code returns a sequence of 2D plots for each alpha value. Instead, I want to plot the whole set of plots in one figure, something like this image attached
Any solution?
from numpy import arange, cos, linspace, pi, sin, sqrt
from matplotlib.pyplot import colorbar, Normalize, show, subplots
from matplotlib.cm import ScalarMappable, viridis
a=45
t= linspace(0, 2*pi, 2001)
norm = Normalize(vmin=0.5, vmax=3)
cmap = viridis
sm = ScalarMappable(cmap=cmap, norm=norm)
fig, (ax_xy, ax_tM) = subplots(1, 2, figsize=(10, 4), constrained_layout=1)
for alpha in arange(0.5,3,.1):
color = cmap(norm(alpha))
M=a*sqrt(cos(2*t)+sqrt(pow(alpha,4)+pow(sin(2*t),2)))
x = M*cos(t)
y = M*sin(t)
ax_tM.plot(t, M, color=color)
ax_xy.plot(x, y, color=color)
colorbar(sm, aspect=40)
show()
I am trying to plot a 3D-Array in matplotlib, but I only see a linear output. The expected output was a 10x10x10 cube.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
points = np.zeros((10, 10, 10))
for x in range(10):
for y in range(10):
for z in range(10):
points[x][y][z] = z
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(points[:,0],points[:,1],points[:,2])
plt.show()
OK, you were very, very close. I didn't realize how close until I tried it. The problem you had was that you made points a 3D array where each entry had a value. It needed to be a 2D array, 1000 x 3.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
points = []
for x in range(10):
for y in range(10):
for z in range(10):
points.append((x,y,z))
points = np.array(points)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(points[:,0],points[:,1],points[:,2])
plt.show()
You've got a good answer by Tim. However, there are alternatives approaches. For example, there is np.meshgrid() that are often used in your situation to produce and manipulate data. Here is the code to generate array of data and produce sample plot.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
n1 = 10 #number of grid rows/columns
xg, yg = np.meshgrid(np.arange(n1),np.arange(n1))
for i in np.arange(n1):
zg = np.ones(xg.shape) * i
ax.scatter(xg, yg, zg, s=3, c='k')
lim = n1 + 0.1*n1
ax.set_xlim3d(-0.1*n1, lim)
ax.set_ylim3d(-0.1*n1, lim)
ax.set_zlim3d(-0.1*n1, lim)
# set viewing angle
ax.azim = 120 # z rotation (default=270); 160+112
ax.elev = 35 # x rotation (default=0)
ax.dist = 10 # zoom (define perspective)
plt.show()
I would like to know how to transform data so as to obtain:
a plot of each signal from each file corresponding to an Z Value in one image.
View 3D Data with X, Y, Z .
(X,Y) from import text files and Z is a list.
X column 1 and Y column 2,
I have written some code,
import matplotlib.pyplot as plt
import glob,os
from matplotlib import pyplot
from mpl_toolkits.mplot3d.axes3d import Axes3D
from pylab import *
from mpl_toolkits.mplot3d import axes3d
for data in glob.iglob("S21/*.txt"):
data = np.loadtxt(data,skiprows=21)
fig = plt.figure()
ax = fig.gca(projection='3d')
x_data = data[:, 1]
y_data = data[:, 2]
x_array = np.array(x_data)
y_array = np.array(y_data)
z_array = np.array([0,100,200,300,400,500,600,700,800,900,1000,1100])
X,Y,Z = x_array, y_array, z_array
plt.plot(X,Y,"o",label= 'Measured Data')
ax.set_xlabel('X')
ax.set_xlim3d()
ax.set_ylabel('Y')
ax.set_ylim3d()
ax.set_zlabel('Z')
ax.set_zlim3d()
plt.show()
Is it possible in matplotlib to generate a quiver plot with arrowheads on both sides of the arrows and if so how (without the obvious workaround of over plotting two sets of arrows).
A workaround is to create two arrows pointing in opposite directions.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d', proj_type = 'ortho')
ax.set_xlim(-2, 2)
ax.set_ylim(-2, 2)
ax.set_zlim(-2, 2)
v_location = [0, 0, 0]
v = [1, 1, 0]
v_temp = np.concatenate([np.array(v_location), np.array(v)])
v_q = ax.quiver(*v_temp, color='black', arrow_length_ratio=0.2)
v_temp = np.concatenate([np.array(v_location), -np.array(v)])
v_q = ax.quiver(*v_temp, color='black', arrow_length_ratio=0.2)