Plot multiple intersecting planes in 3D with matplotlib python - python

I am trying to plot three planes in 3D space with Matplotlib.
What I got so far looks not good, and I want to ask.
Is there a better solution, so they are intersected?
x = np.linspace(-5,5,2)
y = np.linspace(-5,5,2)
z = np.linspace(-5,5,2)
X,Z = np.meshgrid(x,z)
Y1 = -2*X
Y2 = (-1+X+Z)/2
Y3 = -(4-4*z)/3
# plot the surface
fig = plt.figure()
ax = fig.add_subplot(111,projection='3d')
ax.plot_surface(X, Y1, Z, alpha=0.5)
ax.plot_surface(X, Y2, Z, alpha=0.5)
ax.plot_surface(X, Y3, Z, alpha=0.5)
plt.show()

Related

Making the lines of the scatter plot smooth in MatPlotlib

I want to make the lines of the following graph smooth. I tried to search and it seems that we have to represent the x-axis in terms of a float or some type such as date time. Here since the x-axis are just labels, I could not figure out how I should change my code. Any help is appreciated.
import matplotlib.pyplot as plt
x1 = [">1", ">10",">20"]
y1 = [18,8,3]
y2 = [22,15,10]
y3=[32,17,11]
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax1.scatter(x1, y1, color='blue', label='Heuristic')
ax1.scatter(x1, y2, color='green', label='SAFE')
ax1.scatter(x1, y3, color='red', label='discovRE')
plt.plot(x1, y2, '.g:')
plt.plot(x1, y1, '.b:')
plt.plot(x1, y3, '.r:')
plt.ylabel('False Positives',fontsize=8)
plt.xlabel('Function instruction sizes',fontsize=8)
plt.legend()
plt.show()
Following is the graph that I get right now.
Maybe you can fit a curve to 'smooth' the curve
import matplotlib.pyplot as plt
x1 = [">1", ">10",">20"]
y1 = [18,8,3]
y2 = [22,15,10]
y3=[32,17,11]
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax1.scatter(x1, y1, color='blue', label='Heuristic')
ax1.scatter(x1, y2, color='green', label='SAFE')
ax1.scatter(x1, y3, color='red', label='discovRE')
buff_x = np.linspace(0,2,100)
def reg_func(y):
params = np.polyfit(range(len(y)),y,2)
return np.polyval(params,buff_x)
plt.plot(buff_x, reg_func(y2), 'g',linestyle='dotted')
plt.plot(buff_x, reg_func(y1), 'b',linestyle='dotted')
plt.plot(buff_x, reg_func(y3), 'r',linestyle='dotted')
plt.ylabel('False Positives',fontsize=8)
plt.xlabel('Function instruction sizes',fontsize=8)
plt.legend()
plt.show()
as you can see, I use a function reg_func to fit your data, and plot the predicted curves

3D wireframe plot with 2D projections: Spatial organiszation & frequency of projection

