def plot_retino_image(mesh_path, name, tf=None, tex=None, curv=None, mask=None, vmin=0, vmax=0): """Custom function to plot mesh in the case of retinotopic mapping Parameters ---------- mesh_path: string, path of the mesh to plot name: string, object identifier tf: (4, 4) array affine transformation that has to be applied to the mesh tex: array of shape (mes.n_vertices), texture to plot on the surface curv: array of shape (mes.n_vertices), curvature texture to plot on the surface mask: array of shape (mes.n_vertices), A mask for functional regions of interest vmin, vmax: bounds for color clipping """ vertices, triangles = mesh_arrays(mesh_path) af_coord = np.hstack((vertices, np.ones((vertices.shape[0], 1)))) if tf is not None: af_coord = np.dot(af_coord, tf.T) vertices = af_coord[:, :3] x, y, z = vertices.T # it is expected that the curvature takes values between 0 and 1 if curv is not None: cmin = 2 * curv.min() - curv.max() cmax = 2 * curv.max() - curv.min() mlab.triangular_mesh(x, y, z, triangles, transparent=False, opacity=1., name=name, scalars=curv, colormap="bone", vmin=cmin, vmax=cmax) else: mlab.triangular_mesh(x, y, z, triangles, transparent=False, opacity=1., name=name) if tex is not None: if mask is not None: tex[mask == 0] = vmin - 1 func_mesh = mlab.pipeline.triangular_mesh_source(x, y, z, triangles, scalars=tex) thresh = mlab.pipeline.threshold(func_mesh, low=vmin) mlab.pipeline.surface(thresh, colormap="jet", vmin=vmin, vmax=vmax, transparent=True, opacity=.8) mlab.scalarbar(thresh)
def plot_mesh(mesh, name, tf=None, tex=None): """ old version -- probably deprecated """ vertices, triangles = mesh_arrays(mesh) af_coord = np.hstack((vertices, np.ones((vertices.shape[0], 1)))) if tf is not None: af_coord = np.dot(af_coord, tf.T) vertices = af_coord[:, :3] x, y, z = vertices.T # show with mayavi if tex is None: mlab.triangular_mesh(x, y, z, triangles, transparent=False, opacity=1., name=name, color=(0.5, 0.5, 0.)) else: mlab.triangular_mesh(x, y, z, triangles, transparent=False, opacity=1., name=name, scalars=tex)
def find_fovea(mesh, side, mask, xy): """Small utility that returns the assumed fovea position on a mesh of a certain hemisphere""" from .group_analysis import resample_from_average REF_LEFT = np.arange(163842) == 71785 REF_RIGHT = np.arange(163842) == 129181 binary_texture = REF_LEFT if side == 'left' else REF_RIGHT binary_texture_path = '/tmp/fovea.gii' save_texture(binary_texture_path, binary_texture, intent='none') subject_path = op.join(op.dirname(mesh), '..') # resample from the average to the individual space resampled = resample_from_average(binary_texture_path, subject_path, side, verbose=True) # get the vertices of the mesh vertices, _ = mep.mesh_arrays(mesh) point = vertices[load_texture(resampled).argmax()] sq_dist = ((vertices - point) ** 2). sum(1) # find the point on the mask fovea = xy[np.argmin(sq_dist[mask])] return fovea
def retino_template(xy, ring, wedge, mesh, mask_, verbose=False, side='left'): """""" if ring is None: center = find_fovea(mesh, side, mask_, xy) else: center = get_ring_minimum(xy, ring, 0) # - np.pi / 2) ecc = np.sqrt(np.sum((xy - center) ** 2, 1)) angle = - np.arctan2(xy.T[1] - center[1], xy.T[0] - center[0]) radius = np.sqrt(np.mean(ecc ** 2)) * 1.2 def retino_polar(angle, ecc, radius, scale=1.): """""" a1, a2, a3 = scale * np.pi *.2, scale * np.pi *.3, scale * np.pi * .4 delta = .2 * 4. / radius ** 2 corr = angle * (radius ** 2 / 4 - (ecc - radius / 2) ** 2) angle_ = angle - delta * corr mask = (ecc < radius) * (np.abs(angle_) < a3) polar = np.zeros_like(angle_) slope = np.pi / (2 * a1) b1 = 2 * slope * a1 polar = slope * angle_ polar[angle_ > a1] = b1 - slope * angle_[angle_ > a1] polar[angle_ > a2] = slope * angle_[angle_ > a2] - 2 * slope * (a2 - a1) polar[angle_ < - a1] = - b1 - slope * angle_[angle_ < - a1] polar[angle_ < - a2] = slope * (angle_[angle_ < - a2] + 2 * (a2 - a1)) polar[mask == 0] = 0 maps = {'V1v': mask * (angle_ < 0) * (angle_ > - a1), 'V1d': mask * (angle_ > 0) * (angle_ < a1), 'V2v': mask * (angle_ < -a1) * (angle_ > - a2), 'V2d': mask * (angle_ > a1) * (angle_ < a2), 'V3v': mask * (angle_ < - a2) * (angle_ > - a3), 'V3d': mask * (angle_ > a2) * (angle_ < a3), } return mask, polar, maps vmin, vmax = 0., np.pi if side == 'left': vmin, vmax = -np.pi, 0. best_score = - np.inf # 2-dimensional search of the best rotation/scaling for scale in [1.]: for theta in np.linspace(0, 2 * np.pi, 100): angle_ = angle + theta angle_[angle_ > np.pi] -= 2 * np.pi mask, polar, maps = retino_polar(angle_, ecc, radius, scale) if mask.sum() == 0: continue if side == 'left': polar -= np.pi / 2 else: polar += np.pi / 2 weight = mask * (polar > vmin) * (polar < vmax) score = 1. - np.sum( weight[mask] * (wedge[mask] - polar[mask]) ** 2)/\ np.sum(weight[mask] * (wedge[mask]) ** 2) score = np.corrcoef(wedge[mask], polar[mask])[0, 1] if score > best_score: best_score = score best_polar = polar best_theta = theta visual_maps = maps best_mask = mask best_corr = np.corrcoef(wedge[mask], polar[mask])[0, 1] if verbose: print best_theta, best_corr import matplotlib.pyplot as plt plt.figure(figsize = (10, 5)) coord, tri = mep.mesh_arrays(mesh) coord, tri = coord[mask_], tri[mask_[tri].all(1)] tri = np.hstack((0, np.cumsum(mask_)[:-1]))[tri] plt.subplot(1, 3, 1) plt.tripcolor(xy.T[0], xy.T[1], tri, best_polar * best_mask, vmin=vmin, vmax=vmax) plt.plot(center[0], center[1], '+k', linewidth=4) plt.subplot(1, 3, 2) plt.tripcolor(xy.T[0], xy.T[1], tri, wedge, vmin=vmin, vmax=vmax) plt.plot(center[0], center[1], '+k', linewidth=4) plt.subplot(1, 3, 3) if ring is not None: plt.tripcolor(xy.T[0], xy.T[1], tri, ring) plt.plot(center[0], center[1], '+k', linewidth=4) return mask, polar, visual_maps