3D plane plot with wireframes matplotlib - python-3.x

I have created a 3d plot that contains two wireframes of half sheres and a point:
now i want to add to it a plane that touches both the point and the tops of the wireframes.
the point is at [0,0,0].
the first sphere is centered at [4.73 , 4.73 , 0] with radius r = 0.29
the second shpere is centered at [0, 9.46 , 0] with radius r = 2.176
This is the code i have so far. Anyone can suggest how to add the plane in the same plot?
theta, phi = np.linspace(0, np.pi, 10), np.linspace(0,2* np.pi, 13)
THETA, PHI = np.meshgrid(theta, phi)
R2 = r_2
X2 = R2 * np.sin(THETA) * np.cos(PHI) + x_in[1]
Y2 = R2 *np.sin(THETA) * np.sin(PHI) + y_in[1]
Z2 = R2 *np.absolute(np.cos(THETA))
R3 = r_3
X3 = R3 * np.sin(THETA) * np.cos(PHI) + x_in[2]
Y3 = R3 *np.sin(THETA) * np.sin(PHI) + y_in[2]
Z3 = R3 *np.absolute(np.cos(THETA))
fig = plt.figure(figsize = (10,10))
ax = fig.add_subplot(1,1,1, projection='3d')
plot = ax.plot_wireframe(X2, Y2, Z2, rstride=1, cstride=1, linewidth=1,antialiased=False,\
alpha=1)
plot = ax.plot_wireframe(X3, Y3, Z3, rstride=1, cstride=1, linewidth=1, antialiased=False,\
alpha=1)
ax.scatter(x_in[0] , y_in[0] , 0, color='blue')
plt.show()

Related

How to a reach solid surface in 3d surface in matplotlib?