I'm working on a 3D plot displayed by a wireframe, where 2D plots are projected on the x, y, and z surface, respectively. Below you can find a minimum example.
I have 2 questions:
With contourf, the 2D plots for every x=10, x=20,... or y=10, y=20,... are displayed on the plot walls. Is there a possibility to define for which x or y, respectively, the contour plots are displayed? For example, in case I only want to have the xz contour plot for y = 0.5 mirrored on the wall?
ADDITION: To display what I mean with "2D plots", I changed "contourf" in the code to "contour" and added the resulting plot to this question. Here you can see now the xz lines for different y values, all offset to y=90. What if I do not want to have all the lines, but only two of them for defined y values?
3D_plot_with_2D_contours
As you can see in the minimum example, the 2D contour plot optically covers the wireframe 3D plot. With increasing the transparency with alpha=0.5 I can increase the transparency of the 2D contours to at least see the wireframe, but it is still optically wrong. Is it possible to sort the objects correctly?
import matplotlib.pyplot as plt,numpy as np
import pylab as pl
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt,numpy as np
plt.clf()
fig = plt.figure(1,figsize=(35,17),dpi=600,facecolor='w',edgecolor='k')
fig.set_size_inches(10.5,8)
ax = fig.gca(projection='3d')
X, Y, Z = axes3d.get_test_data(0.05)
Xnew = X + 50
Ynew = Y + 50
cset = ax.contourf(Xnew, Ynew, Z, zdir='z', offset=-100, cmap=plt.cm.coolwarm, alpha=0.5)
cset = ax.contourf(Xnew, Ynew, Z, zdir='x', offset=10, cmap=plt.cm.coolwarm, alpha=0.5)
cset = ax.contourf(Xnew, Ynew, Z, zdir='y', offset=90, cmap=plt.cm.coolwarm, alpha = 0.5)
ax.plot_wireframe(Xnew, Ynew, Z, rstride=5, cstride=5, color='black')
Z=Z-Z.min()
Z=Z/Z.max()
from scipy.ndimage.interpolation import zoom
Xall=zoom(Xnew,5)
Yall=zoom(Ynew,5)
Z=zoom(Z,5)
ax.set_xlim(10, 90)
ax.set_ylim(10, 90)
ax.set_zlim(-100, 100)
ax.tick_params(axis='z', which='major', pad=10)
ax.set_xlabel('X',labelpad=10)
ax.set_ylabel('Y',labelpad=10)
ax.set_zlabel('Z',labelpad=17)
ax.view_init(elev=35., azim=-70)
fig.tight_layout()
plt.show()
ADDITION 2: Here is the actual code I'm working with. However, the original data are hidden in the csv files which are too big to be included in the minimal example. That's why was initially replacing them by the test data. However, maybe the actual code helps nevertheless.
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt,numpy as np
import pylab as pl
from matplotlib.markers import MarkerStyle
import csv
with open("X.csv", 'r') as f:
X = list(csv.reader(f, delimiter=";"))
import numpy as np
X = np.array(X[1:], dtype=np.float)
import csv
with open("Z.csv", 'r') as f:
Z = list(csv.reader(f, delimiter=";"))
import numpy as np
Z = np.array(Z[1:], dtype=np.float)
Y = [[7,7.1,7.2,7.3,7.4,7.5,7.6,7.7,7.8,7.9,8,8.1,8.2,8.3,8.4,8.5,8.6,8.7,8.8,8.9,9]]
Xall = np.repeat(X[:],21,axis=1)
Yall = np.repeat(Y[:],30,axis=0)
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt,numpy as np
plt.clf()
fig = plt.figure(1,figsize=(35,17),dpi=600,facecolor='w',edgecolor='k')
fig.set_size_inches(10.5,8)
ax = fig.gca(projection='3d')
cset = ax.contourf(Xall, Yall, Z, 2, zdir='x', offset=0, cmap=plt.cm.coolwarm, shade = False, edgecolor='none', alpha=0.5)
cset = ax.contourf(Xall, Yall, Z, 2, zdir='y', offset=9, cmap=plt.cm.coolwarm, shade = False, edgecolor='none', alpha=0.5)
ax.plot_wireframe(Xall, Yall, Z, rstride=1, cstride=1, color='black')
Z=Z-Z.min()
Z=Z/Z.max()
from scipy.ndimage.interpolation import zoom
Xall=zoom(Xall,5)
Yall=zoom(Yall,5)
Z=zoom(Z,5)
cset = ax.plot_surface(Xall, Yall, np.zeros_like(Z)-0,facecolors=plt.cm.coolwarm(Z),shade=False,alpha=0.5,linewidth=False)
ax.set_xlim(-0.5, 31)
ax.set_ylim(6.9, 9.1)
ax.set_zlim(0, 500)
labelsx = [item.get_text() for item in ax.get_xticklabels()]
empty_string_labelsx = ['']*len(labelsx)
ax.set_xticklabels(empty_string_labelsx)
labelsy = [item.get_text() for item in ax.get_yticklabels()]
empty_string_labelsy = ['']*len(labelsy)
ax.set_yticklabels(empty_string_labelsy)
labelsz = [item.get_text() for item in ax.get_zticklabels()]
empty_string_labelsz = ['']*len(labelsz)
ax.set_zticklabels(empty_string_labelsz)
import matplotlib.ticker as ticker
ax.xaxis.set_major_locator(ticker.MultipleLocator(5))
ax.xaxis.set_minor_locator(ticker.MultipleLocator(1))
ax.yaxis.set_major_locator(ticker.MultipleLocator(0.5))
ax.yaxis.set_minor_locator(ticker.MultipleLocator(0.25))
ax.zaxis.set_major_locator(ticker.MultipleLocator(100))
ax.zaxis.set_minor_locator(ticker.MultipleLocator(50))
ax.tick_params(axis='z', which='major', pad=10)
ax.set_xlabel('X',labelpad=5,fontsize=15)
ax.set_ylabel('Y',labelpad=5,fontsize=15)
ax.set_zlabel('Z',labelpad=5,fontsize=15)
ax.view_init(elev=35., azim=-70)
fig.tight_layout()
plt.show()
Alternate possible answer.
This code demonstrates
A plot of a surface and its correponding wireframe
The creation of data and its plot of 3d lines (draped on the surface in 1) at specified values of x and y
Projections of the 3d lines (in 2) on to the frame walls
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
from scipy import interpolate
import numpy as np
# use the test data for plotting
fig = plt.figure(1, figsize=(6,6), facecolor='w', edgecolor='gray')
ax = fig.gca(projection='3d')
X, Y, Z = axes3d.get_test_data(0.1) #get 3d data at appropriate density
# create an interpolating function
# can take a long time if data is too large
f1 = interpolate.interp2d(X, Y, Z, kind='linear')
# in general, one can use a set of other X,Y,Z that cover a surface
# preferably, (X,Y) are in grid arrangement
# make up a new set of 3d data to plot
# ranges of x1, and y1 will be inside (X,Y) of the data obtained above
# related grid, x1g,y1g,z1g will be obtained from meshgrid and the interpolated function
x1 = np.linspace(-15,15,10)
y1 = np.linspace(-15,15,10)
x1g, y1g = np.meshgrid(x1, y1)
z1g = f1(x1, y1) #dont use (x1g, y1g)
# prep data for 3d line on the surface (X,Y,Z) at x=7.5
n = 12
x_pf = 7.5
x5 = x_pf*np.ones(n)
y5 = np.linspace(-15, 15, n)
z5 = f1(x_pf, y5)
# x5,y5,z5 can be used to plot 3d line on the surface (X,Y,Z)
# prep data for 3d line on the surface (X,Y,Z) at y=6
y_pf = 6
x6 = np.linspace(-15, 15, n)
y6 = x_pf*np.ones(n)
z6 = f1(x6, y_pf)
# x6,y6,z6 can be used to plot 3d line on the surface (X,Y,Z)
ax = fig.gca(projection='3d')
ax.plot_surface(x1g, y1g, z1g, alpha=0.25)
ax.plot_wireframe(x1g, y1g, z1g, rstride=2, cstride=2, color='black', zorder=10, alpha=1, lw=0.8)
# 3D lines that follow the surface
ax.plot(x5,y5,z5.flatten(), color='red', lw=4)
ax.plot(x6,y6,z6.flatten(), color='green', lw=4)
# projections of 3d curves
# project red and green lines to the walls
ax.plot(-15*np.ones(len(y5)), y5, z5.flatten(), color='red', lw=4, linestyle=':', alpha=0.6)
ax.plot(x6, 15*np.ones(len(x6)), z6.flatten(), color='green', lw=4, linestyle=':', alpha=0.6)
# projections on other sides (become vertical lines)
# change to if True, to plot these
if False:
ax.plot(x5, 15*np.ones(len(x5)), z5.flatten(), color='red', lw=4, alpha=0.3)
ax.plot(-15*np.ones(len(x6)), y6, z6.flatten(), color='green', lw=4, alpha=0.3)
ax.set_title("Projections of 3D lines")
# set limits
ax.set_xlim(-15, 15.5)
ax.set_ylim(-15.5, 15)
plt.show();
(Answer to question 1) To plot the intersections between the surface and the specified planes (y=-20, and y=20), one need to find what Y[?]=-20 and 20. By inspection, I found that Y[100]=20, Y[20]=-20.
The relevant code to plot the lines of intersection:
# By inspection, Y[100]=20, Y[20]=-20
ax.plot3D(X[100], Y[100], Z[100], color='red', lw=6) # line-1 at y=20
ax.plot3D(X[20], Y[20], Z[20], color='green', lw=6) # line-2 at y=-20
# Project them on Z=-100 plane
ax.plot3D(X[100], Y[100], -100, color='red', lw=3) # projection of Line-1
ax.plot3D(X[20], Y[20], -100, color='green', lw=3) # projection of Line-2
The output plot:
(Answer to question 2) To get better plot with the wireframe standout from the surface plot. The surface plot must be partially transparent, which is achieved by setting option alpha=0.6. The relevant code follows.
Z1 = Z-Z.min()
Z1 = Z1/Z.max()
Xall = zoom(X,3)
Yall = zoom(Y,3)
Zz = zoom(Z1, 3)
surf = ax.plot_surface(Xall, Yall, Zz, rstride=10, cstride=10,
facecolors = cm.jet(Zz/np.amax(Zz)),
linewidth=0, antialiased=True,
alpha= 0.6)
# Wireframe
ax.plot_wireframe(X, Y, Z, rstride=5, cstride=5, color='black', alpha=1, lw=0.8)
The plot is:

