I am trying the fill the space between my lines in 3D.
I have the following code:
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.collections import PolyCollection
import matplotlib.pyplot as plt
import numpy as np
class plotting3D(object):
"""
Class to plot 3d
"""
def __init__(self):
pass
def cc(self, arg):
return colorConverter.to_rgba(arg, alpha=0.6)
def poly3d(self, df):
"""
Method to create depth of joints plot for GP regression.
"""
fig = plt.figure(figsize=(10,10))
ax = fig.gca(projection='3d')
which_joints = df.columns
dix = df.index.values
zs = [1,4]
verts = []
for j in which_joints:
verts.append(list(zip(dix,df[j])))
poly = PolyCollection(verts,facecolors=[self.cc('r'), self.cc('g')])
poly.set_alpha(0.6)
ax.add_collection3d(poly, zs=zs, zdir='y')
ax.set_ylim([0, 5])
ax.set_zlim([0, 20])
ax.set_xlim([0,dix[-1]])
ax.grid(False)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
plt.show()
Some synthetic data:
k= pd.DataFrame(20*np.random.rand(10,2),columns=['foot','other_foot'])
Produces this:
Now I want to fill the space between the lines and say z=-30 NOT z=0 which is what I am trying to change.
df.index.values take a values between 0 and say 1000. And the ang dataframe has values ranging from -30 to 10.
Hence, I am trying to produce an offset version of this:
Another solution to my suggestion in the comments is to use fill_between; there you have the possibility to set the lower boundary. fill_between returns a PolyCollection, so you can add it to the 3d figure similar to what you are doing now:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(10,10))
ax = fig.gca(projection='3d')
# +/- your data:
z = [0,10,10,-20,10,0]
x = [0,1000,1500,2500,3000,3500]
ax.add_collection3d(plt.fill_between(x,z,0), zs=1, zdir='y') # lower boundary z=0
ax.add_collection3d(plt.fill_between(x,z,-30), zs=5, zdir='y') # lower boundary z=-30
ax.set_ylim([0, 5])
ax.set_zlim([-30, 20])
ax.set_xlim([0,3500])
Related
I am trying to draw a curve without a line (skeleton). I want the axis and grid lines only.
Here is the code.
++++++++++
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams["figure.figsize"] = [10.00, 7.00]
plt.rcParams["figure.autolayout"] = True
x = [1.6,2,2.5,3.2,4,5,6.3,8,10,13,16,20,25,32,40,50,63,80,100,130,160,200,250,320,400,500,630,800,1000]
y = range(1,10000,350)#[1,10,100,1000,10000]
# Display grid
plt.grid(True, which="both")
default_x_ticks = range(len(x))
plt.plot(default_x_ticks, y)
plt.yscale('log')
plt.xticks(default_x_ticks, x, rotation=90)
plt.show()
+++++++
Kindly help draw without the curve.
By adding
print(plt.xlim())
print(plt.ylim())
to your code you get the exact axis limits.
These can be used in a second run to create the plot without actually plotting anything:
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams["figure.figsize"] = [10.00, 7.00]
plt.rcParams["figure.autolayout"] = True
x = [1.6,2,2.5,3.2,4,5,6.3,8,10,13,16,20,25,32,40,50,63,80,100,130,160,200,250,320,400,500,630,800,1000]
y = range(1,10000,350)#[1,10,100,1000,10000]
# Display grid
plt.grid(True, which="both")
default_x_ticks = range(len(x))
# plt.plot(default_x_ticks, y)
plt.yscale('log')
plt.xticks(default_x_ticks, x, rotation=90)
plt.xlim(-1.4, 29.4)
plt.ylim(0.6315917965717447, 15517.934294269562)
plt.show()
I want to add a colormap to this interpolated line, such that the colour of the line-segment changes with the value in the y-axis.
import matplotlib.pyplot as plt
import numpy as np
from scipy.interpolate import CubicHermiteSpline
fig, ax = plt.subplots()
x = [1,2,3,4,5,6,7,8,9,10]
y = [8,2,1,7,5,5,8,1,9,5]
cs = CubicHermiteSpline(x, y, np.zeros(len(x)))
xs = np.linspace(min(x), max(x), num=100)
ax.plot(xs, cs(xs))
Further updates:
I took the suggestion of playing around with this tutorial. I've been able to create a LineCollection and apply the colormap. However, the multicoloured line will only show up behind the plotted line. Removing the plot command removes all lines from plot.
import matplotlib.pyplot as plt
import numpy as np
from scipy.interpolate import CubicHermiteSpline
from matplotlib.collections import LineCollection
from matplotlib.colors import ListedColormap, BoundaryNorm
fig, ax = plt.subplots()
x = [1,2,3,4,5,6,7,8,9,10]
y = [8,2,1,7,5,5,8,1,9,5]
cs = CubicHermiteSpline(x, y, np.zeros(len(x)))
xs = np.linspace(min(x), max(x), num=400)
points = np.array([xs, cs(xs)]).T.reshape(-1, 1, 2)
segments = np.concatenate([points[:-1], points[1:]], axis=1)
norm = plt.Normalize(cs(xs).min(), cs(xs).max())
lc = LineCollection(segments, cmap='rainbow', norm=norm)
lc.set_array(cs(xs))
lc.set_linewidth(2)
line = ax.add_collection(lc)
fig.colorbar(line, ax=ax)
ax.plot(xs, cs(xs))
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()
How can I plot the paraboloid after fitting it using Python? in order to get that plot
import numpy as np
import scipy.optimize as opt
import matplotlib.pyplot as plt
doex = [0.4,0.165,0.165,0.585,0.585]
doey = [.45, .22, .63, .22, .63]
doez = np.array([1, .99, .98,.97,.96])
def paraBolEqn(data,a,b,c,d):
x,y = data
return -(((x-b)/a)**2+((y-d)/c)**2)+1.0
popt,pcov=opt.curve_fit(paraBolEqn,np.vstack((doex,doey)),doez,p0=[1.5,0.4,1.5,0.4])
print(popt)
Everything you need to know is documented at the mplot3d tutorial, where the different methods to make 3d plots in matplotlib are presented.
Your desired plot can be reproduced using the methods Axes3D.plot_wireframe and Axes3D.scatter:
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(figsize=(8,6))
ax = fig.add_subplot(111, projection='3d')
x, y = np.meshgrid(np.linspace(np.min(doex), np.max(doex),10), np.linspace(np.min(doey),np.max(doey), 10))
ax.plot_wireframe(x, y, paraBolEqn((x,y), *popt))
ax.scatter(doex, doey, doez, color='b')
which results in the following plot:
Python plot in Matplotlib: I have a number of samples taken daily at the same time which shows a change in measurement (of something). This may be shown as a 2D plot (below left), but as the sample number increases I'd like to display this data as a 3D plot which is stacked (below right image) - this image is for illustration only.
For a starting point my code is below, how may I achieve this?
import numpy as np
import pylab as plt
t = np.arange(1024)*1e-6
y1 = np.sin(t*2e3*np.pi)
y2 = 0.5*y1
y3 = 0.25*y1
plt.plot(t,y1,'k-', label='12/03/14')
plt.plot(t,y2,'r-', label='13/03/14')
plt.plot(t,y3,'b-', label='14/03/14')
plt.xlabel('Time/sample no.')
plt.ylabel('Pk-pk level (arbitrary units)')
plt.legend()
plt.grid()
plt.show()
Would it be something like this?
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.collections import PolyCollection
from matplotlib.colors import colorConverter
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
zs = [0.0, 1.0, 2.0]
t = np.arange(1024)*1e-6
ones = np.ones(1024)
y1 = np.sin(t*2e3*np.pi)
y2 = 0.5*y1
y3 = 0.25*y1
verts=[list(zip(t, y1)), list(zip(t, y2)), list(zip(t, y3))]
poly = PolyCollection(verts, facecolors = ['r','g','b'])
poly.set_alpha(0.7)
ax.add_collection3d(poly, zs=zs, zdir='y')
ax.set_xlabel('X')
ax.set_xlim3d(0, 1024e-6)
ax.set_ylabel('Y')
ax.set_ylim3d(-1, 3)
ax.set_zlabel('Z')
ax.set_zlim3d(-1, 1)
plt.show()