"""Interpolate the arrays of a source Mesh (RandomHills) onto another (ellipsoid) by averaging closest point values""" from vedo import ParametricShape, Sphere, show # RandomHills already contains the height as a scalar defined on vertices h = ParametricShape('RandomHills') h.cmap('hsv', vmin=0, vmax=6) h.addScalarBar3D(title='RandomHills height scalar value') # interpolate such values on a completely different Mesh. # pick N=4 closest points and assign an ave value based on shepard kernel. s = Sphere().scale([1, 1, 0.5]).pos(-.1, 1.5, 0.3).alpha(1).lw(0.1) s.interpolateDataFrom(h, N=4, kernel='gaussian') s.cmap('hsv', vmin=0, vmax=6) show(h, s, __doc__, axes=1)
data.append([place, theta, phi, confirmed, deaths, recos]) data.append(['U.S.A.\n', 0.9, 1.4, conf_us, deat_us, reco_us]) return (date, data, csvdata['Confirmed'].sum(), csvdata['Deaths'].sum(), csvdata['Recovered'].sum()) # Create the scene ------------------------------------------------------------- from vedo import spher2cart, Sphere, Text2D, Earth, merge, show date, data, allconf, alldeat, allreco = load_data() s1, s2, vigs = [], [], [] for place, theta, phi, confirmed, deaths, recos in data: pos = spher2cart(1, theta, phi) fl = 'cases: ' + str(confirmed) + '\ndeaths: ' + str(deaths) radius = np.power(confirmed, 1 / 3) / 4000 sph1 = Sphere(pos, radius, alpha=0.4, res=12).flag(place + fl) if deaths > 20000: sph1.flag(fl) anchorpt = sph1.pos() * (1 + radius) vig = sph1.vignette(place, anchorpt, font="Kanopus") vig.c('k').scale(1.5 * (1 + radius)).followCamera() vigs.append(vig) s1.append(sph1) s2.append( Sphere(pos, np.power(deaths, 1 / 3) / 10000, alpha=0.4, c='k', res=10)) tx = Text2D('COVID-19 spread on ' + date + '\n# cases : ' + str(allconf) + '\n# deaths: ' + str(alldeat) + '\n# recovd: ' + str(allreco) + '\n(hover mouse for local info)', font="VictorMono")
pts = [] for i, longs in enumerate(agrid_reco): ilat = grid_reco.lats()[i] for j, value in enumerate(longs): ilong = grid_reco.lons()[j] th = np.deg2rad(90 - ilat) ph = np.deg2rad(ilong) r = value + rbias p = np.array([sin(th) * cos(ph), sin(th) * sin(ph), cos(th)]) * r pts.append(p) return pts vp = Plotter(shape=[2, 2], axes=3, interactive=0) shape1 = Sphere(alpha=0.2) shape2 = vp.load(datadir + "icosahedron.vtk").normalize().lineWidth(1) agrid1, actorpts1 = makeGrid(shape1, N) vp.show(shape1, actorpts1, at=0) agrid2, actorpts2 = makeGrid(shape2, N) vp.show(shape2, actorpts2, at=1) vp.camera.Zoom(1.2) vp.interactive = False clm1 = pyshtools.SHGrid.from_array(agrid1).expand() clm2 = pyshtools.SHGrid.from_array(agrid2).expand() # clm1.plot_spectrum2d() # plot the value of the sph harm. coefficients
def make_actor_label( atlas, actors, labels, size=300, color=None, radius=100, xoffset=0, yoffset=-500, zoffset=0, ): """ Adds a 2D text ancored to a point on the actor's mesh to label what the actor is :param kwargs: key word arguments can be passed to determine text appearance and location: - size: int, text size. Default 300 - color: str, text color. A list of colors can be passed if None the actor's color is used. Default None. - xoffset, yoffset, zoffset: integers that shift the label position - radius: radius of sphere used to denote label anchor. Set to 0 or None to hide. """ offset = [-yoffset, -zoffset, xoffset] default_offset = np.array([0, -200, 100]) new_actors = [] for n, (actor, label) in enumerate(zip(listify(actors), listify(labels))): # Get label color if color is None: color = [0.2, 0.2, 0.2] # Get mesh's highest point points = actor.points().copy() point = points[np.argmin(points[:, 1]), :] point += np.array(offset) + default_offset try: if atlas.hemisphere_from_coords(point, as_string=True) == "left": point = atlas.mirror_point_across_hemispheres(point) except IndexError: pass # Create label txt = Text3D(label, point, s=size, c=color) txt._kwargs = dict( size=size, color=color, radius=radius, xoffset=xoffset, yoffset=yoffset, zoffset=zoffset, ) # rotate label p = txt.pos() txt.pos(x=0, y=0, z=0).rotateX(180).rotateY(180).pos(p) new_actors.append(txt) # Mark a point on Mesh that corresponds to the label location if radius is not None: pt = actor.closestPoint(point) sphere = Sphere(pt, r=radius, c=color) sphere.ancor = pt new_actors.append(sphere) return new_actors
from vedo import Cone, Sphere, merge, Volume import numpy as np import vtk print('---------------------------------') print('vtkVersion', vtk.vtkVersion().GetVTKVersion()) print('---------------------------------') ##################################### cone = Cone(res=48) sphere = Sphere(res=24) carr = cone.cellCenters()[:, 2] parr = cone.points()[:, 0] cone.pointdata["parr"] = parr cone.celldata["carr"] = carr carr = sphere.cellCenters()[:, 2] parr = sphere.points()[:, 0] sphere.pointdata["parr"] = parr sphere.celldata["carr"] = carr sphere.pointdata["pvectors"] = np.sin(sphere.points()) sphere.addElevationScalars() cone.computeNormals() sphere.computeNormals()
ListPos.append(PossiblePos[n]) del PossiblePos[n] Pos = np.array(ListPos) # Create an array with all the radius and a list with all the masses Radius = np.concatenate((np.array([Rb]), np.array([Rs] * (Nsp - 1)))) Mass = [1.0] + [Ms] * (Nsp - 1) # Create the initial array of velocities at random with big sphere at rest ListVel = [(0.0, 0.0)] for s in range(1, Nsp): ListVel.append((Rb * random.uniform(-1, 1), Rb * random.uniform(-1, 1))) Vel = np.array(ListVel) # Create the spheres Spheres = [Sphere(pos=(Pos[0][0], Pos[0][1], 0), r=Radius[0], c="red", res=12).phong()] for s in range(1, Nsp): a = Sphere(pos=(Pos[s][0], Pos[s][1], 0), r=Radius[s], c="blue", res=6).phong() Spheres.append(a) # plt += a plt += Spheres plt += Grid(sx=screen_w, sy=screen_w) # Auxiliary variables Id = np.identity(Nsp) Dij = (Radius + Radius[:, np.newaxis]) ** 2 # Matrix Dij=(Ri+Rj)**2 # The main loop pb = ProgressBar(0, 2000, c="r") for i in pb.range(): # Update all positions
# Create the initial positions and velocitites (0,0) of the bobs bob_x = [0] bob_y = [0] x_dot = np.zeros(N+1) # velocities y_dot = np.zeros(N+1) for k in range(1, N + 1): alpha = np.pi / 5 * k / 10 bob_x.append(bob_x[k - 1] + np.cos(alpha) + np.random.normal(0, 0.1)) bob_y.append(bob_y[k - 1] + np.sin(alpha) + np.random.normal(0, 0.1)) # Create the bobs vp = Plotter(title="Multiple Pendulum", axes=0, interactive=0, bg2='ly') vp += Box(pos=(0, -5, 0), length=12, width=12, height=0.7, c="k").wireframe(1) bob = [vp.add(Sphere(pos=(bob_x[0], bob_y[0], 0), r=R / 2, c="gray"))] for k in range(1, N + 1): c = Cylinder(pos=(bob_x[k], bob_y[k], 0), r=R, height=0.3, c=k) vp += c bob.append(c) # Create the springs out of N links link = [None] * N for k in range(N): p0 = bob[k].pos() p1 = bob[k + 1].pos() link[k] = Spring(p0, p1, thickness=0.015, r=R / 3, c="gray") vp += link[k] # Create some auxiliary variables x_dot_m = np.zeros(N+1)
"""Build a custom colormap, including out-of-range and NaN colors and labels""" from vedo import buildLUT, Sphere, show, settings settings.useDepthPeeling = True # might help with transparencies # generate a sphere and stretch it, so it sits between z=-2 and z=+2 mesh = Sphere(quads=True).scale([1, 1, 2]).lineWidth(0.1) # create some dummy data array to be associated to points data = mesh.points()[:, 2] # pick z-coords, use them as scalar data data[10:70] = float('nan') # make some values invalid by setting to NaN data[300:600] = 100 # send some values very far above-scale # build a custom LookUp Table of colors: # value, color, alpha lut = buildLUT( [ #(-2, 'pink' ), # up to -2 is pink (0.0, 'pink'), # up to 0 is pink (0.4, 'green', 0.5), # up to 0.4 is green with alpha=0.5 (0.7, 'darkblue'), #( 2, 'darkblue' ), ], vmin=-1.2, belowColor='lightblue', vmax=0.7, aboveColor='grey', nanColor='red', interpolate=False, )
def make_actor_label( atlas, actors, labels, size=300, color=None, radius=100, xoffset=0, yoffset=0, zoffset=0, ): """ Adds a 2D text ancored to a point on the actor's mesh to label what the actor is :param kwargs: key word arguments can be passed to determine text appearance and location: - size: int, text size. Default 300 - color: str, text color. A list of colors can be passed if None the actor's color is used. Default None. - xoffset, yoffset, zoffset: integers that shift the label position - radius: radius of sphere used to denote label anchor. Set to 0 or None to hide. """ # Check args if not isinstance(actors, (tuple, list)): actors = [actors] if not isinstance(labels, (tuple, list)): labels = [labels] if atlas.atlas_name == "ABA": offset = [-yoffset, -zoffset, xoffset] default_offset = np.array([0, -200, 100]) else: offset = [xoffset, yoffset, zoffset] default_offset = np.array([100, 0, -200]) new_actors = [] for n, (actor, label) in enumerate(zip(actors, labels)): if not isinstance(actor, Mesh): raise ValueError( f"Mesh must be an instance of Mesh, not {type(actor)}") if not isinstance(label, str): raise ValueError(f"Label must be a string, not {type(label)}") # Get label color if color is None: color = actor.c() elif isinstance(color, (list, tuple)): color = color[n] # Get mesh's highest point points = actor.points().copy() point = points[np.argmin(points[:, 1]), :] point += np.array(offset) + default_offset try: if atlas.hemisphere_from_coords(point, as_string=True) == "left": point = atlas.mirror_point_across_hemispheres(point) except IndexError: pass # Create label txt = Text(label, point, s=size, c=color) txt._original_actor = actor txt._label = label txt._kwargs = dict( size=size, color=color, radius=radius, xoffset=xoffset, yoffset=yoffset, zoffset=zoffset, ) new_actors.append(txt) # Mark a point on Mesh that corresponds to the label location if radius is not None: pt = actor.closestPoint(point) sphere = Sphere(pt, r=radius, c=color) sphere.ancor = pt new_actors.append(sphere) return new_actors
"""Simulation of an optical system with lenses and mirrors of arbitrary shapes and orientations (points mark the exit locations of photons, many from total internal reflections)""" from vedo import Grid, Sphere, Cube, Cone, Points, show from optics_base import Lens, Ray, Mirror, Screen # see file ./optics_base.py import numpy as np # Create meshes as ordinary vedo objects sm = Sphere(r=8).z(-8.1) sp = Sphere(r=8).z(+8.1) shape1 = Sphere(r=0.9, res=53).cutWithPlane().cap().rotateY(-90).pos(0, 0, 0.5) shape2 = Cube(side=2).triangulate().boolean('-', sm).boolean("-", sp).z(3) shape3 = Cone().rotateY(-90).z(6) shape4 = Cube().scale([1.7, 1, 0.2]).rotateY(70).pos(-0.3, 0, 8) shape5 = Sphere(r=2).boolean("intersect", Sphere(r=2).z(3.5)).rotateX(10).pos(0.8, 0, 7.5) shape6 = Grid(resx=1, resy=1).rotateY(-60).rotateX(30).pos(0, -1, 11) # Build lenses (with their refractive indices), and mirrors, using those meshes lens1 = Lens(shape1, ref_index=1.35).c("blue9") # constant refr. index lens2 = Lens(shape2, ref_index="glass").c("blue7") lens3 = Lens(shape3, ref_index="glass").c("green9") lens4 = Lens(shape4, ref_index="glass").c("purple9").lineWidth(1) lens5 = Lens(shape5, ref_index="glass").c("orange9") mirror = Mirror(shape6) screen = Screen(4, 4).rotateY(20).pos(1, 0, 12) elements = [lens1, lens2, lens3, lens4, lens5, mirror, screen] # Generate photons and trace them through the optical elements lines = [] source = Grid(resx=20, resy=20).points() # a numpy array for pt in source:
"""Non blocking interactive rendering window, python flow is not blocked but displayed objects cannot be accessed""" import time, os from multiprocessing import Process from vedo import Sphere, show, printc printc("..starting main", c='g') sphere = Sphere().alpha(0.1).lw(0.1) # ------ instead of (typical): #show(sphere, __doc__, axes=1) # ------ spawn an independent subprocess: def spawn(): show(sphere, __doc__, axes=1) Process(target=spawn).start() printc("..python flow is not blocked, wait 1 sec..", c='y') time.sleep(1) printc("..continuing in main", c='r') os._exit(0) # this exits immediately with no cleanup or buffer flushing
"""Click a sphere to highlight it""" from vedo import Text2D, Sphere, Plotter import numpy as np spheres = [] for i in range(25): p = np.random.rand(2) s = Sphere(r=0.05).pos(p).color('k5') s.name = f"sphere nr.{i} at {p}" spheres.append(s) def func(evt): if not evt.actor: return sil = evt.actor.silhouette().lineWidth(6).c('red5') msg.text("You clicked: "+evt.actor.name) plt.remove(silcont.pop()).add(sil) silcont.append(sil) silcont = [None] msg = Text2D("", pos="bottom-center", c='k', bg='r9', alpha=0.8) plt = Plotter(axes=1, bg='black') plt.addCallback('mouse click', func) plt.show(spheres, msg, __doc__, zoom=1.2)
ListPos.append(PossiblePos[n]) del PossiblePos[n] Pos = np.array(ListPos) # Create an array with all the radius and a list with all the masses Radius = np.concatenate((np.array([Rb]), np.array([Rs] * (Nsp - 1)))) Mass = [1.0] + [Ms] * (Nsp - 1) # Create the initial array of velocities at random with big sphere at rest ListVel = [(0.0, 0.0)] for s in range(1, Nsp): ListVel.append((Rb * random.uniform(-1, 1), Rb * random.uniform(-1, 1))) Vel = np.array(ListVel) # Create the spheres Spheres = [Sphere(pos=(Pos[0][0], Pos[0][1], 0), r=Radius[0], c="red")] for s in range(1, Nsp): a = Sphere(pos=(Pos[s][0], Pos[s][1], 0), r=Radius[s], c="blue") Spheres.append(a) # vp += a vp += Spheres vp += Grid(sx=screen_w, sy=screen_w) # Auxiliary variables Id = np.identity(Nsp) Dij = (Radius + Radius[:, np.newaxis])**2 # Matrix Dij=(Ri+Rj)**2 # The main loop pb = ProgressBar(0, 2000, c="r") for i in pb.range(): # Update all positions
"""Customizing Axes. Cartesian planes can be displaced from their lower-range default position""" from vedo import Sphere, Axes, precision, show, settings # settings.useDepthPeeling = True sph = Sphere().scale([4, 3, 2]).shift(5, 6, 7).c('green2', 0.1) axs = Axes( sph, # build axes for object sph xtitle="x axis", ytitle="y axis", ztitle="z axis", htitle='An ellipsoid at ' + precision(sph.centerOfMass(), 2), hTitleFont=1, hTitleColor='red3', zxGrid=True, xyFrameLine=2, yzFrameLine=2, zxFrameLine=2, xyFrameColor='red3', yzFrameColor='green3', zxFrameColor='blue3', xyShift=0.2, # move xy plane 20% along z yzShift=0.2, # move yz plane 20% along x zxShift=0.2, # move zx plane 20% along y ) show(sph, axs, __doc__).close()
# Create the initial positions and velocitites (0,0) of the bobs bob_x = [0] bob_y = [0] x_dot = np.zeros(N + 1) # velocities y_dot = np.zeros(N + 1) for k in range(1, N + 1): alpha = np.pi / 5 * k / 10 bob_x.append(bob_x[k - 1] + np.cos(alpha) + np.random.normal(0, 0.1)) bob_y.append(bob_y[k - 1] + np.sin(alpha) + np.random.normal(0, 0.1)) # Create the bobs vp = Plotter(title="Multiple Pendulum", axes=0, interactive=0, bg2='ly') vp += Box(pos=(0, -5, 0), length=12, width=12, height=0.7, c="k").wireframe(1) sph = Sphere(pos=(bob_x[0], bob_y[0], 0), r=R / 2, c="gray") vp += sph bob = [sph] for k in range(1, N + 1): c = Cylinder(pos=(bob_x[k], bob_y[k], 0), r=R, height=0.3, c=k) vp += c bob.append(c) # Create the springs out of N links link = [None] * N for k in range(N): p0 = bob[k].pos() p1 = bob[k + 1].pos() link[k] = Spring(p0, p1, thickness=0.015, r=R / 3, c="gray") vp += link[k]
"""Compute the (signed) distance of one mesh to another""" from vedo import Sphere, Cube, show s1 = Sphere().x(10) s2 = Cube(c='grey4').scale([2, 1, 1]).x(14) s1.distanceTo(s2, signed=False) s1.cmap('hot').addScalarBar('Signed\nDistance') # print(s1.pointdata["Distance"]) # numpy array show(s1, s2, __doc__, axes=1, size=(1000, 500), zoom=1.5).close()
plt += __doc__ plt += Torus(c="g", r=RingRadius, thickness=RingThickness, alpha=0.1).wireframe(1) ### <-- Atoms = [] poslist = [] plist, mlist, rlist = [], [], [] mass = Matom * Ratom ** 3 / Ratom ** 3 pavg = np.sqrt(2.0 * mass * 1.5 * k * T) # average kinetic energy p**2/(2mass) = (3/2)kT for i in range(Natoms): alpha = 2 * np.pi * random() x = RingRadius * np.cos(alpha) * 0.9 y = RingRadius * np.sin(alpha) * 0.9 z = 0 atm = Sphere(pos=(x, y, z), r=Ratom, c=i, res=6).phong() plt += atm Atoms = Atoms + [atm] ### <-- theta = np.pi * random() phi = 2 * np.pi * random() px = pavg * np.sin(theta) * np.cos(phi) py = pavg * np.sin(theta) * np.sin(phi) pz = pavg * np.cos(theta) poslist.append((x, y, z)) plist.append((px, py, pz)) mlist.append(mass) rlist.append(Ratom) pos = np.array(poslist) poscircle = pos p = np.array(plist)
""" Example usage of addTrail(). Add a trailing line to a moving object. """ print(__doc__) from vedo import Plotter, sin, Sphere, Point plt = Plotter(axes=6, interactive=False) s = Sphere().c("green").bc("tomato") s.cutWithPlane([-0.9, 0, 0]) # cut left part of sphere p = Point([1, 1, 1], r=12, c="black") # add a trail to point p with max length 0.5 and 50 segments p.addTrail(lw=3, maxlength=0.5, n=50) # add meshes to Plotter list plt += [s, p] for i in range(200): p.pos(-2 + i / 100.0, sin(i / 5.0) / 15, 0) plt.camera.Azimuth(-0.2) plt.show() if plt.escaped: break # if ESC is hit during the loop plt.close()
"""Computes the signed distance from one mesh to another. """ from vedo import Sphere, Cube, show s1 = Sphere() s2 = Cube(pos=[1, 0, 0], c='white', alpha=0.4) s1.distanceToMesh(s2, signed=True, negate=False) s1.addScalarBar(title='Signed\nDistance') #print(s1.getPointArray("Distance")) show(s1, s2, __doc__)
def plot( data, names=None, colors=None, lines=None, targets=None, arrows=None, text=None, boxes=None, points=None, interactive=True, ): """ A vedo wrapper for quicly visualizing well trajectories for QAQC purposes. Parameters ---------- data: a trimesh.Trimesh object or a list of trimesh.Trimesh objects or a trmiesh.scene object names: list of strings (default: None) A list of names, index aligned to the list of well meshes. colors: list of strings (default: None) A list of color or colors. If a single color is listed then this is applied to all meshes in data, otherwise the list of colors is indexed to the list of meshes. """ if isinstance(data, trimesh.scene.scene.Scene): meshes = [v for k, v in data.geometry.items()] if names is None: names = list(data.geometry.keys()) # handle a single mesh being passed elif isinstance(data, trimesh.Trimesh): meshes = [data] else: meshes = data if names is not None: assert len(names) == len(data), \ "Names must be length of meshes list else None" if colors is not None: if len(colors) == 1: colors = colors * len(names) else: assert len(colors) == len(names), \ "Colors must be length of meshes list, 1 else None" if points is not None: points = [Sphere(p, r=30, c='grey') for p in points] meshes_vedo = [] for i, mesh in enumerate(meshes): if i == 0: vertices = np.array(mesh.vertices) start_locations = np.array([mesh.vertices[0]]) else: vertices = np.concatenate((vertices, np.array(mesh.vertices)), axis=0) start_locations = np.concatenate( (start_locations, np.array([mesh.vertices[0]])), axis=0) # convert to vedo mesh m_vedo = trimesh2vedo(mesh) if colors is not None: m_vedo.c(colors[i]) if names is not None: m_vedo.flag(names[i]) meshes_vedo.append(m_vedo) w = get_bb(vertices) axes = get_axes(w.world) # try and figure out a nice start camera position pos = w.bb_center vec1 = pos - [w.length, w.width, 0] vec2 = np.array([vec1[1], vec1[0], 0]) pos_new = [pos[0], pos[1], -4000] + vec2 * 3 camera_opts = dict(pos=pos_new, focalPoint=pos, viewup=[0., 0., -1.]) show(meshes_vedo, w.world, lines, targets, arrows, boxes, axes, points, bg='lightgrey', bg2='lavender', camera=camera_opts, interactorStyle=10, resetcam=True, interactive=True, verbose=True, title=f'welleng {VERSION}')
"""Click a sphere to highlight it""" from vedo import Sphere, Plotter import numpy as np pts = np.random.rand(30, 2) * 20 spheres = [Sphere().pos(p).color('k5') for p in pts] def func(evt): if not evt.actor: return sil = evt.actor.silhouette().lineWidth(6).c('red5') plt.remove(silcont.pop()).add(sil) silcont.append(sil) silcont = [None] plt = Plotter(axes=1, bg='black') plt.addCallback('mouse click', func) plt.show(spheres, __doc__, zoom=1.2)