matplotlib 3D Surface Plot - smooth

I have my data, and I want to create a smooth plot, however after running the code, it turns out too rough. Is there a way to smooth out the plot?
my code:
fig = plt.figure(figsize = (10,10))
ax = Axes3D(fig)
# ax.view_init(azim=120, elev=30)
X = visualdf.lat
Y = visualdf.lan
Z = visualdf.students
xi = np.linspace(X.min(),X.max(),(len(Z)/3))
yi = np.linspace(Y.min(),Y.max(),(len(Z)/3))
zi = griddata((X, Y), Z, (xi[None,:], yi[:,None]), method='nearest')
xig, yig = np.meshgrid(xi, yi)
ls = LightSource(270,45)
rgb = ls.shade(zi, cmap=cm.gist_earth , vert_exag=0.1, blend_mode='soft')
surf = ax.plot_surface(xig, yig, zi, rstride=1, cstride=1, antialiased=True, shade=False, facecolors=rgb, linewidth=0)
fig.colorbar(surf, shrink=0.5, aspect=5)
ax.set_title('Lat, Lan & No of Students')
ax.set_xlabel('Latitude')
ax.set_ylabel('Longitude')
ax.set_zlabel('No of Students')
ax.set_zlim3d(0,3000)
3D plot:
Desired 3D plot, something like below:
Taken from - https://matplotlib.org/examples/mplot3d/custom_shaded_3d_surface.html

