def __init__( self, griddata, voxel_size=1, cmap="bwr", min_quantile=None, min_value=None, name=None, br_class=None, as_surface=True, **volume_kwargs, ): """ Takes a 3d numpy array with volumetric data and returns an Actor with mesh: vedo.Volume.isosurface or a vedo.Volume. BY default the volume is represented as a surface To extract the surface: The isosurface needs a lower bound threshold, this can be either a user defined hard value (min_value) or the value corresponding to some percentile of the grid data. :param griddata: np.ndarray, 3d array with grid data :param voxel_size: int, size of each voxel in microns :param min_quantile: float, percentile for threshold :param min_value: float, value for threshold :param cmap: str, name of colormap to use :param as_surface, bool. default True. If True a surface mesh is returned instead of the whole volume :param volume_kwargs: keyword arguments for vedo's Volume class """ # Create mesh color = volume_kwargs.pop("c", "viridis") if isinstance(griddata, np.ndarray): # create volume from data mesh = VedoVolume( griddata, spacing=[voxel_size, voxel_size, voxel_size], c=color, **volume_kwargs, ) else: mesh = griddata # assume a vedo Volume was passed if as_surface: # Get threshold if min_quantile is None and min_value is None: th = 0 elif min_value is not None: th = min_value else: th = np.percentile(griddata.ravel(), min_quantile) mesh = mesh.legosurface(vmin=th, cmap=cmap) Actor.__init__(self, mesh, name=name or "Volume", br_class=br_class or "Volume")
def griddata_to_volume(self, griddata, min_quantile=None, min_value=None, **kwargs): """ Takes a 3d numpy array with volumetric gene expression and returns a vedo.Volume.isosurface actor. The isosurface needs a lower bound threshold, this can be either a user defined hard value (min_value) or the value corresponding to some percentile of the gene expression data. :param griddata: np.ndarray, 3d array with gene expression data :param min_quantile: float, percentile for threshold :param min_value: float, value for threshold """ # Check inputs if not isinstance(griddata, np.ndarray): raise ValueError("Griddata should be a numpy array") if not len(griddata.shape) == 3: raise ValueError("Griddata should be a 3d array") # Get threshold if min_quantile is None and min_value is None: th = 0 elif min_value is not None: if not isinstance(min_value, (int, float)): raise ValueError("min_values should be a float") th = min_value else: if not isinstance(min_quantile, (float, int)): raise ValueError( "min_values should be a float in range [0, 1]") if 0 > min_quantile or 100 < min_quantile: raise ValueError( "min_values should be a float in range [0, 100]") th = np.percentile(griddata.ravel(), min_quantile) # Create mesh cmap = kwargs.pop("cmap", None) actor = Volume( griddata, spacing=[self.voxel_size, self.voxel_size, self.voxel_size], ) actor = actor.legosurface(vmin=th, cmap=cmap) return actor
def plot_err_field_vedo(X, Y, Z, scalar_field, fig_name): isomin = 1. * scalar_field.min() isomax = 1. * scalar_field.max() # isomin = 10 # isomax = 11 vol = Volume(scalar_field) # vol.addScalarBar3D() vol.addScalarBar3D(sy=1.5, title='height is the scalar') # generate an isosurface the volume for each thresholds ts = np.linspace(isomin, isomax, 6) # ts = [10.1, 10.25, 10.4] # Use c=None to use the default vtk color map. isos is of type Mesh isos = Volume(scalar_field).isosurface(threshold=ts).opacity(0.4) text1 = Text2D(f'Make a Volume from numpy.mgrid', c='blue') text2 = Text2D(f'its isosurface representation\nvmin={isomin:.2e}, vmax={isomax:.2e}', c='dr') print('numpy array from Volume:', vol.getPointArray().shape, vol.getDataArray().shape) # show([(vol, text1), (isos, text2)], N=2, azimuth=10, zoom=1.3) destination_path = os.path.join(plot_dir, fig_name) write(vol, destination_path) print(f'zapisano w: {destination_path}')
r = np.sqrt(x * x + y * y + z * z + 2 * t * t) + 0.1 return np.sin(9 * np.pi * r) / r n = 64 qn = 50 vol = np.zeros((n, n, n)) n1 = int(n / 2) pb = ProgressBar(0, qn, c="r") for q in pb.range(): pb.print() t = 2 * q / qn - 1 for k in range(n1): z = 2 * k / n1 - 1 for j in range(n1): y = 2 * j / n1 - 1 for i in range(n1): x = 2 * i / n1 - 1 vol[i, j, k] = f(x, y, z, t) volf = fftn(vol) volf = fftshift(abs(volf)) volf = np.log(12 * volf / volf.max() + 1) / 2.5 vb = Volume(volf).mode(1).c("rainbow").alpha([0, 0.8, 1]) plt = show(vb, bg="black", axes=1, viewup='z', interactive=False) if plt.escaped: break # ESC button was hit interactive().close()
"""Interactively cut a set of isosurfaces from a volumetric dataset""" from vedo import dataurl, show, Volume # generate an isosurface the volume for each thresholds thresholds = [0.1, 0.25, 0.4, 0.6, 0.75, 0.9] # isos is of type Mesh isos = Volume(dataurl + 'quadric.vti').isosurface(thresholds) show(isos, __doc__, axes=1, interactive=False).addCutterTool(isos)
"""Histogram (or plot) in 3D. The size of each cube is proportional to the value at that point""" import numpy as np from vedo import Volume, Cube, Glyph, show # Make up some arbitrary data X, Y, Z = np.mgrid[:4, :8, :8] counts = 50 - ( (X-4)**2 + (Y-4)**2 + (Z-4)**2 ) # This is now a point cloud with an associated array of counts pcloud = Volume(counts).topoints() marker = Cube().scale(0.015) glyphed_pcl = Glyph(pcloud, marker, scaleByScalar=True) glyphed_pcl.cmap('seismic').addScalarBar('counts') show(glyphed_pcl, __doc__, axes=1)
"""Create a Volume from a numpy array""" import numpy as np data_matrix = np.zeros([75, 75, 75], dtype=np.uint8) # all voxels have value zero except: data_matrix[0:35, 0:35, 0:35] = 1 data_matrix[35:55, 35:55, 35:55] = 2 data_matrix[55:74, 55:74, 55:74] = 3 from vedo import Volume, show vol = Volume(data_matrix, c=['white', 'b', 'g', 'r']) vol.addScalarBar3D() show(vol, __doc__, axes=1)
"""Load and render a 3D Volume mode=0, composite rendering mode=1, maximum-projection rendering""" from vedo import dataurl, Volume, show vol1 = Volume(dataurl + "vase.vti") # can set colors and transparencies along the scalar range # from minimum to maximum value. In this example voxels with # the smallest value will be completely transparent (and white) # while voxels with highest value of the scalar will get alpha=0.8 # and color will be=(0,0,1) vol1.color(["white", "fuchsia", "dg", (0, 0, 1)]) #vol1.color('jet') # a matplotlib colormap name is also accepted vol1.alpha([0.0, 0.2, 0.3, 0.8]) # a transparency for the GRADIENT of the scalar can also be set: # in this case when the scalar is ~constant the gradient is ~zero # and the voxel are made transparent: vol1.alphaGradient([0.0, 0.5, 0.9]).addScalarBar3D(title='composite shade', c='k') vol1.scalarbar.scale(0.8).x(20) # mode = 1 is maximum-projection volume rendering vol2 = Volume(dataurl + "vase.vti").mode(1).shift(60, 0, 0) vol2.addScalarBar3D(title='maximum-projection', c='k') vol2.scalarbar.scale(0.8).x(160) # show command creates and returns an instance of class Plotter show(vol1, vol2, __doc__, size=(800, 600), zoom=1.5).close()
###################################### print('unpack', len(asse.unpack()), 2) assert len(asse.unpack()) == 2 print('unpack', asse.unpack(0).name) assert asse.unpack(0) == cone print('unpack', asse.unpack(1).name) assert asse.unpack(1) == sphere print('unpack', asse.diagonalSize(), 4.15) assert 4.1 < asse.diagonalSize() < 4.2 ############################################################################ Volume X, Y, Z = np.mgrid[:30, :30, :30] scalar_field = ((X - 15)**2 + (Y - 15)**2 + (Z - 15)**2) / 225 print('Test Volume, scalar min, max =', np.min(scalar_field), np.max(scalar_field)) vol = Volume(scalar_field) volarr = vol.pointdata[0] print('Volume', volarr.shape[0], 27000) assert volarr.shape[0] == 27000 print('Volume', np.max(volarr), 3) assert np.max(volarr) == 3 print('Volume', np.min(volarr), 0) assert np.min(volarr) == 0 ###################################### isosurface iso = vol.isosurface(threshold=1.0) print('isosurface', iso.area()) assert 2540 < iso.area() < 3000
from vedo import settings, Volume, Text, show, datadir settings.fontIsMono = False settings.fontLSpacing = 0.2 settings.fontHSpacing = 0.5 vol = Volume(datadir + "embryo.slc") vol.mode(1).c('b2') # vol.mode(1).c(['dr','dr','dr','dr', 'dg', 'dg', 'db', 'db', 'db']) # vol.mode(0).c('b2') t = Text("Sharpe\n~~~Lab", s=40, font="./Spears.npz", vspacing=1.4, depth=.04) t.c('k1').rotateX(90).pos(200, 150, 70) cam = dict(pos=(363, -247, 121), focalPoint=(240, 137, 116), viewup=(4.45e-3, 0.0135, 1.00), distance=403, clippingRange=(36.0, 874)) show( vol, t, size=(700, 400), camera=cam, # elevation=-89, zoom=2, )
# 1. load the data print("Loading data") data = imio.load.load_any(datafile) # 2. aligned the data to the scene's atlas' axes print("Transforming data") scene = Scene(atlas_name="mpin_zfish_1um") source_space = AnatomicalSpace( "ira" ) # for more info: https://docs.brainglobe.info/bg-space/usage target_space = scene.atlas.space transformed_stack = source_space.map_stack_to(target_space, data) # 3. create a Volume vedo actor and smooth print("Creating volume") vol = Volume(transformed_stack, origin=scene.root.origin()).medianSmooth() # 4. Extract a surface mesh from the volume actor print("Extracting surface") SHIFT = [-20, 15, 30] # fine tune mesh position mesh = ( vol.isosurface(threshold=20).c(blue_grey).decimate().clean().addPos(*SHIFT) ) # 5. render print("Rendering") scene.add(mesh) scene.render(zoom=13)
"""Share the same color and trasparency mapping across different volumes""" from vedo import Volume, Line, show import numpy as np arr = np.zeros(shape=(50, 50, 50)) for i in range(50): for j in range(50): for k in range(50): arr[i, j, k] = j vol1 = Volume(arr).mode(1).cmap('jet', alpha=[0, 1], vmin=0, vmax=80).addScalarBar("vol1") vol2 = Volume(arr + 30).mode(1).cmap('jet', alpha=[0, 1], vmin=0, vmax=80).addScalarBar("vol2") # or equivalently, to set transparency: # vol1.alpha([0,1], vmin=0, vmax=70) # can also manually build a scalarbar object to span the whole range: sb = Line([50, 0, 0], [50, 50, 0]).cmap('jet', [0, 70]).addScalarBar3D("vol2", c='black').scalarbar show([(vol1, __doc__), (vol2, sb)], N=2, axes=1)
from vedo import dataurl, Volume from vedo.applications import IsosurfaceBrowser vol = Volume(dataurl+'head.vti') plt = IsosurfaceBrowser(vol, c='gold') # Plotter instance plt.show(axes=7, bg2='lb').close()
def add_volume(self, volume, cmap="afmhot_r", alpha=1, add_colorbar=True, **kwargs): """ Renders intensitdata from a 3D numpy array as a lego volumetric actor. :param volume: np 3D array with number of dimensions = those of the 100um reference space. :param cmap: str with name of colormap to use :param alpha: float, transparency :param add_colorbar: if True a colorbar is added to show the values of the colormap """ # Parse kwargs line_width = kwargs.pop("line_width", 1) if cmap == "random" or not cmap or cmap is None: cmap = get_random_colormap() # Get vmin and vmax threshold for visualisation vmin = kwargs.pop("vmin", 0.000001) vmax = kwargs.pop("vmax", np.nanmax(volume)) # Check values if np.max(volume) > vmax: print( "While rendering mapped projection some of the values are above the vmax threshold." + "They will not be displayed." + f" vmax was {vmax} but found value {round(np.max(volume), 5)}." ) if vmin > vmax: raise ValueError( f"The vmin threhsold [{vmin}] cannot be larger than the vmax threshold [{vmax}" ) if vmin < 0: vmin = 0 # Get 'lego' actor vol = Volume(volume) lego = vol.legosurface(vmin=vmin, vmax=vmax, cmap=cmap) # Scale and color actor lego.alpha(alpha).lw(line_width).scale(self.voxel_size) lego.cmap = cmap # Add colorbar if add_colorbar: lego.addScalarBar( vmin=vmin, vmax=vmax, horizontal=1, c="k", pos=(0.05, 0.05), titleFontSize=40, ) # Add to scene actor = self.scene.add_actor(lego) return actor
"""A Volume can have multiple scalars associated to each voxel""" from vedo import dataurl, Volume, printc, show import numpy as np vol = Volume(dataurl + 'vase.vti') nx, ny, nz = vol.dimensions() r0, r1 = vol.scalarRange() vol.addScalarBar3D(title='original voxel scalars') # create a set of scalars and add it to the Volume vol.pointdata["myscalars1"] = np.linspace(r0, r1, num=nx * ny * nz) # create another set of scalars and add it to the Volume vol.pointdata["myscalars2"] = np.random.randint(-100, +100, nx * ny * nz) # make SLCImage scalars the active array (can set 0, to pick the first): printc('Arrays in Volume are:\n', vol.pointdata.keys(), invert=True) vol.pointdata.select( "SLCImage") # select the first data array as the active one # Build the isosurface of the active scalars, # but use testscals1 to colorize this isosurface, and then smooth it iso1 = vol.isosurface().cmap('jet', 'myscalars1').smooth().lw(0.1) iso1.addScalarBar3D(title='myscalars1') iso2 = vol.isosurface().cmap('viridis', 'myscalars2') iso2.addScalarBar3D(title='myscalars2') show([ (vol, __doc__),
from vedo import datadir, Volume from vedo.applications import IsosurfaceBrowser vol = Volume(datadir + 'head.vti') plt = IsosurfaceBrowser(vol, c='gold') # Plotter instance plt.show(axes=7, bg2='lb')
import numpy as np from vedo import dataurl, Volume, Axes, show from vedo.pyplot import histogram, plot cmap = 'nipy_spectral' alpha = np.array([0, 0, 0.05, 0.2, 0.8, 1]) vol = Volume(dataurl + "embryo.slc") vol.cmap(cmap).alpha(alpha).addScalarBar3D(c='w') xvals = np.linspace(*vol.scalarRange(), len(alpha)) p = histogram(vol, logscale=True, c=cmap, bc='white') p += plot(xvals, alpha * p.ybounds()[1], '--ow').z(1) show( [(vol, Axes(vol, c='w'), f"Original Volume\ncolor map: {cmap}"), (p, "Voxel scalar histogram\nand opacity transfer function")], N=2, sharecam=False, bg=(82, 87, 110), )
from vedo import Volume, Text3D, show, dataurl vol = Volume(dataurl+"embryo.slc").mode(0).c('b2').alphaUnit(5) t = Text3D("Sharpe\n~~~Lab", s=40, font="Spears", vspacing=1.4, depth=.04) t.c('k1').rotateX(90).pos(200,150,70) cam = dict(pos=(363, -247, 121), focalPoint=(240, 137, 116), viewup=(4.45e-3, 0.0135, 1.00), distance=403) show(vol, t, size=(700,400), camera=cam)
"""Custom color and transparency maps for Volumes""" from vedo import Volume, dataurl, show from vedo.pyplot import CornerHistogram # Build a Volume object. # A set of color/transparency values - of any length - can be passed # to define the transfer function in the range of the scalar. # E.g.: setting alpha=[0, 0, 0, 1, 0, 0, 0] would make visible # only voxels with value close to center of the range (see histogram). vol = Volume(dataurl + 'embryo.slc') vol.color([ (0, "green"), (49, "green"), (50, "blue"), (109, "blue"), (110, "red"), (180, "red"), ]) # vol.mode('max-projection') vol.alpha([0., 1.]) vol.alphaUnit(8) # absorption unit, higher factors = higher transparency vol.addScalarBar3D(title='color~\dot~alpha transfer function', c='k') ch = CornerHistogram(vol, logscale=True, pos='bottom-left') # show both Volume and Mesh show(vol, ch, __doc__, axes=1, zoom=1.2).close()
"""Modify a Volume dataset and colorize voxels individually """ from vedo import Volume, show import numpy as np vol = Volume(dims=(10,11,12), mode=0) vol.alpha(0.8).jittering(False) vol.interpolation(0) # nearest neighbour interpolation type # Overwrite the (sofar empty) voxel data with new data vol.imagedata().AllocateScalars(3, 4) # type 3 corresponds to np.uint8 arr = vol.getPointArray() arr[:] = np.random.randint(0,255, (10*11*12,4)).astype(np.uint8) # For 4 component data, the first 3 directly represent RGB, no lookup table. # (see https://vtk.org/doc/nightly/html/classvtkVolumeProperty.html): vol.GetProperty().IndependentComponentsOff() show(vol, __doc__, axes=1)
"""Generate the isosurfaces corresponding to a set of thresholds. (These surfaces are not separate meshes). """ from vtk import vtkQuadric, vtkSampleFunction # Quadric definition. This is a type of implicit function. quadric = vtkQuadric() quadric.SetCoefficients(0.5, 1, 0.2, 0, 0.1, 0, 0, 0.2, 0, 0) # the vtkSampleFunction evaluates quadric over a volume sample = vtkSampleFunction() sample.SetSampleDimensions(40, 40, 40) sample.SetImplicitFunction(quadric) sample.Update() img = sample.GetOutput() # vtkImageData print("Scalar Range", img.GetScalarRange(), "\ntry press shift-x.") ######################## from vedo import show, Volume # generate an isosurface the volume for each thresholds ts = [0.1, 0.25, 0.4, 0.6, 0.75, 0.9] # Use c=None to use the default vtk color map. isos is of type Mesh isos = Volume(img).isosurface(threshold=ts) show(isos, __doc__)
from vedo import Volume, dataurl from vedo.applications import RayCastPlotter embryo = Volume(dataurl+"embryo.slc").mode(1).c('jet') # change properties plt = RayCastPlotter(embryo) # Plotter instance plt.show(viewup="z", bg='black', bg2='blackboard', axes=7).close()
"""Embed a 3D scene in a webpage with x3d""" from vedo import dataurl, Plotter, Volume, Text3D plt = Plotter(size=(800, 600), bg='GhostWhite') embryo = Volume(dataurl + 'embryo.tif').isosurface().decimate(0.5) coords = embryo.points() embryo.cmap('PRGn', coords[:, 1]) # add dummy colors along y txt = Text3D(__doc__, font='Bongas', s=350, c='red2', depth=0.05) txt.pos(2500, 300, 500) plt.show(embryo, txt, txt.box(pad=250), axes=1, viewup='z', zoom=1.2) # This exports the scene and generates 2 files: # embryo.x3d and an example embryo.html to inspect in the browser plt.export('embryo.x3d', binary=False) print("Type: \n firefox embryo.html")
print('unpack',len(asse.unpack()) , 2) assert len(asse.unpack()) ==2 print('unpack', asse.unpack(0).name) assert asse.unpack(0) == cone print('unpack',asse.unpack(1).name) assert asse.unpack(1) == sphere print('unpack',asse.diagonalSize(), 4.15) assert 4.1 < asse.diagonalSize() < 4.2 ############################################################################ Volume X, Y, Z = np.mgrid[:30, :30, :30] scalar_field = ((X-15)**2 + (Y-15)**2 + (Z-15)**2)/225 print('Test Volume, scalar min, max =', np.min(scalar_field), np.max(scalar_field)) vol = Volume(scalar_field) volarr = vol.getPointArray() print('Volume',volarr.shape[0] , 27000) assert volarr.shape[0] == 27000 print('Volume',np.max(volarr) , 3) assert np.max(volarr) == 3 print('Volume',np.min(volarr) , 0) assert np.min(volarr) == 0 ###################################### isosurface iso = vol.isosurface(threshold=1.0) print('isosurface', iso.area()) assert 2540 < iso.area() < 3000
"""Use sliders to slice volume Click button to change colormap""" from vedo import dataurl, Volume, show, Text2D from vedo.applications import SlicerPlotter filename = dataurl + 'embryo.slc' #filename = dataurl+'embryo.tif' #filename = dataurl+'vase.vti' vol = Volume(filename) #.print() plt = SlicerPlotter( vol, bg='white', bg2='lightblue', cmaps=("gist_ncar_r", "jet", "Spectral_r", "hot_r", "bone_r"), useSlider3D=False, ) #Can now add any other object to the Plotter scene: #plt += Text2D('some message', font='arial') plt.show().close()