def ipv_plot_molecule(molecule): for atom_symbol in atom_symbols: atoms = [atom for atom in molecule.atoms if atom.symbol == atom_symbol] if len(atoms) == 0: continue x = np.array([atom.position[0] for atom in atoms]) y = np.array([atom.position[1] for atom in atoms]) z = np.array([atom.position[2] for atom in atoms]) p3.scatter(x=x, y=y, z=z, color=atom_color[atom_symbol], size=atom_size[atom_symbol], marker='sphere') for bond in molecule.bonds: p1 = bond.atom1.position p2 = bond.atom2.position p3.plot(x=np.array([p1[0], p2[0]]), y=np.array([p1[1], p2[1]]), z=np.array([p1[2], p2[2]]), color='black') p3.show()
def ball(rmax=3, rmin=0, shape=128, limits=[-4, 4], draw=True, show=True, **kwargs): """Show a ball.""" import ipyvolume.pylab as p3 __, __, __, r, _theta, _phi = xyz(shape=shape, limits=limits, spherical=True) data = r * 0 data[(r < rmax) & (r >= rmin)] = 0.5 if "data_min" not in kwargs: kwargs["data_min"] = 0 if "data_max" not in kwargs: kwargs["data_max"] = 1 data = data.T if draw: vol = p3.volshow(data=data, **kwargs) if show: p3.show() return vol else: return data
def klein_bottle(draw=True, show=True, figure8=False, endpoint=True): # http://paulbourke.net/geometry/klein/ u = np.linspace(0, 2 * pi, num=40, endpoint=endpoint) v = np.linspace(0, 2 * pi, num=40, endpoint=endpoint) u, v = np.meshgrid(u, v) if figure8: #u -= np.pi #v -= np.pi a = 2 s = 5 x = s * (a + cos(u / 2) * sin(v) - sin(u / 2) * sin(2 * v) / 2) * cos(u) y = s * (a + cos(u / 2) * sin(v) - sin(u / 2) * sin(2 * v) / 2) * sin(u) z = s * (sin(u / 2) * sin(v) + cos(u / 2) * sin(2 * v) / 2) else: r = 4 * (1 - cos(u) / 2) x = 6 * cos(u) * (1 + sin(u)) \ + r * cos(u) * cos(v) * (u < pi) \ + r * cos(v + pi) * (u >= pi) y = 16 * sin(u) + r * sin(u) * cos(v) * (u < pi) z = r * sin(v) if draw: mesh = p3.plot_surface(x, y, np.array([z]), wrapx=not endpoint, wrapy=not endpoint) if show: p3.show() return mesh else: return x, y, z, u, v
def show_image(index=0): p3.figure() p3.volshow(indexed_timeseries.data[index], tf=linear_transfer_function([0, 0, 0], max_opacity=.3)) output.clear_output(wait=True) with output: p3.show()
def plot_soma_3d(neurons_df, color_by='cellBodyFiber', point_size=1.0): """ Plot the soma locations in 3D, colored randomly according to the column given in ``color_by``. Requires ``ipyvolume``. If using Jupyterlab, install it like this: .. code-block: bash conda install -c conda-forge ipyvolume jupyter labextension install ipyvolume Example: .. code-block: python from neuprint import fetch_neurons, NeuronCriteria as NC criteria = NC(status='Traced', cropped=False) neurons_df, _roi_counts_df = fetch_neurons(criteria) plot_soma_3d(neurons_df, 'cellBodyFiber') """ import ipyvolume.pylab as ipv neurons_df = neurons_df[['somaLocation', color_by]].copy() extract_soma_coords(neurons_df) assign_colors(neurons_df, color_by) neurons_with_soma_df = neurons_df.query('not somaLocation.isnull()') assert neurons_with_soma_df.eval('color.isnull()').sum() == 0 soma_x = neurons_with_soma_df['soma_x'].values soma_y = neurons_with_soma_df['soma_y'].values soma_z = neurons_with_soma_df['soma_z'].values def color_to_vals(color_string): # Convert bokeh color string into float tuples, # e.g. '#00ff00' -> (0.0, 1.0, 0.0) s = color_string return (int(s[1:3], 16) / 255, int(s[3:5], 16) / 255, int(s[5:7], 16) / 255) color_vals = neurons_with_soma_df['color'].apply(color_to_vals).tolist() # DVID coordinate system assumes (0,0,0) is in the upper-left. # For consistency with DVID and neuroglancer conventions, # we invert the Y and X coordinates. ipv.figure() ipv.scatter(soma_x, -soma_y, -soma_z, color=color_vals, marker="circle_2d", size=point_size) ipv.show()
def plot_group_brain_activation(self, radius=12.5, freq_range=(40, 200), clim=None, cmap='RdBu_r'): """ Plots brain surface based on the mean activity across the group. Uses ipyvolume to plot Parameters ---------- radius: float Maximum distance between an electrode and a vertex to be counted as data for that vertex freq_range: list 2 element list defining minimum and maximum frequncies to average. clim: float Maximum/minumum value of the colormap. Will be centered at zero. If not given, will use the maximum absolute value of the data. cmap: str matplotlib colormap to use Returns ------- left hemisphere and right hemisphere activation maps """ # load brain mesh l_coords, l_faces, r_coords, r_faces = self.load_brain_mesh() # compute mean activation l_vert_mean, r_vert_mean = self.compute_surface_map(radius, freq_range) # define colormap range if clim is None: clim = np.max([np.nanmax(np.abs(l_vert_mean)), np.nanmax(np.abs(r_vert_mean))]) c_norm = plt.Normalize(vmin=-clim, vmax=clim) c_mappable = cmx.ScalarMappable(norm=c_norm, cmap=plt.get_cmap(cmap)) # compute surface colors for left valid_l_inds = ~np.isnan(l_vert_mean) l_colors = np.full((l_vert_mean.shape[0], 4), 0.) l_colors[valid_l_inds] = c_mappable.to_rgba(l_vert_mean[valid_l_inds]) # and right valid_r_inds = ~np.isnan(r_vert_mean) r_colors = np.full((r_vert_mean.shape[0], 4), 0.) r_colors[valid_r_inds] = c_mappable.to_rgba(r_vert_mean[valid_r_inds]) # plot it! fig = p3.figure(width=800, height=800, lighting=True) brain_l = p3.plot_trisurf(l_coords[:, 0], l_coords[:, 1], l_coords[:, 2], triangles=l_faces, color=l_colors) brain_r = p3.plot_trisurf(r_coords[:, 0], r_coords[:, 1], r_coords[:, 2], triangles=r_faces, color=r_colors) # turn off axis and make square ipv.squarelim() ipv.style.box_off() ipv.style.axes_off() p3.show() return fig
def klein_bottle(draw=True, show=True, figure8=False, endpoint=True, uv=False, wireframe=False, texture=None): import ipyvolume.pylab as p3 # http://paulbourke.net/geometry/klein/ u = np.linspace(0, 2 * pi, num=40, endpoint=endpoint) v = np.linspace(0, 2 * pi, num=40, endpoint=endpoint) u, v = np.meshgrid(u, v) if figure8: #u -= np.pi #v -= np.pi a = 2 s = 5 x = s * (a + cos(u / 2) * sin(v) - sin(u / 2) * sin(2 * v) / 2) * cos(u) y = s * (a + cos(u / 2) * sin(v) - sin(u / 2) * sin(2 * v) / 2) * sin(u) z = s * (sin(u / 2) * sin(v) + cos(u / 2) * sin(2 * v) / 2) else: r = 4 * (1 - cos(u) / 2) x = 6 * cos(u) * (1 + sin(u)) \ + r * cos(u) * cos(v) * (u < pi) \ + r * cos(v + pi) * (u >= pi) y = 16 * sin(u) + r * sin(u) * cos(v) * (u < pi) z = r * sin(v) if draw: if texture: uv = True if uv: mesh = p3.plot_mesh(x, y, np.array([z]), wrapx=not endpoint, wrapy=not endpoint, u=u / (2 * np.pi), v=v / (2 * np.pi), wireframe=wireframe, texture=texture) else: mesh = p3.plot_mesh(x, y, np.array([z]), wrapx=not endpoint, wrapy=not endpoint, wireframe=wireframe, texture=texture) if show: p3.show() return mesh else: return x, y, z, u, v
def update_figure(index=0): p3.figure() p3.volshow( indexed_timeseries.data[index].transpose([1, 0, 2]), tf=linear_transfer_function([0, 0, 0], max_opacity=0.3), ) output.clear_output(wait=True) self.figure = output with output: p3.show()
def plot(self, plot_mesh=True, plot_voxels=True, width=800, height=600, voxel_count_offset=0, voxel_limit=None, use_centroids_instead=False, scaling=1, mesh_color='red', **kwargs): """ This method needs better documentation. :param **kwargs: Is used in ipyvolume.pylab.scatter() or ipyvolume.pylab.plot() depending on whether use_centroids_instead is set to true or not. """ if plot_mesh: if self.triangles is None: raise ValueError( "There is no triangle data stored for this mesh!") else: fig = p3.figure(width=width, height=height) p3.plot_trisurf(*self.vertices.T * scaling, self.triangles, color=mesh_color) if plot_voxels: self.voxels.plot( width=width, height=height, voxel_count_offset=voxel_count_offset, voxel_limit=voxel_limit, use_centroids_instead=use_centroids_instead, ipyvol_fig=fig, scaling=scaling, **kwargs) else: p3.squarelim() p3.show() elif plot_voxels: try: fig = p3.figure(width=width, height=height) self.voxels.plot(width=width, height=height, voxel_count_offset=voxel_count_offset, voxel_limit=voxel_limit, use_centroids_instead=use_centroids_instead, ipyvol_fig=fig, scaling=scaling, **kwargs) except AttributeError: raise AttributeError( "This object does not have a Voxels object, you must initialize the voxel mesh with a Voxels object or run voxelize() to generate new voxels." )
def example_ylm(m=0, n=2, shape=128, limits=[-4, 4], draw=True, show=True, **kwargs): import ipyvolume.pylab as p3 __, __, __, r, theta, phi = xyz(shape=shape, limits=limits, spherical=True) radial = np.exp(-(r - 2) ** 2) data = np.abs(scipy.special.sph_harm(m, n, theta, phi) ** 2) * radial if draw: vol = p3.volshow(data=data, **kwargs) if show: p3.show() return vol else: return data
def init_vector(show=True): #This function initializes a figure with basis vectors in world frame - requires import ipyvolume.pylab as p3 outside scope #p3.clear() origin = np.array([0.0, 0.0, 0.0]) x = origin + np.array([1.0, 0.0, 0.0]) y = origin + np.array([0.0, 1.0, 0.0]) z = origin + np.array([0.0, 0.0, 1.0]) u = np.array([1.0, 0.0, 0.0]) v = np.array([0.0, 1.0, 0.0]) w = np.array([0.0, 0.0, 1.0]) quiver = p3.quiver(x, y, z, u, v, w, size=10, marker='arrow', color=np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])) #ipv.show() scatter = p3.scatter(np.array([origin[0]]), np.array([origin[0]]), np.array([origin[0]]), size=5, marker='sphere', color='red') line1 = p3.plot(np.array([origin[0], x[0]]), np.array([origin[0], x[1]]), np.array([origin[0], x[2]]), color='red') line2 = p3.plot(np.array([origin[0], y[0]]), np.array([origin[0], y[1]]), np.array([origin[0], y[2]]), color='green') line3 = p3.plot(np.array([origin[0], z[0]]), np.array([origin[0], z[1]]), np.array([origin[0], z[2]]), color='blue') #scatter = p3.scatter(x,y,z,size=2,marker = 'sphere',color='red') # the origin if show: p3.show() p3.style.box_off() handle = { 'origin': scatter, 'arrows': quiver, 'linex': line1, 'liney': line2, 'linez': line3 } #p3.style.axes_off() return handle
def plot(self, width=800, height=600, voxel_count_offset=0, voxel_limit=None, use_centroids_instead=False, ipyvol_fig=None, scaling=1, **kwargs): """ This method needs better documentation. :param **kwargs: Is used in ipyvolume.pylab.scatter() or ipyvolume.pylab.plot() depending on whether use_centroids_instead is set to true or not. """ if ipyvol_fig is None: p3.figure(width=width, height=height) else: p3.figure(ipyvol_fig) voxels_length = len(self) if voxel_count_offset >= voxels_length: raise ValueError( "voxel_count_offset is greater than the number of voxels!") else: if voxel_limit is None: n_voxels_to_plot = len(self) else: n_voxels_to_plot = voxel_count_offset + voxel_limit if n_voxels_to_plot > voxels_length: n_voxels_to_plot = len(self) if use_centroids_instead: if 'marker' not in kwargs: kwargs['marker'] = 'sphere' if 'color' not in kwargs: kwargs['color'] = 'blue' if 'size' not in kwargs: kwargs['size'] = 0.5 p3.scatter( *self.centroids[voxel_count_offset:n_voxels_to_plot].T * scaling, **kwargs) else: voxel_count_offset *= 18 n_voxels_to_plot *= 18 drawable_bboxes = self.drawable_bboxes[ voxel_count_offset:n_voxels_to_plot] p3.plot(*drawable_bboxes.T * scaling, **kwargs) p3.squarelim() p3.show()
def klein_bottle(draw=True, show=True, figure8=False, endpoint=True, uv=True, wireframe=False, texture=None, both=False, interval=1000): """Show one or two Klein bottles""" import ipyvolume.pylab as p3 # http://paulbourke.net/geometry/klein/ u = np.linspace(0, 2 * pi, num=40, endpoint=endpoint) v = np.linspace(0, 2 * pi, num=40, endpoint=endpoint) u, v = np.meshgrid(u, v) if both: x1, y1, z1, u1, v1 = klein_bottle(endpoint=endpoint, draw=False, show=False) x2, y2, z2, u2, v2 = klein_bottle(endpoint=endpoint, draw=False, show=False, figure8=True) x = [x1, x2] y = [y1, y2] z = [z1, z2] else: if figure8: #u -= np.pi #v -= np.pi a = 2 s = 5 x = s * (a + cos(u / 2) * sin(v) - sin(u / 2) * sin(2 * v)/2) * cos(u) y = s * (a + cos(u / 2) * sin(v) - sin(u / 2) * sin(2 * v)/2) * sin(u) z = s * (sin(u / 2) * sin(v) + cos(u / 2) * sin(2 * v)/2) else: r = 4 * (1 - cos(u) / 2) x = 6 * cos(u) * (1 + sin(u)) \ + r * cos(u) * cos(v) * (u < pi) \ + r * cos(v + pi) * (u >= pi) y = 16 * sin(u) + r * sin(u) * cos(v) * (u < pi) z = r * sin(v) if draw: if texture: uv = True if uv: mesh = p3.plot_mesh(x, y, z, wrapx=not endpoint, wrapy=not endpoint, u=u/(2*np.pi), v=v/(2*np.pi), wireframe=wireframe, texture=texture) else: mesh = p3.plot_mesh(x, y, z, wrapx=not endpoint, wrapy=not endpoint, wireframe=wireframe, texture=texture) if show: if both: p3.animation_control(mesh, interval=interval) p3.squarelim() p3.show() return mesh else: return x, y, z, u, v
# coordinate frame axes line segment tip arrows Xfv = Xf[:, 1, :] - Xf[:, 0, :] Yfv = Yf[:, 1, :] - Yf[:, 0, :] Zfv = Zf[:, 1, :] - Zf[:, 0, :] arrowcols = np.zeros((k, 3, 3)) arrowcols[0:k, 0, 0] = 1.0 arrowcols[0:k, 1, 1] = 1.0 arrowcols[0:k, 2, 2] = 1.0 q = p3.quiver(Xf[:, 1, :], Yf[:, 1, :], Zf[:, 1, :], Xfv[:, :], Yfv[:, :], Zfv[:, :], size=10, size_selected=5, color=arrowcols, color_selected='gray') # cylinder body surface s = p3.plot_surface(Xc, Yc, Zc, color='orange') # pass ipyvolume objects to animation controller and show p3.animation_control([Lx, Ly, Lz, q, s], interval=100) p3.show() # In[ ]: p3.save("shape_xform.html", offline=True)
import ipyvolume.pylab as p3 import numpy as np fig = p3.figure() q = p3.quiver(*stream.data[:,0:50,:200], color="red", size=7) p3.style.use("dark") # looks better p3.animation_control(q, interval=200) p3.show()
def showSurface(surface,overlay=None,frame=0,newfigure=True,colormap='summer',figsize=np.array([300,400]), figlims=np.array([[-75,75],[-75,75],[-75,75]])): ''' Displays a surface mesh in gifti or FreeSurfer (FS) surface format with/without an overlay inside Jupyter notebook for interactive visualization. Parameters ---------- surface: str, gifti opject Path to surface file in gifti or FS surface format or an already loaded gifti object of surface overlay: str, gifti opject Path to overlay file in gifti or FS annot or anaotimcal (.curv,.sulc,.thickness) format or an already loaded gifti object of overlay, default None frame: int indice of the frame (timepoint or functional data frame) to show newfigure: bool Create a new figure else prints into the last figure (in order to visualize both hemispheres in one plot), default True colormap: string A matplotlib colormap, default summer figsize: ndarray Size of the figure to display, default [600,600] figLims: ndarray x,y and z limits of the axes, default [[-100,100],[-100,100],[-100,100]]) ''' if isinstance(surface,str): if not os.path.exists(surface): error('File does not exist, please provide a valid file path to a gifti or FreeSurfer file.') filename, file_extension = os.path.splitext(surface) if file_extension is '.gii': surface = nb.load(surface) else: fsgeometry = nb.freesurfer.read_geometry(surface) x,y,z = fsgeometry[0].T vertex_edges=fsgeometry[1] if isinstance(surface,nb.gifti.gifti.GiftiImage): try: vertex_spatial=surface.darrays[0] vertex_edges=surface.darrays[1] x, y, z = vertex_spatial.data.T except: raise ValueError('Please provide a valid gifti file.') if not isinstance(frame,int): ValueError('Please provide a valid integer frame index.') if isinstance(overlay,list): if frame>len(overlay) or frame < 0: error('Frame index out of bounds, please provide a valid frame index.') overlay = overlay[frame] if isinstance(overlay,str): if not os.path.exists(overlay): error('File does not exist, please provide a valid file path to a gifti or FreeSurfer file.') filename, file_extension = os.path.splitext(overlay) if file_extension is '.gii': overlay = nb.load(overlay) elif (file_extension in ('.annot','')): annot = nb.freesurfer.read_annot(overlay) activation = annot[0] elif (file_extension in ('.curv','.thickness','.sulc')): activation = nb.freesurfer.read_morph_data(overlay) if isinstance(overlay,nb.gifti.gifti.GiftiImage): try: activation=overlay.darrays[0].data except: raise ValueError('Please provide a valid gifti file') if newfigure: fig = p3.figure(width=figsize[0], height=figsize[1]) fig.camera_fov = 1 fig.style = {'axes': {'color': 'black', 'label': {'color': 'black'}, 'ticklabel': {'color': 'black'}, 'visible': False}, 'background-color': 'white', 'box': {'visible': False}} fig.xlim = (figlims[0][0], figlims[0][1]) fig.ylim = (figlims[1][0], figlims[1][1]) fig.zlim = (figlims[2][0], figlims[2][1]) # plot surface if overlay is None: p3.plot_trisurf(x, y, z, triangles=vertex_edges.data) else: my_color = plt.cm.get_cmap(colormap) colors=my_color((activation-min(activation))/(max(activation)-min(activation))) p3.plot_trisurf(x, y, z, triangles=vertex_edges.data, color=colors[:,:3]) if newfigure: p3.show()
def plot_group_brain_activation(self, radius=12.5, freq_range=(40, 200), clim=None, cmap='RdBu_r', n_perms=100, min_n=5, res_key='t-stat'): """ Plots brain surface based on the mean activity across the group. Uses ipyvolume to plot Parameters ---------- radius: float Maximum distance between an electrode and a vertex to be counted as data for that vertex freq_range: list 2 element list defining minimum and maximum frequncies to average. clim: float Maximum/minumum value of the colormap. Will be centered at zero. If not given, will use the maximum absolute value of the data. cmap: str matplotlib colormap to use n_perms: int Number of permutations to do when computing our t-statistic significance thresholds min_n: int Vertices with less than this number of subjects will be plotted in gray, regardless of the significance val res_key: str Column name of dataframe to use as the metric Returns ------- left hemisphere and right hemisphere activation maps """ # load brain mesh l_coords, l_faces, r_coords, r_faces = self.load_brain_mesh() # compute mean activation. First get vertex x subject arrays l_vert_vals, r_vert_vals = self.compute_surface_map(radius, freq_range, res_key) # we will actually be plotting t-statistics, so compute those l_ts, l_ps = ttest_1samp(l_vert_vals, 0, axis=1, nan_policy='omit') r_ts, r_ps = ttest_1samp(r_vert_vals, 0, axis=1, nan_policy='omit') # not let's compute our significance thresholds via non-parametric permutation procedure sig_thresh = self.compute_permute_dist_par(l_vert_vals, r_vert_vals, n_perms=n_perms) # define colormap range if clim is None: clim = np.max([np.nanmax(np.abs(l_ts)), np.nanmax(np.abs(r_ts))]) c_norm = plt.Normalize(vmin=-clim, vmax=clim) c_mappable = cmx.ScalarMappable(norm=c_norm, cmap=plt.get_cmap(cmap)) # compute surface colors for left valid_l_inds = ~np.isnan(l_ts) & (np.sum(np.isnan(l_vert_vals), axis=1) >= min_n) l_colors = np.full((l_ts.shape[0], 4), 0.) l_colors[valid_l_inds] = c_mappable.to_rgba(l_ts[valid_l_inds]) # and right valid_r_inds = ~np.isnan(r_ts) & (np.sum(np.isnan(r_vert_vals), axis=1) >= min_n) r_colors = np.full((r_ts.shape[0], 4), 0.) r_colors[valid_r_inds] = c_mappable.to_rgba(r_ts[valid_r_inds]) # lastly, mask out vertices that do not meet our significance thresh sig_l = (l_ts < sig_thresh[0]) | (l_ts > sig_thresh[1]) sig_r = (r_ts < sig_thresh[0]) | (r_ts > sig_thresh[1]) l_colors[~sig_l] = [.7, .7, .7, 0.] r_colors[~sig_r] = [.7, .7, .7, 0.] # plot it! fig = p3.figure(width=800, height=800, lighting=True) brain_l = p3.plot_trisurf(l_coords[:, 0], l_coords[:, 1], l_coords[:, 2], triangles=l_faces, color=l_colors) brain_r = p3.plot_trisurf(r_coords[:, 0], r_coords[:, 1], r_coords[:, 2], triangles=r_faces, color=r_colors) # turn off axis and make square ipv.squarelim() ipv.style.box_off() ipv.style.axes_off() p3.show() return fig
def plot_skeleton_3d(skeleton, color='blue', *, client=None): """ Plot the given skeleton in 3D. Args: skeleton: Either a bodyId or a pre-fetched pandas DataFrame color: See ``ipyvolume`` docs. Examples: ``'blue'``, ``'#0000ff'`` If the skeleton is fragmented, you can give a list of colors and each fragment will be shown in a different color. Requires ``ipyvolume``. If using Jupyterlab, install it like this: .. code-block: bash conda install -c conda-forge ipyvolume jupyter labextension install ipyvolume """ import ipyvolume.pylab as ipv if np.issubdtype(type(skeleton), np.integer): skeleton = client.fetch_skeleton(skeleton, format='pandas') assert isinstance(skeleton, pd.DataFrame) g = skeleton_df_to_nx(skeleton) def skel_path(root): """ We want to plot each skeleton fragment as a single continuous line, but that means we have to backtrack: parent -> leaf -> parent to avoid jumping from one branch to another. This means that the line will be drawn on top of itself, and we'll have 2x as many line segments in the plot, but that's not a big deal. """ def accumulate_points(n): p = (g.nodes[n]['x'], g.nodes[n]['y'], g.nodes[n]['z']) points.append(p) children = [*g.successors(n)] if not children: return for c in children: accumulate_points(c) points.append(p) points = [] accumulate_points(root) return np.asarray(points) # Skeleton may contain multiple fragments, # so compute the path for each one. def skel_paths(df): paths = [] for root in df.query('link == -1')['rowId']: paths.append(skel_path(root)) return paths paths = skel_paths(skeleton) if isinstance(color, str): colors = len(paths) * [color] else: colors = (1 + len(paths) // len(color)) * color ipv.figure() for points, color in zip(paths, colors): ipv.plot(*points.transpose(), color) ipv.show()
def plot_group_brain_activation(self, radius=12.5, freq_range=(40, 200), clim=None, cmap='RdBu_r', n_perms=100, min_n=5): """ Plots brain surface based on the mean activity across the group. Uses ipyvolume to plot Parameters ---------- radius: float Maximum distance between an electrode and a vertex to be counted as data for that vertex freq_range: list 2 element list defining minimum and maximum frequncies to average. clim: float Maximum/minumum value of the colormap. Will be centered at zero. If not given, will use the maximum absolute value of the data. cmap: str matplotlib colormap to use n_perms: int Number of permutations to do when computing our t-statistic significance thresholds min_n: int Vertices with less than this number of subjects will be plotted in gray, regardless of the significance val Returns ------- left hemisphere and right hemisphere activation maps """ # load brain mesh l_coords, l_faces, r_coords, r_faces = self.load_brain_mesh() # compute mean activation. First get vertex x subject arrays l_vert_vals, r_vert_vals = self.compute_surface_map(radius, freq_range) # we will actually be plotting t-statistics, so compute those l_ts, l_ps = ttest_1samp(l_vert_vals, 0, axis=1, nan_policy='omit') r_ts, r_ps = ttest_1samp(r_vert_vals, 0, axis=1, nan_policy='omit') # not let's compute our significance thresholds via non-parametric permutation procedure sig_thresh = self.compute_permute_dist_par(l_vert_vals, r_vert_vals, n_perms=n_perms) # define colormap range if clim is None: clim = np.max([np.nanmax(np.abs(l_ts)), np.nanmax(np.abs(r_ts))]) c_norm = plt.Normalize(vmin=-clim, vmax=clim) c_mappable = cmx.ScalarMappable(norm=c_norm, cmap=plt.get_cmap(cmap)) # compute surface colors for left valid_l_inds = ~np.isnan(l_ts) & (np.sum(np.isnan(l_vert_vals), axis=1) >= min_n) l_colors = np.full((l_ts.shape[0], 4), 0.) l_colors[valid_l_inds] = c_mappable.to_rgba(l_ts[valid_l_inds]) # and right valid_r_inds = ~np.isnan(r_ts) & (np.sum(np.isnan(r_vert_vals), axis=1) >= min_n) r_colors = np.full((r_ts.shape[0], 4), 0.) r_colors[valid_r_inds] = c_mappable.to_rgba(r_ts[valid_r_inds]) # lastly, mask out vertices that do not meet our significance thresh sig_l = (l_ts < sig_thresh[0]) | (l_ts > sig_thresh[1]) sig_r = (r_ts < sig_thresh[0]) | (r_ts > sig_thresh[1]) l_colors[~sig_l] = [.7, .7, .7, 0.] r_colors[~sig_r] = [.7, .7, .7, 0.] # plot it! fig = p3.figure(width=800, height=800, lighting=True) brain_l = p3.plot_trisurf(l_coords[:, 0], l_coords[:, 1], l_coords[:, 2], triangles=l_faces, color=l_colors) brain_r = p3.plot_trisurf(r_coords[:, 0], r_coords[:, 1], r_coords[:, 2], triangles=r_faces, color=r_colors) # turn off axis and make square ipv.squarelim() ipv.style.box_off() ipv.style.axes_off() p3.show() return fig
def fermi3D(procar, outcar, bands=-1, scale=1, mode="plain", st=False, **kwargs): """ This function plots 3d fermi surface list of acceptable kwargs : plotting_package nprocess face_colors arrow_colors arrow_spin atom orbital spin """ welcome() # Initilizing the arguments : if "plotting_package" in kwargs: plotting_package = kwargs["plotting_package"] else: plotting_package = "mayavi" if "nprocess" in kwargs: nprocess = kwargs["nprocess"] else: nprocess = 2 if "face_colors" in kwargs: face_colors = kwargs["face_colors"] else: face_colors = None if "cmap" in kwargs: cmap = kwargs["cmap"] else: cmap = "jet" if "atoms" in kwargs: atoms = kwargs["atoms"] else: atoms = [-1] # project all atoms if "orbitals" in kwargs: orbitals = kwargs["orbitals"] else: orbitals = [-1] if "spin" in kwargs: spin = kwargs["spin"] else: spin = [0] if "mask_points" in kwargs: mask_points = kwargs["mask_points"] else: mask_points = 1 if "energy" in kwargs: energy = kwargs["energy"] else: energy = 0 if "transparent" in kwargs: transparent = kwargs["transparent"] else: transparent = False if "arrow_projection" in kwargs: arrow_projection = kwargs["arrow_projection"] else: arrow_projection = 2 if plotting_package == "mayavi": try: from mayavi import mlab from tvtk.api import tvtk except: print( "You have selected mayavi as plottin package. please install mayavi or choose a different package" ) return elif plotting_package == "plotly": try: import plotly.plotly as py import plotly.figure_factory as ff import plotly.graph_objs as go cmap = mpl.cm.get_cmap(cmap) figs = [] except: print( "You have selected plotly as plottin package. please install plotly or choose a different package" ) return elif plotting_package == "matplotlib": try: import matplotlib.pylab as plt from mpl_toolkits.mplot3d.art3d import Poly3DCollection except: print( "You have selected matplotlib as plotting package. please install matplotlib or choose a different package" ) return elif plotting_package == "ipyvolume": try: import ipyvolume.pylab as ipv except: print( "You have selected ipyvolume as plotting package. please install ipyvolume or choose a different package" ) return permissive = False # get fermi from outcar outcarparser = UtilsProcar() e_fermi = outcarparser.FermiOutcar(outcar) print("Fermi=", e_fermi) e_fermi += energy # get reciprocal lattice from outcar recLat = outcarparser.RecLatOutcar(outcar) # parsing the Procar file procarFile = ProcarParser() procarFile.readFile(procar, permissive) poly = get_wigner_seitz(recLat) # plot brilliouin zone if plotting_package == "mayavi": brillouin_point = [] brillouin_faces = [] point_count = 0 for iface in poly: single_face = [] for ipoint in iface: single_face.append(point_count) brillouin_point.append(list(ipoint)) point_count += 1 brillouin_faces.append(single_face) polydata_br = tvtk.PolyData(points=brillouin_point, polys=brillouin_faces) mlab.pipeline.surface( polydata_br, representation="wireframe", color=(0, 0, 0), line_width=4, name="BRZ", ) elif plotting_package == "plotly": for iface in poly: iface = np.pad(iface, ((0, 1), (0, 0)), "wrap") x, y, z = iface[:, 0], iface[:, 1], iface[:, 2] plane = go.Scatter3d(x=x, y=y, z=z, mode="lines", line=dict(color="black", width=4)) figs.append(plane) elif plotting_package == "matplotlib": fig = plt.figure() ax = fig.add_subplot(111, projection="3d") brillouin_zone = Poly3DCollection(poly, facecolors=["None"] * len(poly), alpha=1, linewidth=4) brillouin_zone.set_edgecolor("k") ax.add_collection3d(brillouin_zone, zs=0, zdir="z") br_points = [] for iface in poly: for ipoint in iface: br_points.append(ipoint) br_points = np.unique(br_points, axis=0) print("Number of bands: %d" % procarFile.bandsCount) print("Number of koints %d" % procarFile.kpointsCount) print("Number of ions: %d" % procarFile.ionsCount) print("Number of orbitals: %d" % procarFile.orbitalCount) print("Number of spins: %d" % procarFile.ispin) # selecting the data data = ProcarSelect(procarFile, deepCopy=True) if bands == -1: bands = range(data.bands.shape[1]) kvector = data.kpoints kmax = np.max(kvector) kmin = np.min(kvector) if abs(kmax) != abs(kmin): print("The mesh provided is gamma center, symmetrizing data") print("For a better fermi surface, use a non-gamma centered k-mesh") data = symmetrize(data) kvector = data.kpoints kvector_red = data.kpoints.copy() kvector_cart = np.dot(kvector_red, recLat) # This section finds points that are outside of the 1st BZ and and creates those points in the 1st BZ kvector_cart, kvector_red, has_points_out = bring_pnts_to_BZ( recLat, kvector_cart, kvector_red, br_points) # has_points_out = False # getting the mesh grid in each dirrection kx_red = np.unique(kvector_red[:, 0]) ky_red = np.unique(kvector_red[:, 1]) kz_red = np.unique(kvector_red[:, 2]) # getting the lengths between kpoints in each direction klength_x = np.abs(kx_red[-1] - kx_red[-2]) klength_y = np.abs(ky_red[-1] - ky_red[-2]) klength_z = np.abs(kz_red[-1] - kz_red[-2]) klengths = [klength_x, klength_y, klength_z] # getting number of kpoints in each direction with the addition of kpoints needed to sample the 1st BZ fully (in reduced) nkx_red = kx_red.shape[0] nky_red = ky_red.shape[0] nkz_red = kz_red.shape[0] # getting numner of kpoints in each direction provided by vasp nkx_orig = np.unique(kvector[:, 0]).shape[0] nky_orig = np.unique(kvector[:, 1]).shape[0] nkz_orig = np.unique(kvector[:, 2]).shape[0] # Amount of kpoints needed to add on to fully sample 1st BZ padding_x = (nkx_red - nkx_orig) // 2 padding_y = (nky_red - nky_orig) // 2 padding_z = (nkz_red - nkz_orig) // 2 if mode == "parametric": data.selectIspin(spin) data.selectAtoms(atoms, fortran=False) data.selectOrbital(orbitals) elif mode == "external": if "color_file" in kwargs: rf = open(kwargs["color_file"]) lines = rf.readlines() counter = 0 color_kvector = [] color_eigen = [] for iline in lines: if counter < 2: if "band" in iline: counter += 1 continue temp = [float(x) for x in iline.split()] color_kvector.append([temp[0], temp[1], temp[2]]) counter = -1 for iline in lines: if "band" in iline: counter += 1 iband = int(iline.split()[-1]) color_eigen.append([]) continue color_eigen[counter].append(float(iline.split()[-1])) rf.close() color_kvector = np.array(color_kvector) color_kvector_red = color_kvector.copy() color_kvector_cart = np.dot(color_kvector, recLat) if has_points_out: color_kvector_cart, color_kvector_red, temp = bring_pnts_to_BZ( recLat, color_kvector_cart, color_kvector_red, br_points) else: print( "mode selected was external, but no color_file name was provided" ) return if st: dataX = ProcarSelect(procarFile, deepCopy=True) dataY = ProcarSelect(procarFile, deepCopy=True) dataZ = ProcarSelect(procarFile, deepCopy=True) dataX.kpoints = data.kpoints dataY.kpoints = data.kpoints dataZ.kpoints = data.kpoints dataX.spd = data.spd dataY.spd = data.spd dataZ.spd = data.spd dataX.bands = data.bands dataY.bands = data.bands dataZ.bands = data.bands dataX.selectIspin([1]) dataY.selectIspin([2]) dataZ.selectIspin([3]) dataX.selectAtoms(atoms, fortran=False) dataY.selectAtoms(atoms, fortran=False) dataZ.selectAtoms(atoms, fortran=False) dataX.selectOrbital(orbitals) dataY.selectOrbital(orbitals) dataZ.selectOrbital(orbitals) ic = 0 for iband in bands: print("Plotting band %d" % iband) eigen = data.bands[:, iband] # mapping the eigen values on the mesh grid to a matrix mapped_func, kpoint_matrix = mapping_func(kvector, eigen) # adding the points from the 2nd BZ to 1st BZ to fully sample the BZ. Check np.pad("wrap") for more information mapped_func = np.pad( mapped_func, ((padding_x, padding_x), (padding_y, padding_y), (padding_z, padding_z)), "wrap", ) # Fourier interpolate the mapped function E(x,y,z) surf_equation = fft_interpolate(mapped_func, scale) # after the FFT we loose the center of the BZ, using numpy roll we bring back the center of the BZ surf_equation = np.roll(surf_equation, (scale) // 2, axis=[0, 1, 2]) try: # creating the isosurface if possible verts, faces, normals, values = measure.marching_cubes_lewiner( surf_equation, e_fermi) except: print("No isosurface for this band") continue # the vertices provided are scaled and shifted to start from zero # we center them to zero, and rescale them to fit the real BZ by multiplying by the klength in each direction for ix in range(3): verts[:, ix] -= verts[:, ix].min() verts[:, ix] -= (verts[:, ix].max() - verts[:, ix].min()) / 2 verts[:, ix] *= klengths[ix] / scale # the vertices need to be transformed to reciprocal spcae from recuded space, to find the points that are # in 2nd BZ, to be removed verts = np.dot(verts, recLat) # identifying the points in 2nd BZ and removing them if has_points_out: args = [] for ivert in range(len(verts)): args.append([br_points, verts[ivert]]) p = Pool(nprocess) results = np.array(p.map(is_outside, args)) p.close() out_verts = np.arange(0, len(results))[results] new_faces = [] # outs_bool_mat = np.zeros(shape=faces.shape,dtype=np.bool) for iface in faces: remove = False for ivert in iface: if ivert in out_verts: remove = True continue if not remove: new_faces.append(iface) faces = np.array(new_faces) print("done removing") # At this point we have the plain Fermi surface, we can color the surface depending on the projection # We create the center of faces by averaging coordinates of corners if mode == "parametric": character = data.spd[:, iband] centers = np.zeros(shape=(len(faces), 3)) for iface in range(len(faces)): centers[iface, 0:3] = np.average(verts[faces[iface]], axis=0) colors = interpolate.griddata(kvector_cart, character, centers, method="nearest") elif mode == "external": character = np.array(color_eigen[ic]) ic += 1 centers = np.zeros(shape=(len(faces), 3)) for iface in range(len(faces)): centers[iface, 0:3] = np.average(verts[faces[iface]], axis=0) colors = interpolate.griddata(color_kvector_cart, character, centers, method="nearest") if st: projection_x = dataX.spd[:, iband] projection_y = dataY.spd[:, iband] projection_z = dataZ.spd[:, iband] verts_spin, faces_spin, normals, values = measure.marching_cubes_lewiner( mapped_func, e_fermi) for ix in range(3): verts_spin[:, ix] -= verts_spin[:, ix].min() verts_spin[:, ix] -= (verts_spin[:, ix].max() - verts_spin[:, ix].min()) / 2 verts_spin[:, ix] *= klengths[ix] verts_spin = np.dot(verts_spin, recLat) if has_points_out: args = [] for ivert in range(len(verts_spin)): args.append([br_points, verts_spin[ivert]]) p = Pool(nprocess) results = np.array(p.map(is_outside, args)) p.close() out_verts = np.arange(0, len(results))[results] new_faces = [] for iface in faces_spin: remove = False for ivert in iface: if ivert in out_verts: remove = True continue if not remove: new_faces.append(iface) faces_spin = np.array(new_faces) centers = np.zeros(shape=(len(faces_spin), 3)) for iface in range(len(faces_spin)): centers[iface, 0:3] = np.average(verts_spin[faces_spin[iface]], axis=0) colors1 = interpolate.griddata(kvector_cart, projection_x, centers, method="linear") colors2 = interpolate.griddata(kvector_cart, projection_y, centers, method="linear") colors3 = interpolate.griddata(kvector_cart, projection_z, centers, method="linear") spin_arrows = np.vstack((colors1, colors2, colors3)).T if plotting_package == "mayavi": polydata = tvtk.PolyData(points=verts, polys=faces) if face_colors != None: mlab.pipeline.surface( polydata, representation="surface", color=face_colors[ic], opacity=1, name="band-" + str(iband), ) ic += 1 else: if mode == "plain": if not (transparent): s = mlab.pipeline.surface( polydata, representation="surface", color=(0, 0.5, 1), opacity=1, name="band-" + str(iband), ) elif mode == "parametric" or mode == "external": polydata.cell_data.scalars = colors polydata.cell_data.scalars.name = "celldata" mlab.pipeline.surface(polydata, vmin=0, vmax=colors.max(), colormap=cmap) cb = mlab.colorbar(orientation="vertical") if st: x, y, z = list(zip(*centers)) u, v, w = list(zip(*spin_arrows)) pnts = mlab.quiver3d( x, y, z, u, v, w, line_width=5, mode="arrow", resolution=25, reset_zoom=False, name="spin-" + str(iband), mask_points=mask_points, scalars=spin_arrows[:, arrow_projection], vmin=-1, vmax=1, colormap=cmap, ) pnts.glyph.color_mode = "color_by_scalar" pnts.glyph.glyph_source.glyph_source.shaft_radius = 0.05 pnts.glyph.glyph_source.glyph_source.tip_radius = 0.1 elif plotting_package == "plotly": if mode == "plain": if not (transparent): x, y, z = zip(*verts) fig = ff.create_trisurf( x=x, y=y, z=z, plot_edges=False, simplices=faces, title="band-%d" % ic, ) figs.append(fig["data"][0]) elif mode == "parametric" or mode == "external": face_colors = cmap(colors) colormap = [ "rgb(%i,%i,%i)" % (x[0], x[1], x[2]) for x in (face_colors * 255).round() ] x, y, z = zip(*verts) fig = ff.create_trisurf( x=x, y=y, z=z, plot_edges=False, colormap=colormap, simplices=faces, show_colorbar=True, title="band-%d" % ic, ) figs.append(fig["data"][0]) elif plotting_package == "matplotlib": if mode == "plain": x, y, z = zip(*verts) ax.plot_trisurf(x, y, faces, z, linewidth=0.2, antialiased=True) elif mode == "parametric" or mode == "external": print( "coloring the faces is not implemented in matplot lib, please use another plotting package.we recomend mayavi." ) elif plotting_package == "ipyvolume": if mode == "plain": ipv.figure() ipv.plot_trisurf(verts[:, 0], verts[:, 1], verts[:, 2], triangles=faces) elif mode == "paramteric" or mode == "external": face_colors = cmap(colors) colormap = [ "rgb(%i,%i,%i)" % (x[0], x[1], x[2]) for x in (face_colors * 255).round() ] ipv.figure() ipv.plot_trisurf(verts[:, 0], verts[:, 1], verts[:, 2], triangles=faces, color=cmap) if plotting_package == "mayavi": mlab.colorbar(orientation="vertical") # ,label_fmt='%.1f') mlab.show() elif plotting_package == "plotly": layout = go.Layout(showlegend=False) fig = go.Figure(data=figs, layout=layout) py.iplot(fig) elif plotting_package == "matplotlib": plt.show() elif plotting_package == "ipyvolume": ipv.show() return