adding 3D subplot to the set of 2D

I would like to add 3D plot in matplotlib 1.5.1 to the existing set of 2D plots (subplots). 2D plots work fine w/o 3D, but when I add 3D I'm getting an error that 'module' object has no attribute 'plot_surface'. I'd like to keep the code simple so I apply all commands to plt without creating new figure(there is also a way of adding labels with set_xlabel) which makes things ambiguous. The first 3 plots are simple 2D plots and the last is 3D.
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d
y1 = u.nodes.concentration
x1 = u.nodes.x
plt.figure(figsize=(20, 10))
plt.subplot(221)
plt.title('Profile')
plt.xlabel('Range')
plt.ylabel('Concentration')
plt.plot(x1, y1, '-b')
# Inhibitor plt
y2 = z.nodes.concentration
x2 = z.nodes.x
plt.subplot(222)
plt.title('Profile')
plt.xlabel('Range')
plt.ylabel('Concentration')
plt.plot(x2, y2, '-r')
# Modulator plt
y3 = v.nodes.concentration
x3 = v.nodes.x
plt.subplot(223)
plt.title('Profile')
plt.xlabel('Range')
plt.ylabel('Concentration')
plt.plot(x3, y3, '-g')
#3D plot
plt.subplot(224, projection='3d')
# Grab data.
xx = u_fft_x_norm
yy = [i*time_period for i in xrange(1, times)]
zz = u_timespace
XX, YY = np.meshgrid(xx, yy)
ZZ = zz
# Plot a basic wireframe.
plt.plot_surface(XX, YY, ZZ, rstride=20, cstride=20)
plt.xlabel('Space')
plt.ylabel('Time')
plt.zlabel('Value')
plt.title('Profile')
I guess the error is self-explanatory. pyplot does not have a plot_surface command. There is also no indication that it should. Looking at all examples you find, plot_surface is an attribute of an axes.
ax = plt.subplot(224, projection='3d')
ax.plot_surface(X, Y, Z, cmap=cm.coolwarm, linewidth=0, antialiased=False)

Filling between two lines with Matplotlib with 2 restrictions

I would like to fill the area between the curve y1=x^3 and then line y2=3x-2.
Below is code I have that will do this, however, I want to place the restriction that y1 < y2 (which I have done with the where option of fill_between) and that x<1.
The problem that occurs with the code below is that the area between the curve is filled for x>1. I would like to plot these graphs on the range [-2.5,2.5]. How do I get matplotlib to stop filling between the curves for x>1?
My code:
import matplotlib.pyplot as plot
import numpy as np
x = np.linspace(-2.5, 2.5, 100)
y1 = np.array([i**3 for i in x])
y2 = np.array([3*i-2 for i in x])
fig = plot.figure()
ax = fig.add_subplot(1,1,1)
ax.plot(x, y1, label=r"$y=x^3$")
ax.plot(x, y2, label=r"$y=3x-2$")
ax.spines['left'].set_position('center')
ax.spines['right'].set_color('none')
ax.spines['bottom'].set_position('center')
ax.spines['top'].set_color('none')
ax.spines['left'].set_smart_bounds(True)
ax.spines['bottom'].set_smart_bounds(True)
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
ax.fill_between(x, y1, y2, where=y2<y1, facecolor='green')
ax.legend()
plot.show()
I got it. The easiest fix is to define 3 new variables, u,v, and w, where u holds the x values for v and w, and v = x^3, w=3x-2.
u=x[x<1]
v=y1[y1<1]
w=y2[y2<1]
Then plot these values with fill_between:
ax.fill_between(u, v, w, where=w<v, facecolor='green')

Categories