How to reach a solid surface in 3d surface in matplotlib, please? I tried to apply plot_surface more times, but the refinement is limited and not enough. The transparency is still obvious. More sample also did not help.
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
# Coordinate for the cylinder
def data_for_cylinder_along_z(center_x,center_y,radius,height_z):
z = np.linspace(0, height_z, 200)
theta = np.linspace(0, 2*np.pi, 200)
theta_grid, z_grid=np.meshgrid(theta, z)
x_grid = radius*np.cos(theta_grid) + center_x
y_grid = radius*np.sin(theta_grid) + center_y
return x_grid,y_grid,z_grid
fig = plt.figure(figsize = (5,10))
ax = fig.add_subplot(111, projection='3d')
ax.set_xlim(-2, 2)
ax.set_ylim(-2, 2)
ax.set_zlim(0, 10)
ax.get_proj = lambda: np.dot(Axes3D.get_proj(ax), np.diag([0.4, 0.4, 1.6, 1])) # (x, y, z) ration of sides
theta1 = np.linspace(0, 2*np.pi, 100)
r1 = np.linspace(-2, 0, 100)
t1, R1 = np.meshgrid(theta1, r1)
X1 = R1*np.cos(t1)
Y1 = R1*np.sin(t1)
Z1 = 3+R1*1.5+4
ax.set_xlabel('x axis')
ax.set_ylabel('y axis')
ax.set_zlabel('z axis')
ax.plot_surface(X1, Y1, Z1, color="dimgray")
ax.plot_surface(X1, Y1, Z1, color="dimgray")
# Cylinder
Xc,Yc,Zc = data_for_cylinder_along_z(0,0,2,4)
rep=10
for i in range(rep):
ax.plot_surface(Xc, Yc, Zc, color = 'palegoldenrod')
plt.show()
you need to set antialiased to True (found by trial and error, couldn't find description in the docs):
# Cylinder
Xc,Yc,Zc = data_for_cylinder_along_z(0,0,2,4)
ax.plot_surface(Xc, Yc, Zc, color='palegoldenrod', antialiased=False)

How to color space between two lines with a colour transition?

How to colour space between two lines with a colour transition? For instance, with grey colour - the dark grey from the upper line should become lighter as proceeding to the lower line. Thank you
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
plt.rcParams["figure.figsize"] = [8, 8]
x = np.linspace(0, 1, 100)
y = 0.3*x
ax.set_ylim(-0.2, 0.6)
ax.plot(x, y)
width_l = ax.get_ylim()[1] - ax.get_ylim()[0]
ax.plot(x, y - 0.1*width_l)
plt.show()
Edit
And this, please? How to make the width of the coloured part the same?
import matplotlib.pyplot as plt
import numpy as np
import pywt
fig, ax = plt.subplots()
plt.rcParams["figure.figsize"] = [8, 8]
wavelet = pywt.ContinuousWavelet('morl')
psi, x = wavelet.wavefun(level=2)
cmap = plt.get_cmap('Greys_r')
ax.plot(x, psi)
ax.set_xlim(ax.get_xlim()[0], ax.get_xlim()[1])
y_a = ax.get_ylim()
ax.set_ylim(y_a[0],y_a[1]*1.3)
width_l = ax.get_ylim()[1] - ax.get_ylim()[0]
x_range = ax.get_xlim()[1] - ax.get_xlim()[0]
x_shift = x_range * 0.1
ax.plot([x[0]+x_shift, x[1]+x_shift], [psi[0], psi[1]])
ax.plot([x[2]-x_shift, x[3]-x_shift], [psi[2], psi[3]])
ax.plot([x[1], x[2]], [psi[1]-width_l*0.1, psi[2]-width_l*0.1])
for t in np.linspace(0, 1, 40):
ax.plot(x, psi - t * 0.1 * width_l, color=cmap(t/2 + 0.25))
plt.show()
You could draw a lot of parallel lines (or curves) using a color from a gray-scale colormap. The example code below uses a transformation u = t/2 + 0.25, so when t goes from 0 to 1, u would just go between 0.25 and 0.75 to select of specific range from the colormap, avoiding the very dark and very light parts.
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
plt.rcParams["figure.figsize"] = [8, 8]
x = np.linspace(0, 1, 100)
y = 0.3 * x
width_l = ax.get_ylim()[1] - ax.get_ylim()[0]
ax.set_ylim(-0.2, 0.6)
cmap = plt.get_cmap('Greys_r')
for t in np.linspace(0, 1, 40):
u = t/2 + 0.25
ax.plot(x, y - t * 0.1 * width_l, color=cmap(u))
ax.plot(x, y)
ax.plot(x, y - 0.1 * width_l)
plt.show()

Add points to a circle

I constructed a large uniform circle (dots = 8000000) in python 3. In the next step, I would like to add additional dots (in myList) outside the circle but at the corresponding position.
import matplotlib.pyplot as plt
import numpy as np
circleSize = 8000000
myList = [155744, 213230, 215537, 262274, 262613, 6143898, 244883, 509516, 1997259, 2336382]
fig = plt.figure(figsize=(4, 4))
n_dots = circleSize # set number of points in circle
uniformSpacing = np.linspace(0, 2*np.pi, n_dots) # create uniform spacing between points
center_x, center_y = (50, 20) # set the center of the circle
x_coord, y_coord = [], [] # for coordinates of points to plot
radius = 10.0 # set the radius of circle
for items in uniformSpacing :
x = center_x + radius*np.cos(items)
y = center_y + radius*np.sin(items)
x_coord.append(x)
y_coord.append(y)
plt.scatter(x_coord, y_coord, c = 'black', s=1) # plot points
plt.show()
How can I add the points to my plot?
Thank you!
If you're coming from a MATLAB background, pyplot has hold on by default, so you can do multiple plot() or scatter() calls without it erasing what was on the plot before.
Also, since you're already using numpy, you should utilize its vectorization capabilities and calculate x_coord and y_coord using SIMD instructions rather than looping and appending to a Python list (which is painfully slow).
fig = plt.figure(figsize=(4, 4))
n_dots = circleSize # set number of points in circle
uniformSpacing = np.linspace(0, 2*np.pi, n_dots) # create uniform spacing between points
center_x, center_y = (50, 20) # set the center of the circle
radius = 10.0 # set the radius of circle
x_coord = center_x + radius * np.cos(uniformSpacing)
y_coord = center_y + radius * np.sin(uniformSpacing)
plt.scatter(x_coord, y_coord, marker='o', color='k');
new_dots_angles = np.linspace(0, 2 * np.pi, 5)
new_radius = 15.0
new_xcoord = center_x + new_radius * np.cos(new_dots_angles)
new_ycoord = center_y + new_radius * np.sin(new_dots_angles)
plt.scatter(new_xcoord, new_ycoord, marker='*', color='r')

Buggy vectors in quiver plot (Gradient of of Voltage) with matplotlib

I edited some examples to make a simulation for the voltage superposition of 2 point charges and made a 3D surface plot, the code is the following:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
q1 = 2e-9
q2 = -2e-9
K = 9e9
#Charge1 position
x1 = 2.0
y1 = 4.0
#Charge2 position
x2 = 6.0
y2 = 4.0
x = np.linspace(0,8,50)
y = np.linspace(0,8,50)
x, y = np.meshgrid(x,y)
r1 = np.sqrt((x - x1)**2 + (y - y1)**2)
r2 = np.sqrt((x - x2)**2 + (y - y2)**2)
V = K*(q1/r1 + q2/r2)
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(x, y, V, rstride=1, cstride=1, cmap=cm.rainbow,
linewidth=0, antialiased=False)
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
3D Surface
Now what I want to do is a contour plot with a vector (quiver) plot on top of it. I tried the following code, but I get a bunch of buggy vectors coming out of both charges, even the negative one:
fig2, ax2 = plt.subplots(1,1)
cp = ax2.contourf(x, y, V, cmap=cm.coolwarm)
fig2.colorbar(cp)
v,u = np.gradient(-V, 0.2, 0.2) #E = -∇V
ax2.quiver(x, y, u, v)
ax2.set_title("Point Charges")
plt.show()
Buggy vectors
I suspect that the long vectors are related to a division by zero. The vectors should come out of the positive charge and get into the negative one. But how would I go about fixing them? Thanks in advance.
Welcome to SO, very nice MWE. One option would be to exclude all vectors beyond a certain length by setting them to NaN. Here I use the 95th percentile.
r = np.sqrt(u**2 + v**2)
is_valid = r < np.percentile(r, 95)
u[~is_valid] = np.nan
v[~is_valid] = np.nan
x[~is_valid] = np.nan
y[~is_valid] = np.nan
fig2, ax2 = plt.subplots(1,1)
cp = ax2.contourf(x, y, V, cmap=cm.coolwarm)
fig2.colorbar(cp)
ax2.quiver(x, y, u, v)
ax2.set_title("Point Charges")
ax2.set_xlim(0, 8)
ax2.set_ylim(0, 8)
plt.show()

Coloring the area between two curves with bokeh

I've got a code with bokeh. There is two math functions where there is an area zone between these two functions in the interval [0, 2]. How can I fill this area zone with a color? I can't use polygon because it is not a polygon.
Here's the code:
import numpy as np
from bokeh.plotting import *
N = 300
x0 = np.linspace(-1, 4, N)
x1 = np.linspace(0, 4, N)
y0 = 0.5 * (x0 ** 2)
y1 = np.sqrt(2 * x1)
y2 = -y1
# output to static HTML file
output_file('plotting_areas.html')
TOOLS = 'pan, wheel_zoom, box_zoom, reset,save, box_select, lasso_select'
p = figure(tools=TOOLS, width=350, height=350,
title=None, x_range=(-1, 5), y_range=(-5, 5))
p.line(x0, y0)
p.line(x1, y1)
p.line(x1, y2)
show(p)
And here is an image for more details.
Thanks
There is nothing built in to Bokeh that will do, e.g. a flood fill, which is really what would be needed. Your best bet is to compute a polygonal approximation to the area yourself.
Otherwise you could (in principle) create a custom extension to perform a flood-fill in JavaScript, but I'm not sure how much effort that would take.
Ok, I've found the solution with bokeh and it is very simple and possible. The key is making two vectors (arrays) with the images of every two math functions between the OX interval. For each vector make a polygon with patch bokeh instruction without border line.
Here is the code:
import numpy as np
from bokeh.plotting import *
N = 300
x0 = np.linspace(-1, 4, N)
x1 = np.linspace(0, 4, N)
y0 = 0.5 * (x0 ** 2)
y1 = np.sqrt(2 * x1)
y2 = -y1
def f1(x):
return 0.5 * (x**2)
def f2(x):
return np.sqrt(2 * x)
z = np.zeros(N)
w = np.zeros(N)
x = np.linspace(0, 2, N)
for i in np.arange(len(x)):
z[i] = f1(x[i])
w[i] = f2(x[i])
# output to static HTML file
output_file('plotting_areas.html')
TOOLS = 'pan, wheel_zoom, box_zoom, reset,save, box_select, lasso_select'
p = figure(tools=TOOLS, width=350, height=350,
title=None, x_range=(-1, 5), y_range=(-5, 5))
p.line(x0, y0)
p.line(x1, y1)
p.line(x1, y2)
p.patch(x, z, color='red')
p.patch(x, w, color='red')
show(p)
And here is an image with the optimal solution:
Thanks
There is VArea now which should do the trick. Perhaps you might want to restict the plotting range to f1 > f2.

Resources