def calc_shading(faces, normals, color=[255.0 / 255.0, 54.0 / 255.0, 57 / 255.0], alpha=1): ls = LightSource(azdeg=225.0, altdeg=45.0) # First change - normals are per vertex, so I made it per face. #normalsarray = np.array([np.array((np.sum(normals[face[:], 0]//3), np.sum(normals[face[:], 1]//3), np.sum(normals[face[:], 2]//3))/np.sqrt(np.sum(normals[face[:], 0]//3)**2 + np.sum(normals[face[:], 1]//3)**2 + np.sum(normals[face[:], 2]//3)**2)) for face in faces]) # Next this is more asthetic, but it prevents the shadows of the image being too dark. (linear interpolation to correct) min = np.min(ls.shade_normals(normals, fraction=1.0)) # min shade value max = np.max(ls.shade_normals(normals, fraction=1.0)) # max shade value diff = max - min newMin = 0.3 newMax = 0.95 newdiff = newMax - newMin # Using a constant color, put in desired RGB values here. colourRGB = np.asarray(color) # The correct shading for shadows are now applied. Use the face normals and light orientation to generate a shading value and apply to the RGB colors for each face. rgbNew = np.array([ colourRGB * (newMin + newdiff * ((shade - min) / diff)) for shade in ls.shade_normals(normals, fraction=1.0) ]) #rgbNew[:,3] = alpha # Apply color to face #new_mesh = Poly3DCollection(mesh.vectors) #new_mesh.set_facecolor(rgbNew) return rgbNew
def plot_isosurface(init_elev, init_azim, output_fname): fig = plt.figure(figsize=(10, 8)) ax = fig.add_subplot(111, projection=Axes3D.name) ax.view_init(init_elev, init_azim) lower_lim = -0.30 upper_lim = +0.30 tps_half = tps_preds_mat[:200, :, :] mask_half = mask_mat[:200, :, :] # Fancy indexing: `verts[faces]` to generate a collection of triangles verts, faces, normals, values = measure.marching_cubes(tps_half, lower_lim, mask=mask_half) mesh = Poly3DCollection(verts[faces], rasterized=rast) ls = LightSource(azdeg=225.0, altdeg=45.0) normalsarray = np.array([ np.array( (np.sum(normals[face[:], 0] / 3), np.sum(normals[face[:], 1] / 3), np.sum(normals[face[:], 2] / 3)) / np.sqrt( np.sum(normals[face[:], 0] / 3)**2 + np.sum(normals[face[:], 1] / 3)**2 + np.sum(normals[face[:], 2] / 3)**2)) for face in faces ]) # Next this is more asthetic, but it prevents the shadows of the image being too dark. (linear interpolation to correct) min = np.min(ls.shade_normals(normalsarray, fraction=1.0)) # min shade value max = np.max(ls.shade_normals(normalsarray, fraction=1.0)) # max shade value diff = max - min newMin = 0.3 newMax = 0.95 newdiff = newMax - newMin # Using a constant color, put in desired RGB values here. colourRGB = np.array((0 / 255.0, 53.0 / 255.0, 107 / 255.0, 1.0)) # The correct shading for shadows are now applied. Use the face normals and light orientation to generate a shading value and apply to the RGB colors for each face. rgbNew = np.array([ colourRGB * (newMin + newdiff * ((shade - min) / diff)) for shade in ls.shade_normals(normalsarray, fraction=1.0) ]) # Apply color to face mesh.set_facecolor(rgbNew) ax.add_collection3d(mesh) verts, faces, normals, values = measure.marching_cubes(tps_half, upper_lim, mask=mask_half) mesh = Poly3DCollection(verts[faces], rasterized=rast) ls = LightSource(azdeg=225.0, altdeg=45.0) normalsarray = np.array([ np.array( (np.sum(normals[face[:], 0] / 3), np.sum(normals[face[:], 1] / 3), np.sum(normals[face[:], 2] / 3)) / np.sqrt( np.sum(normals[face[:], 0] / 3)**2 + np.sum(normals[face[:], 1] / 3)**2 + np.sum(normals[face[:], 2] / 3)**2)) for face in faces ]) # Next this is more asthetic, but it prevents the shadows of the image being too dark. (linear interpolation to correct) min = np.min(ls.shade_normals(normalsarray, fraction=1.0)) # min shade value max = np.max(ls.shade_normals(normalsarray, fraction=1.0)) # max shade value diff = max - min newMin = 0.3 newMax = 0.95 newdiff = newMax - newMin # Using a constant color, put in desired RGB values here. colourRGB = np.array((255.0 / 255.0, 54.0 / 255.0, 57 / 255.0, 1.0)) # The correct shading for shadows are now applied. Use the face normals and light orientation to generate a shading value and apply to the RGB colors for each face. rgbNew = np.array([ colourRGB * (newMin + newdiff * ((shade - min) / diff)) for shade in ls.shade_normals(normalsarray, fraction=1.0) ]) # Apply color to face mesh.set_facecolor(rgbNew) ax.add_collection3d(mesh) ax.set_xlabel(r"Days since TC passage ($\tau$)") ax.set_ylabel(r"Cross-track angle, degrees ($d$)") ax.set_zlabel(r"Pressure, dbars ($z$)") ax.set_xlim(0, 200) ax.set_ylim(0, 100) ax.set_zlim(0, 20) ax.set_xticks([36, 91, 145, 199]) ax.set_xticklabels([0, 3, 6, 9]) ax.set_yticks([19, 50, 80]) ax.set_yticklabels([-5, 0, 5]) ax.set_zticks([0, 5, 10, 15, 19]) ax.set_zticklabels([200, 150, 100, 50, 10]) plt.savefig( output_fname, bbox_inches='tight', pad_inches=0, dpi=300, ) return
def plotColorView( ax, cortex, data, viewkey, shaded=False, shadowed=False, cmap=plt.cm.coolwarm, l_azimuth=0, l_altitude=0, lightingBias=0.2, # Light azimuth and altitude, and bias zlim=None, zthresh=None, suptitle='', viewlabel=False): # ================= This part should be computed only once for all views, but this way it is easier... if 'flat' not in viewkey: vtx_L, tri_L = cortex['model_L'].agg_data() vtx_R, tri_R = cortex['model_R'].agg_data() else: vtx_L, tri_L = cortex['flat_L'].agg_data() vtx_R, tri_R = cortex['flat_R'].agg_data() xL, yL, zL = vtx_L.T xR, yR, zR = vtx_R.T if 'map_L' in cortex or 'map_R' in cortex: # if we are giving a mapping between regions and vertices, let's use it! rm_L = cortex['map_L'] rm_R = cortex['map_R'] if viewkey in ['Lh-lateral', 'Lh-medial', 'L-superior']: vvalues = computeVertexValues(vtx_L, rm_L, data['func_L']) else: vvalues = computeVertexValues(vtx_R, rm_R, data['func_R']) else: # if not, it is because we were given the vertex-level values directly if viewkey in ['Lh-lateral', 'Lh-medial', 'L-superior']: vvalues = data['func_L'] else: vvalues = data['func_R'] views = { 'Lh-lateral': Triangulation(-yL, zL, tri_L), #tri[np.argsort(lh_ty)[::-1]]), 'Lh-medial': Triangulation(yL, zL, tri_L[::-1]), #lh_tri[np.argsort(lh_ty)]), 'Rh-medial': Triangulation(-yR, zR, tri_R[::-1]), #rh_tri[np.argsort(rh_ty)[::-1]]), 'Rh-lateral': Triangulation(yR, zR, tri_R), #rh_tri[np.argsort(rh_ty)]), 'L-superior': Triangulation(xL, yL, tri_L), #tri[np.argsort(tz)]), 'R-superior': Triangulation(xR, yR, tri_R), #tri[np.argsort(tz)]), 'L-flat': Triangulation(xL, yL, tri_L), 'R-flat': Triangulation(xR, yR, tri_R), } # ================= View-specific code... v = views[viewkey] if not viewlabel: plt.axis('off') if zthresh: z = vvalues.copy() * (abs(vvalues) > zthresh) # ================= Let's render it! if not shadowed or 'flat' in viewkey: if 'flat' in viewkey: kwargs = {'shading': 'flat'} # No edgecolors... else: kwargs = { 'shading': 'gouraud' } if shaded else { 'shading': 'flat', 'edgecolors': 'k', 'linewidth': 0.1 } tc = ax.tripcolor(v, vvalues, cmap=cmap, **kwargs) if zlim: tc.set_clim(vmin=-zlim, vmax=zlim) else: # ================= # Ok, we have a problem: tripcolor does not seem to tolerate vertex-defined colors, something we need # for shadows. So let's do this "manually". Internally, I think tripcolor uses a TriMesh to render # the mesh if gouraud is used, but somehow the later stages do not like the outcome (when doing plt.show()). # So, we are going to set the colors up... manually! I hate this as much as you do! ;-) colors = mapValues2Colors(vvalues, cmap) # Vertex colors if viewkey in ['Lh-lateral', 'Lh-medial', 'L-superior']: normals = computeVertexNormals(vtx_L, tri_L) else: normals = computeVertexNormals(vtx_R, tri_R) # Create a light source object for light from # azimuth (from north), elevation (from 0 elevation plane). Both in degrees. light = LightSource(l_azimuth, l_altitude) shaded = lightingBias + light.shade_normals(normals) * (1 - lightingBias) shadedColors = (colors[:, 0:3].T * shaded).T collection = TriMesh(v) collection.set_facecolor(shadedColors) ax.add_collection(collection) ax.autoscale_view() # ================= ax.set_aspect('equal') if suptitle: ax.set_title(suptitle, fontsize=24) if viewlabel: plt.xlabel(viewkey)
def plot_3d(image, ax, threshold=-300, alpha=0.1, face_color=[0.5, 0.5, 1], cut=None): p = image.transpose(2, 1, 0) if cut is not None: indices = np.array([[i, j, k] for i in range(p.shape[0]) for j in range(p.shape[1]) for k in range(p.shape[2])]) print(indices.shape) x, y, z = cut remove = np.logical_and(indices[..., 0] > x, indices[..., 1] < y) print(remove) indices = indices[remove] print(indices) # p[indices] = threshold - 1 p[x:, :y, :] = threshold - 1 print('skimage .....') verts, faces, normals, values = measure.marching_cubes_lewiner( p, threshold) # print(verts, verts.shape) # print(faces, faces.shape) vert = verts[faces] # if cut is not None: # x, y, z = cut # print(vert.shape) # print(vert[0]) # # vert[vert[0, ...] > x] = np.Na # print(np.logical_or(vert[..., 0] < x, vert[..., 1] > y)) # selected = np.logical_or(vert[..., 0] < x, vert[..., 1] > y) # vert = vert[selected] mesh = Poly3DCollection(vert, alpha=alpha) # mesh = Poly3DCollection(np.argwhere(p > threshold), alpha=1) ls = LightSource(azdeg=225.0, altdeg=45.0) normalsarray = np.array([ np.array((np.sum( normals[face[:], 0] / 3), np.sum(normals[face[:], 1] / 3), np.sum(normals[face[:], 2] / 3)) / np.sqrt( np.sum(normals[face[:], 0] / 3)**2 + np.sum(normals[face[:], 1] / 3)**2 + np.sum(normals[face[:], 2] / 3)**2)) for face in faces ]) # min shade value min = np.min(ls.shade_normals(normalsarray, fraction=1.0)) # max shade value max = np.max(ls.shade_normals(normalsarray, fraction=1.0)) diff = max - min newMin = 0.3 newMax = 0.95 newdiff = newMax - newMin # Using a constant color, put in desired RGB values here. # np.array((255.0/255.0, 54.0/255.0, 57/255.0, 1.0)) colourRGB = np.array((*face_color, 1.0)) # The correct shading for shadows are now applied. Use the face normals and light orientation to generate a shading value and apply to the RGB colors for each face. rgbNew = np.array([ colourRGB * (newMin + newdiff * ((shade - min) / diff)) for shade in ls.shade_normals(normalsarray, fraction=1.0) ]) # mesh.set_facecolor(face_color) mesh.set_facecolor(rgbNew) ax.add_collection3d(mesh) # ax.set_xlim(0, p.shape[0]) ax.set_xlim(0, p.shape[0]) ax.set_ylim(0, p.shape[1]) ax.set_zlim(0, p.shape[2])