def showSolution3D(S, start, goal): from vedo import Text3D, Cube, Line, Grid, merge, show pts, cubes, txts = [], [], [] pts = [(x, -y) for y, x in S[0]] for y, line in enumerate(Z): for x, c in enumerate(line): if c: cubes.append(Cube([x, -y, 0])) path = Line(pts).lw(6).c('tomato') walls = merge(cubes).clean().flat().texture('wood1') sy, sx = S[1].shape gradient = np.flip(S[1], axis=0).ravel() grd = Grid(pos=((sx - 1) / 2, -(sy - 1) / 2, -0.49), sx=sx, sy=sy, resx=sx, resy=sy) grd.lw(0).wireframe(False).cmap('gist_earth_r', gradient, on='cells') grd.addScalarBar(title='Gradient', horizontal=True, c='k', nlabels=2) txts.append(__doc__) txts.append(Text3D('Start', pos=[start[1] - 1, -start[0] + 1.5, 1], c='k')) txts.append(Text3D('Goal!', pos=[goal[1] - 2, -goal[0] - 2.7, 1], c='k')) show(path, walls, grd, txts, axes=0, zoom=1.2)
def _parse_neuron_skeleton(self, neuron): """ Parses a neuron's skeleton information from skeleton .json file to create a vtk actor that represents the neuron :param neuron: str, neuron name """ try: # make this work if called by a Scene class cs = self.atlas except: cs = self try: data = cs.skeletons_data[neuron] except: print(f"No skeleton data found for {neuron}") return None # Create an actor for each neuron's branch and then merge actors = [] for branch in data["branches"]: coords = [data["coordinates"][str(p)] for p in branch] # Just like for synapses we need to adjust the coordinates to match the .obj files # coords are x z -y adjusted_coords = [(c[0], c[2], -c[1]) for c in coords] actors.append( Tube( adjusted_coords, r=cs.skeleton_radius, res=NEURON_RESOLUTION, )) return merge(*actors)
def _make_root(self, rootpath): """ Creates a root mesh by merging the mesh corresponding to each neuron, then saves it as an obj file at rootpath """ raise NotImplementedError( "Create root method not supported yet, sorry") print(f"Creating root mesh for atlas {self.atlas_name}") temp_scene = Scene( atlas=Celegans, add_root=False, display_inset=False, atlas_kwargs=dict(data_folder=self.data_folder), ) temp_scene.add_neurons(self.neurons_names) temp_scene.render(interactive=False) temp_scene.close() root = merge(*temp_scene.actors["neurons"]).clean().cap() # root = mesh2Volume(root, spacing=(0.02, 0.02, 0.02)).isosurface() points = Points(root.points()).smoothMLS2D(f=0.8).clean(tol=0.005) root = recoSurface(points, dims=100, radius=0.2) # Save write(root, rootpath) del temp_scene return root
def ruler(p1, p2, unit_scale=1, units=None, s=50): actors = [] # Make two line segments midpoint = np.array([(x + y) / 2 for x, y in zip(p1, p2)]) gap1 = ((midpoint - p1) * 0.8) + p1 gap2 = ((midpoint - p2) * 0.8) + p2 actors.append(Line(p1, gap1, lw=200)) actors.append(Line(gap2, p2, lw=200)) # Add label if units is None: units = "" dist = mag(p2 - p1) * unit_scale label = precision(dist, 3) + " " + units lbl = Text(label, pos=midpoint, s=s + 100, justify="center") lbl.SetOrientation([0, 0, 180]) actors.append(lbl) # Add spheres add end actors.append(Sphere(p1, r=s, c=[0.3, 0.3, 0.3])) actors.append(Sphere(p2, r=s, c=[0.3, 0.3, 0.3])) acts = merge(*actors).c((0.3, 0.3, 0.3)).alpha(1).lw(2) acts.name = "Ruler" acts.bg_class = "Ruler" return acts
def make_root_mesh(self): if self.structures is None: return obj_path = os.path.join(self.meshes_folder, "root.vtk") if os.path.isfile(obj_path): return # Get the mesh for each brain region to create root meshes = [ self._get_structure_mesh(reg) for reg in self.region_acronyms ] root = merge(meshes) write(root, obj_path)
def get_mesh(self): """ Returns the current mesh representation of the probe """ shaft = Cylinder(pos=[self.top, self.tip], c="k", r=self.radius, alpha=1) tip = Sphere(pos=self.tip, r=self.radius + 20, c="k") rois = Spheres([p.coordinates for p in self.points], r=self.radius + 30, c="r") mesh = merge(shaft, tip, rois).c(self.color) return mesh
def write_neuron_to_cache(self, neuron_name, neuron, _params): # Write params to file save_yaml(self.get_cache_params_filename(neuron_name), _params) # Write neurons to file file_names = self.get_cache_filenames(neuron_name) if isinstance(neuron, Mesh): write(neuron, [f for f in file_names if f.endswith("soma.obj")][0]) else: if not isinstance(neuron, dict): raise ValueError( f"Invalid neuron argument passed while caching: {neuron}") for key, actor in neuron.items(): if key == "whole_neuron": fname = [f for f in file_names if f.endswith(f"{key}.obj")] write(actor, fname[0]) else: # Get a single actor for each neuron component. # If there's no data for the component create an empty actor if not isinstance(actor, Mesh): if isinstance(actor, (list, tuple)): if len(actor) == 1: actor = actor[0] elif not actor or actor is None: actor = Mesh() else: try: actor = merge(actor) except: raise ValueError( f"{key} actor should be a mesh or a list of 1 mesh not {actor}" ) if actor is None: actor = Mesh() # Save to file fname = [f for f in file_names if f.endswith(f"{key}.obj")] if fname: write(actor, fname[0]) else: raise ValueError( f"No filename found for {key}. Filenames {file_names}" )
def _make_mesh(self, data): lines = [] if len(data["lines"]) == 1: try: lines_data = data["lines"][0] except KeyError: # pragma: no cover lines_data = data["lines"]["0"] # pragma: no cover else: lines_data = data["lines"] for line in lines_data: points = [[l["x"], l["y"], l["z"]] for l in line] lines.append(Tube( points, r=self.radius, res=8, )) return merge(*lines)
def __init__(self, mesh1, mesh2, n): ############################### init self.n = n # desired nr. of intermediate shapes self.mode = '2d' self.mesh1 = mesh1 self.mesh2 = mesh2 self.merged_meshes = merge(mesh1, mesh2) self.mesh1.lw(4).c('grey2').pickable(False) self.mesh2.lw(4).c('grey1').pickable(False) self.arrow_starts = [] self.arrow_stops = [] self.dottedln = None self.toggle = False self.instructions = ( "Click to add arrows interactively on the left panel\n" "right-click to remove last arrow. Then press:\n" "- m to morph the plane\n" "- c to clear\n" "- g to generate interpolation") self.msg1 = Text2D(self.instructions, pos='top-left', font="VictorMono", bg='g2', alpha=0.6) self.msg2 = Text2D('[output will show here]', pos='top-left', font="VictorMono") sz = self.merged_meshes.diagonalSize() self.plane1 = Grid(sx=sz, sy=sz, resx=50, resy=50).pos(self.merged_meshes.centerOfMass()) self.plane1.wireframe(False).alpha(1).lineWidth(0.1).c('white').lc( 'grey5') self.plane2 = self.plane1.clone().pickable(False) self.plotter = Plotter(N=2, bg='light blue', size=(2000, 1000)) self.plotter.addCallback('left click', self.onleftclick) self.plotter.addCallback('right click', self.onrightclick) self.plotter.addCallback('key press', self.onkeypress)
def ruler(p1, p2, unit_scale=1, units=None, s=50): """ Creates a ruler showing the distance between two points. The ruler is composed of a line between the points and a text indicating the distance. :param p1: list, np.ndarray with coordinates of first point :param p2: list, np.ndarray with coordinates of second point :param unit_scale: float. To scale the units (e.g. show mm instead of µm) :param units: str, name of unit (e.g. 'mm') :param s: float size of text """ actors = [] # Make two line segments midpoint = np.array([(x + y) / 2 for x, y in zip(p1, p2)]) gap1 = ((midpoint - p1) * 0.8) + p1 gap2 = ((midpoint - p2) * 0.8) + p2 actors.append(Line(p1, gap1, lw=200)) actors.append(Line(gap2, p2, lw=200)) # Add label if units is None: # pragma: no cover units = "" # pragma: no cover dist = mag(p2 - p1) * unit_scale label = precision(dist, 3) + " " + units lbl = Text(label, pos=midpoint, s=s + 100, justify="center") lbl.SetOrientation([0, 0, 180]) actors.append(lbl) # Add spheres add end actors.append(Sphere(p1, r=s, c=[0.3, 0.3, 0.3])) actors.append(Sphere(p2, r=s, c=[0.3, 0.3, 0.3])) act = Actor(merge(*actors), name="Ruler", br_class="Ruler") act.c((0.3, 0.3, 0.3)).alpha(1).lw(2) return act
def _make_mesh(self, data, show_injection=True): lines = [] if len(data["lines"]) == 1: try: lines_data = data["lines"][0] except KeyError: # pragma: no cover lines_data = data["lines"]["0"] # pragma: no cover else: lines_data = data["lines"] for line in lines_data: points = [[lin["x"], lin["y"], lin["z"]] for lin in line] lines.append( Tube( points, r=self.radius, res=8, ) ) if show_injection: coords = np.vstack( [ list(point.values()) for point in data.injection_sites.iloc[0] ] ) lines.append( Spheres( coords, r=self.radius * 10, res=8, ) ) return merge(*lines)
def get_neuron_actors_with_morphapi( swcfile=None, neuron=None, neurite_radius=None, use_cache=True, soma_radius=None, ): if swcfile is None and neuron is None: raise ValueError("No input passed") if swcfile is not None: neuron = Neuron(swc_file=swcfile) if neurite_radius is None: neurite_radius = DEFAULT_NEURITE_RADIUS if soma_radius is None: soma_radius = SOMA_RADIUS actors = neuron.create_mesh( neurite_radius=neurite_radius, use_cache=use_cache, soma_radius=soma_radius, ) if actors is None: raise ValueError(f"Failed to get neuron actors. {swcfile} - {neuron}") else: neurites, whole_neuron = actors actors = dict( soma=neurites["soma"], axon=neurites["axon"], dendrites=merge(neurites["basal_dendrites"], neurites["apical_dendrites"]), ) return actors, whole_neuron
sphere.addElevationScalars() cone.computeNormals() sphere.computeNormals() ###################################### test clone() c2 = cone.clone() print('clone()', cone.N(), c2.N()) assert cone.N() == c2.N() print('clone()', cone.NCells(), c2.NCells()) assert cone.NCells() == c2.NCells() ###################################### test merge() m = merge(sphere, cone) print('merge()', m.N(), cone.N() + sphere.N()) assert m.N() == cone.N() + sphere.N() print('merge()', m.NCells(), cone.NCells() + sphere.NCells()) assert m.NCells() == cone.NCells() + sphere.NCells() ###################################### inputdata print('inputdata', [cone.inputdata()], "vtk.vtkPolyData") assert isinstance(cone.inputdata(), vtk.vtkPolyData) ###################################### mapper print('mapper',[cone.mapper()], "vtk.vtkPolyDataMapper") assert isinstance(cone.mapper(), vtk.vtkPolyDataMapper)
def parse_streamline( *args, filepath=None, data=None, show_injection_site=True, color="ivory", alpha=0.8, radius=10, **kwargs, ): """ Given a path to a .json file with streamline data (or the data themselves), render the streamline as tubes actors. Either filepath or data should be passed :param filepath: str, optional. Path to .json file with streamline data (Default value = None) :param data: panadas.DataFrame, optional. DataFrame with streamline data. (Default value = None) :param color: str color of the streamlines (Default value = 'ivory') :param alpha: float transparency of the streamlines (Default value = .8) :param radius: int radius of the streamlines actor (Default value = 10) :param show_injection_site: bool, if True spheres are used to render the injection volume (Default value = True) :param *args: :param **kwargs: """ if filepath is not None and data is None: data = load_json(filepath) elif filepath is None and data is not None: pass else: raise ValueError( "Need to pass eiteher a filepath or data argument to parse_streamline" ) # create actors for streamlines lines = [] if len(data["lines"]) == 1: try: lines_data = data["lines"][0] except KeyError: lines_data = data["lines"]["0"] else: lines_data = data["lines"] for line in lines_data: points = [[l["x"], l["y"], l["z"]] for l in line] lines.append( shapes.Tube( points, r=radius, c=color, alpha=alpha, res=brainrender.STREAMLINES_RESOLUTION, )) coords = [] if show_injection_site: if len(data["injection_sites"]) == 1: try: injection_data = data["injection_sites"][0] except KeyError: injection_data = data["injection_sites"]["0"] else: injection_data = data["injection_sites"] for inj in injection_data: coords.append(list(inj.values())) spheres = [shapes.Spheres(coords, r=brainrender.INJECTION_VOLUME_SIZE)] else: spheres = [] merged = merge(*lines, *spheres) merged.color(color) merged.alpha(alpha) return [merged]
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) / 2000 sph1 = Sphere(pos, radius, alpha=0.4, res=12).flag(place + fl) if deaths > 5000: 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) / 2000, 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") show(Earth(), s1, merge(s2), vigs, tx, axes=11, bg2='lb', zoom=1.7, elevation=-70, size='fullscreen')
"""Thin Plate Spline transformations describe a nonlinear warp transform defined by a set of source and target landmarks. Any point on the mesh close to a source landmark will be moved to a place close to the corresponding target landmark. The points in between are interpolated using Bookstein's algorithm.""" from vedo import Grid, merge, Points, Arrows, show import numpy as np #np.random.seed(2) grids = [] for i in range(5): gr = Grid([0, 0, i / 8], resx=12, resy=12) grids.append(gr) mesh = merge(grids) # merge grids into a single object idxs = np.random.randint(0, mesh.N(), 10) # pick 10 indices pts = mesh.points()[idxs] ptsource, pttarget = [], [] for pt in pts: ptold = pt + np.random.randn(3) * 0.02 ptsource.append(ptold) ptnew = ptold + [0, 0, np.random.randn(1) * 0.1] # move in z pttarget.append(ptnew) warped = mesh.warp(ptsource, pttarget) warped.color("b4").lc('light blue').wireframe(False).lw(1) apts = Points(ptsource, r=10, c="r") arrs = Arrows(ptsource, pttarget, c='k')
def add_neurons( self, neurons, color=None, display_axon=True, display_dendrites=True, alpha=1, neurite_radius=None, ): """ Adds rendered morphological data of neurons reconstructions downloaded from the Mouse Light project at Janelia, neuromorpho.org and other sources. Accepts neurons argument as: - file(s) with morphological data - vedo mesh actor(s) of neurons reconstructions - dictionary or list of dictionary with actors for different neuron parts :param self: instance of brainrender Scene to use to render neurons :param neurons: str, list, dict. File(s) with neurons data or list of rendered neurons. :param display_axon, display_dendrites: if set to False the corresponding neurite is not rendered :param color: default None. Can be: - None: each neuron is colored according to the default color - color: rbg, hex etc. If a single color is passed all neurons will have that color - cmap: str with name of a colormap: neurons are colored based on their sequential order and cmap - dict: a dictionary specifying a color for soma, dendrites and axon actors, will be the same for all neurons - list: a list of length = number of neurons with either a single color for each neuron or a dictionary of colors for each neuron :param alpha: float in range 0,1. Neurons transparency :param neurite_radius: float > 0 , radius of tube actor representing neurites """ if not isinstance(neurons, (list, tuple)): neurons = [neurons] # ------------------------------ Prepare colors ------------------------------ # colors = self._add_neurons_get_colors(neurons, color) # ---------------------------------- Render ---------------------------------- # _neurons_actors = [] for neuron in neurons: neuron_actors = {"soma": None, "dendrites": None, "axon": None} # Deal with neuron as filepath if isinstance(neuron, str): if os.path.isfile(neuron): if neuron.endswith(".swc"): neuron_actors, _ = get_neuron_actors_with_morphapi( swcfile=neuron, neurite_radius=neurite_radius) else: raise NotImplementedError( "Currently we can only parse morphological reconstructions from swc files" ) else: raise ValueError( f"Passed neruon {neuron} is not a valid input. Maybe the file doesn't exist?" ) # Deal with neuron as single actor elif isinstance(neuron, Actor): # A single actor was passed, maybe it's the entire neuron neuron_actors["soma"] = neuron # store it as soma anyway pass # Deal with neuron as dictionary of actor elif isinstance(neuron, dict): neuron_actors["soma"] = neuron.pop("soma", None) neuron_actors["axon"] = neuron.pop("axon", None) # Get dendrites actors if ("apical_dendrites" in neuron.keys() or "basal_dendrites" in neuron.keys()): if "apical_dendrites" not in neuron.keys(): neuron_actors["dendrites"] = neuron["basal_dendrites"] elif "basal_dendrites" not in neuron.keys(): neuron_actors["dendrites"] = neuron["apical_dendrites"] else: neuron_actors["dendrites"] = merge( neuron["apical_dendrites"], neuron["basal_dendrites"], ) else: neuron_actors["dendrites"] = neuron.pop("dendrites", None) # Deal with neuron as instance of Neuron from morphapi elif isinstance(neuron, Neuron): neuron_actors, _ = get_neuron_actors_with_morphapi( neuron=neuron) # Deal with other inputs else: raise ValueError( f"Passed neuron {neuron} is not a valid input") # Check that we don't have anything weird in neuron_actors for key, act in neuron_actors.items(): if act is not None: if not isinstance(act, Actor): raise ValueError( f"Neuron actor {key} is {act.__type__} but should be a vedo Mesh. Not: {act}" ) if not display_axon: neuron_actors["axon"] = None if not display_dendrites: neuron_actors["dendrites"] = None _neurons_actors.append(neuron_actors) # Color actors for n, neuron in enumerate(_neurons_actors): if neuron["axon"] is not None: neuron["axon"].c(colors["axon"][n]) neuron["soma"].c(colors["soma"][n]) if neuron["dendrites"] is not None: neuron["dendrites"].c(colors["dendrites"][n]) # Add to actors storage self.actors.extend([list(n.values()) for n in _neurons_actors]) return return_list_smart(_neurons_actors)
# 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 > 10000: 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)/4000, 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") show(Earth(), s1, merge(s2), vigs, tx, axes=11, bg2='lb', zoom=1.7, elevation=-70, size='fullscreen')
def get_neurons( self, neurons, color=None, display_axon=True, display_dendrites=True, alpha=1, neurite_radius=None, soma_radius=None, use_cache=True, ): """ Gets rendered morphological data of neurons reconstructions Accepts neurons argument as: - file(s) with morphological data - vedo mesh actor(s) of entire neurons reconstructions - dictionary or list of dictionary with actors for different neuron parts :param neurons: str, list, dict. File(s) with neurons data or list of rendered neurons. :param display_axon, display_dendrites: if set to False the corresponding neurite is not rendered :param color: default None. Can be: - None: each neuron is given a random color - color: rbg, hex etc. If a single color is passed all neurons will have that color - cmap: str with name of a colormap: neurons are colored based on their sequential order and cmap - dict: a dictionary specifying a color for soma, dendrites and axon actors, will be the same for all neurons - list: a list of length = number of neurons with either a single color for each neuron or a dictionary of colors for each neuron :param alpha: float in range 0,1. Neurons transparency :param neurite_radius: float > 0 , radius of tube actor representing neurites :param use_cache: bool, if True a cache is used to avoid having to crate a neuron's mesh anew, otherwise a new mesh is created """ if not isinstance(neurons, (list, tuple)): neurons = [neurons] # ---------------------------------- Render ---------------------------------- # _neurons_actors = [] for neuron in neurons: neuron_actors = {"soma": None, "dendrites": None, "axon": None} # Deal with neuron as filepath if isinstance(neuron, str): if os.path.isfile(neuron): if neuron.endswith(".swc"): neuron_actors, _ = get_neuron_actors_with_morphapi( swcfile=neuron, neurite_radius=neurite_radius, soma_radius=soma_radius, use_cache=use_cache, ) else: raise NotImplementedError( "Currently we can only parse morphological reconstructions from swc files" ) else: raise ValueError( f"Passed neruon {neuron} is not a valid input. Maybe the file doesn't exist?" ) # Deal with neuron as single actor elif isinstance(neuron, Mesh): # A single actor was passed, maybe it's the entire neuron neuron_actors["soma"] = neuron # store it as soma pass # Deal with neuron as dictionary of actor elif isinstance(neuron, dict): neuron_actors["soma"] = neuron.pop("soma", None) neuron_actors["axon"] = neuron.pop("axon", None) # Get dendrites actors if ( "apical_dendrites" in neuron.keys() or "basal_dendrites" in neuron.keys() ): if "apical_dendrites" not in neuron.keys(): neuron_actors["dendrites"] = neuron["basal_dendrites"] elif "basal_dendrites" not in neuron.keys(): neuron_actors["dendrites"] = neuron["apical_dendrites"] else: neuron_actors["dendrites"] = merge( neuron["apical_dendrites"], neuron["basal_dendrites"], ) else: neuron_actors["dendrites"] = neuron.pop("dendrites", None) # Deal with neuron as instance of Neuron from morphapi elif isinstance(neuron, Neuron): neuron_actors, _ = get_neuron_actors_with_morphapi( neuron=neuron, neurite_radius=neurite_radius, use_cache=use_cache, ) # Deal with other inputs else: raise ValueError( f"Passed neuron {neuron} is not a valid input" ) # Check that we don't have anything weird in neuron_actors for key, act in neuron_actors.items(): if act is not None: if not isinstance(act, Mesh): raise ValueError( f"Neuron actor {key} is {type(act)} but should be a vedo Mesh. Not: {act}" ) if not display_axon: neuron_actors["axon"] = None if not display_dendrites: neuron_actors["dendrites"] = None _neurons_actors.append(neuron_actors) # Color actors colors = parse_neurons_colors(neurons, color) for n, neuron in enumerate(_neurons_actors): if neuron["axon"] is not None: neuron["axon"].c(colors["axon"][n]) neuron["axon"].name = "neuron-axon" if neuron["soma"] is not None: neuron["soma"].c(colors["soma"][n]) neuron["soma"].name = "neuron-soma" if neuron["dendrites"] is not None: neuron["dendrites"].c(colors["dendrites"][n]) neuron["dendrites"].name = "neuron-dendrites" # Return return return_list_smart(_neurons_actors), None
"""Elliptic Fourier Descriptors parametrizing a closed countour (in red)""" import vedo, pyefd shapes = vedo.load(vedo.dataurl+'timecourse1d.npy') sh = shapes[55] sr = vedo.Line(sh).mirror('x').reverse() sm = vedo.merge(sh, sr).c('red5').lw(3) pts = sm.points()[:,(0,1)] rlines = [] for order in range(5,30, 5): coeffs = pyefd.elliptic_fourier_descriptors(pts, order=order, normalize=False) a0, c0 = pyefd.calculate_dc_coefficients(pts) rpts = pyefd.reconstruct_contour(coeffs, locus=(a0,c0), num_points=400) color = vedo.colorMap(order, "Blues", 5,30) rline = vedo.Line(rpts).lw(3).c(color) rlines.append(rline) sm.z(0.1) # move it on top so it's visible vedo.show(sm, *rlines, __doc__, axes=1, bg='k', size=(1190, 630), zoom=1.8)
(2) `assembly.Assembly` - combines meshes (or other actors); preserves properties (3) `+` - equivalent to `Assembly` ''' import vedo import numpy as np # Define vertices and faces verts = np.array([(0, 0, 0), (10, 0, 0), (0, 10, 0), (0, 0, 10)]) faces = np.array([(0, 1, 2), (2, 1, 3), (1, 0, 3), (0, 2, 3)]) # Create a tetrahedron and a copy mesh = vedo.Mesh([verts, faces], c='red') mesh2 = mesh.clone().x(15).y(15).c('blue') # Create a copy, shift it; change color # Merge: creates a new mesh, color of the second mesh is lost mesh_all = vedo.merge(mesh, mesh2) print('1. Type:', type(mesh_all)) # Show plotter = vedo.show(mesh_all, viewup='z', axes=1) # -> all red plotter.close() # Assembly: groups meshes mesh_all = vedo.assembly.Assembly(mesh, mesh2) print('2. Type:', type(mesh_all)) # Show plotter = vedo.show(mesh_all, viewup='z', axes=1) # -> red and blue plotter.close() # Equivalently, "+" also creates an Assembly mesh_all = mesh + mesh2 print('3. Type:', type(mesh_all))
"""The butterfly effect with cylindrical mirrors and a laser""" # Original idea from "The Action Lab": https://www.youtube.com/watch?v=kBow0kTVn3s # from vedo import Plotter, Grid, Cylinder, merge from optics_base import Ray, Mirror, Detector # see file ./optics_base.py grid = Grid(resx=3, resy=4) # pick a few points in space to place cylinders pts = grid.points().tolist() + grid.cellCenters().tolist() # Create the mirror by merging many (y-scaled) cylinders into a single mesh object cyls = [ Cylinder(p, r=0.065, height=0.2, res=720).scale([1, 1.5, 1]) for p in pts ] mirror = Mirror(merge(cyls)).color("silver") # Create a detector surface as a thin cylinder surrounding the mirror sd = Cylinder(r=1, height=0.3, cap=False).cutWithPlane([0, -0.95, 0], normal='y') detector = Detector(sd) def slider(widget, event): ### callback to shift the beam along x dx = widget.GetRepresentation().GetValue() ray = Ray([dx, -1.2, -0.1], direction=(0, 1, 0.02)) ray.maxiterations = 1000 # max nr. of reflections ray.trace([mirror, detector]) # cumpute trajectory detector.count().cmap("Reds", on='cells', vmax=10) line = ray.asLine().lineWidth(4).c('green5') if plt.actors[-1].name == "Line": plt.pop() # remove the last Line plt.add(line) # add the new one
y += amp * np.sin(freq * time + phase + rotation) path.append([x, y]) if len(points): hline = vedo.Line([x, y], points[-1], c='red5', lw=0.1) pline = vedo.Line(path, c='green5', lw=2) oline = vedo.Line(points, c='red4', lw=5) objs += [hline, pline, oline] plt.add(objs, resetcam=False) return [x, y] # Load some 2D shape and make it symmetric shape = vedo.load(vedo.dataurl + 'timecourse1d.npy')[55] shaper = vedo.Line(shape).mirror('x').reverse() shape = vedo.merge(shape, shaper) x, y, _ = shape.points().T # Compute Fourier Discrete Transform in x and y separately: fourierX = DFT(x) fourierY = DFT(y) vedo.settings.defaultFont = 'Glasgo' plt = vedo.Plotter(size=(1500, 750), bg='black', axes=1, interactive=False) txt = vedo.Text2D(f"{__doc__} (order={order})", c='red9', bg='white', pos='bottom-center') plt.show(shape, txt, mode='image', zoom=1.9) objs, points = [], []
def create_mesh(self, neurite_radius=2, soma_radius=4, use_cache=True, **kwargs): if self.points is None: print("No data loaded, returning") return # Parse kwargs ( soma_color, apical_dendrites_color, basal_dendrites_color, axon_color, whole_neuron_color, kwargs, ) = self._parse_mesh_kwargs(**kwargs) if (not isinstance(neurite_radius, (int, float)) or not neurite_radius > 0): raise ValueError( f"Invalid value for parameter neurite_radius, should be a float > 0" ) if not isinstance(soma_radius, (int, float)) or not soma_radius > 0: raise ValueError( f"Invalid value for parameter soma_radius, should be a float > 0" ) # prepare params dict for caching _params = dict(neurite_radius=neurite_radius, soma_radius=soma_radius) # Check if cached files already exist if use_cache: neurites = self.load_cached_neuron(self.neuron_name, _params) else: neurites = None # Render if neurites is not None: whole_neuron = neurites.pop("whole_neuron") neurites["soma"].c(soma_color) else: # Create soma actor neurites = {} if not self.invert_dims: coords = self.points["soma"].coords else: coords = self.points["soma"].coords z, y, x = coords[0], coords[1], coords[2] coords = np.hstack([x, y, z]).T soma = Sphere( pos=coords, r=self.points["soma"].radius * soma_radius, c=soma_color, ).computeNormals() neurites["soma"] = soma.clone().c(soma_color) # Create neurites actors for ntype in self._neurite_types: actors = [] for neurite in self.points[ntype]: for section in iter_sections(neurite.component): for child in section.children: if not child.children: coords = child.points[:, COLS.XYZ] if self.invert_dims: z, y, x = ( coords[:, 0], coords[:, 1], coords[:, 2], ) coords = np.hstack([x, y, z]).T actors.append(Tube(coords, r=neurite_radius)) else: for grandchild in child.children: coords = grandchild.points[:, COLS.XYZ] if self.invert_dims: z, y, x = ( coords[:, 0], coords[:, 1], coords[:, 2], ) coords = np.vstack([x, y, z]).T actors.append( Tube(coords, r=neurite_radius)) if actors: neurites[ntype] = merge( actors).computeNormals() # .smoothMLS2D(f=0.1) else: neurites[ntype] = None # Merge actors to get the entire neuron actors = [ act.clone() for act in neurites.values() if act is not None ] whole_neuron = merge(actors).clean().computeNormals() # Write to cache to_write = neurites.copy() to_write["whole_neuron"] = whole_neuron self.write_neuron_to_cache(self.neuron_name, to_write, _params) # Color actors colors = [basal_dendrites_color, apical_dendrites_color, axon_color] for n, key in enumerate( ["basal_dendrites", "apical_dendrites", "axon"]): if neurites[key] is not None: neurites[key] = neurites[key].c(colors[n]) whole_neuron.c(whole_neuron_color) return neurites, whole_neuron