So I'm having an issue where I want to plot a simple box, with a wire frame, one panel coloured and spheres on the corners. However, whilst I've managed to do this, the spheres are a source of issue in that they obstruct the wire frame in places (which I like) but not in other places.
Any ideas why this is occurring and how to resolve the matter?
import numpy as NP
import os
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
os.system( 'cls' )
def main( ):
fig = plt.figure( figsize = ( cm2inch( 6 ), cm2inch ( 6 ) ), dpi = 100 )
ax = fig.add_subplot(111, projection='3d')
# Box frame plot
ax.plot( xs = [ 0, 0, 1, 1, 0 ], ys = [ 0, 1, 1, 0, 0 ], zs = [ 0, 0, 0, 0, 0 ], color = 'black', linewidth = 2 ) #<- Base
ax.plot( xs = [ 0, 0, 1, 1, 0 ], ys = [ 0, 1, 1, 0, 0 ], zs = [ 1, 1, 1, 1, 1 ], color = 'black', linewidth = 2 ) #<- Top
ax.plot( xs = [ 0, 0, 1, 1, 0 ], ys = [ 0, 0, 0, 0, 0 ], zs = [ 0, 1, 1, 0, 0 ], color = 'black', linewidth = 2 ) #<- Front
ax.plot( xs = [ 0, 0, 1, 1, 0 ], ys = [ 1, 1, 1, 1, 1 ], zs = [ 0, 1, 1, 0, 0 ], color = 'black', linewidth = 2 ) #<- Back
# Back face plot
xs = [ 0, 0, 1, 1, 0 ]
ys = [ 1, 1, 1, 1, 1 ]
zs = [ 0, 1, 1, 0, 0 ]
verts = [ list( zip( xs, ys, zs ) ) ]
temp = Poly3DCollection( verts, alpha = 0.25 )
temp.set_facecolor( 'blue' )
ax.add_collection3d( temp )
# Corner sphere plots
for x in [ 0, 1 ]:
for y in [ 0, 1 ]:
for z in [ 0, 1 ]:
xs, ys, zs = drawSphere( x, y, z, 0.05 )
ax.plot_surface(xs, ys, zs, color="r", alpha = 1)
#plt.axis('scaled')
plt.axis( 'off' )
plt.savefig( 'Example', pad_inches = 0, transparent = False, dpi = 400 )
plt.show()
plt.close( )
def drawSphere( xCenter, yCenter, zCenter, r ):
#draw sphere
u, v = NP.mgrid[ 0 : 2 * NP.pi : 20j, 0 : NP.pi : 10j ]
x = NP.cos( u ) * NP.sin( v )
y = NP.sin( u ) * NP.sin( v )
z = NP.cos( v )
# shift and scale sphere
x = r * x + xCenter
y = r * y + yCenter
z = r * z + zCenter
return( x, y, z)
def cm2inch( cm ):
inches = cm / 2.54
return inches
if __name__ == '__main__':
main( )
Related
I'm plotting 100K+ cylinders which are added to a GLViewWidget like this:
openGlWidget = GLViewWidget()
points = np.array([
[0, 1, 2],
[0, 1, 5],
[4, 1, 6],
[4, 1, 10]
])
cyl = MeshData.cylinder(6, 6, radius=[.1, .1])
for i in range(0, len(points), 2):
mesh = GLMeshItem(meshdata=cyl)
p1, p2 = points[i], points[i+1]
v = p2 - p1
theta = np.arctan2(v[1], v[0])
phi = np.arctan2(np.linalg.norm(v[:2]), v[2])
tr = Transform3D()
tr.translate(*p1)
tr.rotate(theta * 180 / np.pi, 0, 0, 1)
tr.rotate(phi * 180 / np.pi, 0, 1, 0)
tr.translate(0, 0, 1)
tr.scale(1, 1, np.linalg.norm(v1))
mesh.setTransform(tr)
self.openGlWidget.addItem(mesh)
This of course gives low fps when rotating/paning and I assume a good part of it has to do with adding that many singular items. So, I started thinking about the possibility of combining the cylinders into one item, is this possible? And/or should I be using something else than the GLViewWidget?
I wanted to follow a tutorial posted by Omar Aflak on https://medium.com/swlh/ray-tracing-from-scratch-in-python-41670e6a96f9 but I can’t seem to produce an image? I’m using jupyter notebook if that helps!
This is part of the code that he used, the full one is in the link above!
camera = np.array([0, 0, 1])
ratio = float(width) / height
screen = (-1, 1 / ratio, 1, -1 / ratio) # left, top, right, bottom
light = { 'position': np.array([5, 5, 5]), 'ambient': np.array([1, 1, 1]), 'diffuse': np.array([1, 1, 1]), 'specular': np.array([1, 1, 1]) }
objects = [
{ 'center': np.array([-0.2, 0, -1]), 'radius': 0.7, 'ambient': np.array([0.1, 0, 0]), 'diffuse': np.array([0.7, 0, 0]), 'specular': np.array([1, 1, 1]), 'shininess': 100, 'reflection': 0.5 },
{ 'center': np.array([0.1, -0.3, 0]), 'radius': 0.1, 'ambient': np.array([0.1, 0, 0.1]), 'diffuse': np.array([0.7, 0, 0.7]), 'specular': np.array([1, 1, 1]), 'shininess': 100, 'reflection': 0.5 },
{ 'center': np.array([-0.3, 0, 0]), 'radius': 0.15, 'ambient': np.array([0, 0.1, 0]), 'diffuse': np.array([0, 0.6, 0]), 'specular': np.array([1, 1, 1]), 'shininess': 100, 'reflection': 0.5 },
{ 'center': np.array([0, -9000, 0]), 'radius': 9000 - 0.7, 'ambient': np.array([0.1, 0.1, 0.1]), 'diffuse': np.array([0.6, 0.6, 0.6]), 'specular': np.array([1, 1, 1]), 'shininess': 100, 'reflection': 0.5 }
]
image = np.zeros((height, width, 3))
for i, y in enumerate(np.linspace(screen[1], screen[3], height)):
for j, x in enumerate(np.linspace(screen[0], screen[2], width)):
# screen is on origin
pixel = np.array([x, y, 0])
origin = camera
direction = normalize(pixel - origin)
color = np.zeros((3))
reflection = 1
for k in range(max_depth):
# check for intersections
nearest_object, min_distance = nearest_intersected_object(objects, origin, direction)
if nearest_object is None:
break
intersection = origin + min_distance * direction
normal_to_surface = normalize(intersection - nearest_object['center'])
shifted_point = intersection + 1e-5 * normal_to_surface
intersection_to_light = normalize(light['position'] - shifted_point)
_, min_distance = nearest_intersected_object(objects, shifted_point, intersection_to_light)
intersection_to_light_distance = np.linalg.norm(light['position'] - intersection)
is_shadowed = min_distance < intersection_to_light_distance
if is_shadowed:
break
illumination = np.zeros((3))
# ambiant
illumination += nearest_object['ambient'] * light['ambient']
# diffuse
illumination += nearest_object['diffuse'] * light['diffuse'] * np.dot(intersection_to_light, normal_to_surface)
# specular
intersection_to_camera = normalize(camera - intersection)
H = normalize(intersection_to_light + intersection_to_camera)
illumination += nearest_object['specular'] * light['specular'] * np.dot(normal_to_surface, H) ** (nearest_object['shininess'] / 4)
# reflection
color += reflection * illumination
reflection *= nearest_object['reflection']
origin = shifted_point
direction = reflected(direction, normal_to_surface)
image[i, j] = np.clip(color, 0, 1)
print("%d/%d" % (i + 1, height))
plt.imsave('image.png', image)
Instead of producing an image it just gave me a series of fractions from 1/200 to 200/200…does anyone know how to fix this?
I have a numpy array created as follows
results = np.zeros((X, Y, Z))
Then I am setting values of the points in 3D space as follows (representative of density / intensity of that point)
results[x,y,z] = 5.0
I now want to visualize this data using the x,y,z coordinates and an intensity value (like opacity or size of a scatter plot). However I cannot figure out how to convert this into four lists of x, y, z, and intensity, for a 3D scatter plot. How do I do this?
i would do smth like this:
import numpy as np
import matplotlib.pyplot as plt
dots = np.random.randint(0, 2, size = (3, 3, 3))
dots *= np.random.randint(0, 2, size = (3, 3, 3))
dots *= np.arange(27).reshape(3, 3, 3)
x, y, z = np.where(dots!=0)
o = dots[x, y, z]
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
for i in range(len(x)):
print(o[i]/27)
ax.plot([x[i]], [y[i]], [z[i]], 'o', color=[0, 0, 0, float(o[i])/27])
output:
dots =
[[[ 0 0 0]
[ 0 0 0]
[ 6 0 0]]
[[ 0 0 11]
[ 0 13 0]
[15 16 17]]
[[ 0 0 0]
[21 22 23]
[24 0 0]]]
My solution:
fig = plt.figure(figsize=(15, 15))
ax = fig.add_subplot(projection="3d")
plt.title("Spherical Potential Heatmap ($J = 32, simuls = 6.4M, E = 1, cutoff = 100$)", fontsize=18)
ax.xaxis.pane.fill = False
ax.yaxis.pane.fill = False
ax.zaxis.pane.fill = False
mask = base_array_e0 > 100
idx = np.arange(int(np.prod(base_array_e0.shape)))
x, y, z = np.unravel_index(idx, base_array_e0.shape)
plot = ax.scatter(x, y, z, c=base_array_e0.flatten(), s=10.0 * mask, edgecolor="face", alpha=0.15, marker="o", cmap="magma", linewidth=0)
color_bar = plt.colorbar(plot, ax = ax,fraction=0.036, pad=0.04)
color_bar.set_alpha(1)
color_bar.draw_all()
color_bar.set_label('Steps')
plt.savefig('random_walk_3d_energy_sphere_0.png', bbox_inches='tight');
I want to create the graph bellow, but I want to add a horizontal line marker to each group as shown bellow, do you know how to add it based on the code I currently have?
data = np.array([
[5, 3, 2 ],
[2, -3, 5 ],
[ -4, 4, -6],
[-5, -3, -1],
[2, 6, 6]
])
bar_markers = np.array([4, 3, -2, 2, -1])
fig, axs = plt.subplots()
index = np.arange(len(data[:, 0]))
width = 0.25
p1 = plt.bar(index, data[:,0], width, bottom = 0, color = 'yellowgreen')
p2 = plt.bar(index+width, data[:, 1], width, bottom = 0, color = 'purple')
p3 = plt.bar(index+2*width, data[:, 2], width, bottom = 0, color = 'pink')
axs.set_xticks(index + width / 2)
plt.show()
You can "cheat" and make the height of each bar 0 but start the bottom of each bar at a different height, i.e. do this:
p4 = plt.bar(index+width, [0]*len(bar_markers), width*3, bottom=bar_markers, edgecolor='k')
I have array points
nodes = [(1, 2), (6, 15), (10, 6), (10, 3), (3, 7)]
And now, I need draw Spline passing through the points. You can see image result
But I don't know how to draw with matplotlib.pyplot. Help me
So , the right piece of code is:
from __future__ import division
import matplotlib.pyplot as plt
import numpy as np
from scipy import interpolate
nodes = np.array( [ [1, 2], [6, 15], [10, 6], [10, 3], [3, 7] ] )
x = nodes[:,0]
y = nodes[:,1]
tck,u = interpolate.splprep( [x,y] ,s = 0 )
xnew,ynew = interpolate.splev( np.linspace( 0, 1, 100 ), tck,der = 0)
plt.plot( x,y,'o' , xnew ,ynew )
plt.legend( [ 'data' , 'spline'] )
plt.axis( [ x.min() - 1 , x.max() + 1 , y.min() - 1 , y.max() + 2 ] )
plt.show()