📚 The CoCalc Library - books, templates and other resources
License: OTHER
import matplotlib.pyplot as plt1import numpy as np23from ipywidgets import interact4from mpl_toolkits.mplot3d.art3d import Poly3DCollection5from skimage import exposure, io, measure678def show_plane(axis, plane, cmap="gray", title=None):9"""Shows a specific plane within 3D data.10"""11axis.imshow(plane, cmap=cmap)12axis.set_xticks([])13axis.set_yticks([])1415if title:16axis.set_title(title)1718return None192021def slice_in_3d(axis, shape, plane):22"""Draws a cube in a 3D plot.2324Parameters25----------26axis : matplotlib.Axes27A matplotlib axis to be drawn.28shape : tuple or array (1, 3)29Shape of the input data.30plane : int31Number of the plane to be drawn.3233Notes34-----35Originally from:36https://stackoverflow.com/questions/44881885/python-draw-parallelepiped37"""38Z = np.array([[0, 0, 0],39[1, 0, 0],40[1, 1, 0],41[0, 1, 0],42[0, 0, 1],43[1, 0, 1],44[1, 1, 1],45[0, 1, 1]])4647Z = Z * shape4849r = [-1, 1]5051X, Y = np.meshgrid(r, r)5253# plotting vertices54axis.scatter3D(Z[:, 0], Z[:, 1], Z[:, 2])5556# list of sides' polygons of figure57verts = [[Z[0], Z[1], Z[2], Z[3]],58[Z[4], Z[5], Z[6], Z[7]],59[Z[0], Z[1], Z[5], Z[4]],60[Z[2], Z[3], Z[7], Z[6]],61[Z[1], Z[2], Z[6], Z[5]],62[Z[4], Z[7], Z[3], Z[0]],63[Z[2], Z[3], Z[7], Z[6]]]6465# plotting sides66axis.add_collection3d(67Poly3DCollection(verts,68facecolors=(0, 1, 1, 0.25),69linewidths=1,70edgecolors='darkblue')71)7273verts = np.array([[[0, 0, 0],74[0, 0, 1],75[0, 1, 1],76[0, 1, 0]]])77verts = verts * shape78verts += [plane, 0, 0]7980axis.add_collection3d(81Poly3DCollection(verts,82facecolors='magenta',83linewidths=1,84edgecolors='black')85)8687axis.set_xlabel('plane')88axis.set_ylabel('col')89axis.set_zlabel('row')9091# auto-scale plot axes92scaling = np.array([getattr(axis, 'get_{}lim'.format(dim))() for dim in 'xyz'])93axis.auto_scale_xyz(*[[np.min(scaling), np.max(scaling)]] * 3)9495return None969798def slice_explorer(data, cmap='gray'):99"""Allows to explore 2D slices in 3D data.100101Parameters102----------103data : array (M, N, P)1043D interest image.105cmap : str (optional)106A string referring to one of matplotlib's colormaps.107"""108data_len = len(data)109110@interact(plane=(0, data_len-1), continuous_update=False)111def display_slice(plane=data_len/2):112fig, axis = plt.subplots(figsize=(20, 7))113axis_3d = fig.add_subplot(133, projection='3d')114show_plane(axis, data[plane], title='Plane {}'.format(plane), cmap=cmap)115slice_in_3d(axis=axis_3d, shape=data.shape, plane=plane)116plt.show()117118return display_slice119120121def display(data, cmap="gray", step=2):122_, axes = plt.subplots(nrows=5, ncols=6, figsize=(16, 14))123124# getting data min and max to plot limits125vmin, vmax = data.min(), data.max()126127for axis, image in zip(axes.flatten(), data[::step]):128axis.imshow(image, cmap=cmap, vmin=vmin, vmax=vmax)129axis.set_xticks([])130axis.set_yticks([])131132return None133134135def plot_hist(axis, data, title=None):136"""Helper function for plotting histograms.137"""138axis.hist(data.ravel(), bins=256)139axis.ticklabel_format(axis='y', style='scientific', scilimits=(0, 0))140141if title:142axis.set_title(title)143144return None145146147def plot_3d_surface(data, labels, region=3, spacing=(1.0, 1.0, 1.0)):148"""Generates a 3D surface plot for the specified region.149150Parameters151----------152data : array (M, N, P)1533D interest image.154labels : array (M, N, P)155Labels corresponding to data, obtained by measure.label.156region : int, optional157The region of interest to be plotted.158spacing : array (1, 3)159Spacing information, set distances between pixels.160161Notes162-----163The volume is visualized using the mesh vertexes and faces.164"""165properties = measure.regionprops(labels, intensity_image=data)166# skimage.measure.marching_cubes expects ordering (row, col, plane).167# We need to transpose the data:168volume = (labels == properties[region].label).transpose(1, 2, 0)169170verts_px, faces_px, _, _ = measure.marching_cubes_lewiner(volume, level=0, spacing=(1.0, 1.0, 1.0))171surface_area_pixels = measure.mesh_surface_area(verts_px, faces_px)172173verts_actual, faces_actual, _, _ = measure.marching_cubes_lewiner(volume, level=0, spacing=tuple(spacing))174surface_area_actual = measure.mesh_surface_area(verts_actual, faces_actual)175176print('Surface area\n')177print(' * Total pixels: {:0.2f}'.format(surface_area_pixels))178print(' * Actual: {:0.2f}'.format(surface_area_actual))179180fig = plt.figure(figsize=(10, 10))181ax = fig.add_subplot(111, projection='3d')182183mesh = Poly3DCollection(verts_px[faces_px])184mesh.set_edgecolor('black')185ax.add_collection3d(mesh)186187ax.set_xlabel('col')188ax.set_ylabel('row')189ax.set_zlabel('plane')190191min_pln, min_row, min_col, max_pln, max_row, max_col = properties[region].bbox192193ax.set_xlim(min_row, max_row)194ax.set_ylim(min_col, max_col)195ax.set_zlim(min_pln, max_pln)196197plt.tight_layout()198plt.show()199200return None201202203def results_from_part_1():204205data = io.imread("images/cells.tif")206207vmin, vmax = np.percentile(data, q=(0.5, 99.5))208rescaled = exposure.rescale_intensity(209data,210in_range=(vmin, vmax),211out_range=np.float32212)213214equalized = exposure.equalize_hist(data)215216return data, rescaled, equalized217218219