diff --git a/cortex/export/__init__.py b/cortex/export/__init__.py index 968980861..62a6cdcc5 100644 --- a/cortex/export/__init__.py +++ b/cortex/export/__init__.py @@ -1,13 +1,17 @@ from .save_views import save_3d_views from .panels import plot_panels -from .panels import params_flatmap_lateral_medial -from .panels import params_occipital_triple_view -from .panels import params_inflated_lateral_medial_ventral +from ._default_params import ( + params_inflatedless_lateral_medial_ventral, + params_flatmap_lateral_medial, + params_occipital_triple_view, + params_inflated_dorsal_lateral_medial_ventral, +) __all__ = [ - 'save_3d_views', - 'plot_panels', - 'params_flatmap_lateral_medial', - 'params_occipital_triple_view', - 'params_inflated_lateral_medial_ventral' + "save_3d_views", + "plot_panels", + "params_flatmap_lateral_medial", + "params_occipital_triple_view", + "params_inflatedless_lateral_medial_ventral", + "params_inflated_dorsal_lateral_medial_ventral", ] diff --git a/cortex/export/_default_params.py b/cortex/export/_default_params.py new file mode 100644 index 000000000..88844802b --- /dev/null +++ b/cortex/export/_default_params.py @@ -0,0 +1,228 @@ +params_flatmap_lateral_medial = { + "figsize": [16, 9], + "panels": [ + { + "extent": [0.000, 0.200, 1.000, 0.800], + "view": {"angle": "flatmap", "surface": "flatmap"}, + }, + { + "extent": [0.300, 0.000, 0.200, 0.200], + "view": { + "hemisphere": "left", + "angle": "medial_pivot", + "surface": "inflated", + }, + }, + { + "extent": [0.500, 0.000, 0.200, 0.200], + "view": { + "hemisphere": "right", + "angle": "medial_pivot", + "surface": "inflated", + }, + }, + { + "extent": [0.000, 0.000, 0.300, 0.300], + "view": { + "hemisphere": "left", + "angle": "lateral_pivot", + "surface": "inflated", + }, + }, + { + "extent": [0.700, 0.000, 0.300, 0.300], + "view": { + "hemisphere": "right", + "angle": "lateral_pivot", + "surface": "inflated", + }, + }, + ], +} + +params_occipital_triple_view = { + "figsize": [16, 9], + "panels": [ + { + "extent": [0.260, 0.000, 0.480, 1.000], + "view": { + "angle": "flatmap", + "surface": "flatmap", + "zoom": [0.250, 0.000, 0.500, 1.000], + }, + }, + { + "extent": [0.000, 0.000, 0.250, 0.333], + "view": { + "hemisphere": "left", + "angle": "bottom_pivot", + "surface": "inflated", + }, + }, + { + "extent": [0.000, 0.333, 0.250, 0.333], + "view": { + "hemisphere": "left", + "angle": "medial_pivot", + "surface": "inflated", + }, + }, + { + "extent": [0.000, 0.666, 0.250, 0.333], + "view": { + "hemisphere": "left", + "angle": "lateral_pivot", + "surface": "inflated", + }, + }, + { + "extent": [0.750, 0.000, 0.250, 0.333], + "view": { + "hemisphere": "right", + "angle": "bottom_pivot", + "surface": "inflated", + }, + }, + { + "extent": [0.750, 0.333, 0.250, 0.333], + "view": { + "hemisphere": "right", + "angle": "medial_pivot", + "surface": "inflated", + }, + }, + { + "extent": [0.750, 0.666, 0.250, 0.333], + "view": { + "hemisphere": "right", + "angle": "lateral_pivot", + "surface": "inflated", + }, + }, + ], +} + +params_inflatedless_lateral_medial_ventral = { + "figsize": [10, 9], + "panels": [ + { + "extent": [0.0, 0.0, 0.5, 1 / 3.0], + "view": { + "hemisphere": "left", + "angle": "bottom_pivot", + "surface": "inflated_less", + }, + }, + { + "extent": [0.000, 1 / 3.0, 0.5, 1 / 3.0], + "view": { + "hemisphere": "left", + "angle": "medial_pivot", + "surface": "inflated_less", + }, + }, + { + "extent": [0.000, 2 / 3.0, 0.5, 1 / 3.0], + "view": { + "hemisphere": "left", + "angle": "lateral_pivot", + "surface": "inflated_less", + }, + }, + { + "extent": [0.5, 0.0, 0.5, 1 / 3.0], + "view": { + "hemisphere": "right", + "angle": "bottom_pivot", + "surface": "inflated_less", + }, + }, + { + "extent": [0.5, 1 / 3.0, 0.5, 1 / 3.0], + "view": { + "hemisphere": "right", + "angle": "medial_pivot", + "surface": "inflated_less", + }, + }, + { + "extent": [0.5, 2 / 3.0, 0.5, 1 / 3.0], + "view": { + "hemisphere": "right", + "angle": "lateral_pivot", + "surface": "inflated_less", + }, + }, + ], +} + + +params_inflated_dorsal_lateral_medial_ventral = { + "figsize": [10, 10], + "panels": [ + { + "extent": [0.0, 0.0, 0.5, 0.20], + "view": { + "hemisphere": "left", + "angle": "bottom_pivot", + "surface": "inflated", + }, + }, + { + "extent": [0.000, 0.20, 0.5, 0.3], + "view": { + "hemisphere": "left", + "angle": "medial_pivot", + "surface": "inflated", + }, + }, + { + "extent": [0.000, 0.50, 0.5, 0.3], + "view": { + "hemisphere": "left", + "angle": "lateral_pivot", + "surface": "inflated", + }, + }, + { + "extent": [0.000, 0.80, 0.5, 0.20], + "view": { + "hemisphere": "left", + "angle": "top_pivot", + "surface": "inflated", + }, + }, + { + "extent": [0.5, 0.0, 0.5, 0.20], + "view": { + "hemisphere": "right", + "angle": "bottom_pivot", + "surface": "inflated", + }, + }, + { + "extent": [0.5, 0.20, 0.5, 0.30], + "view": { + "hemisphere": "right", + "angle": "medial_pivot", + "surface": "inflated", + }, + }, + { + "extent": [0.5, 0.50, 0.5, 0.30], + "view": { + "hemisphere": "right", + "angle": "lateral_pivot", + "surface": "inflated", + }, + }, + { + "extent": [0.5, 0.80, 0.5, 0.20], + "view": { + "hemisphere": "right", + "angle": "top_pivot", + "surface": "inflated", + }, + }, + ], +} diff --git a/cortex/export/panels.py b/cortex/export/panels.py index 80c9fdc74..3ccc0c22d 100644 --- a/cortex/export/panels.py +++ b/cortex/export/panels.py @@ -7,12 +7,25 @@ import matplotlib.pyplot as plt from .save_views import save_3d_views - - -def plot_panels(volume, panels, figsize=(16, 9), windowsize=(1600*4, 900*4), - save_name=None, sleep=10, - viewer_params=dict(labels_visible=[], - overlays_visible=['rois'])): +from ._default_params import ( + params_inflatedless_lateral_medial_ventral, + params_occipital_triple_view, + params_flatmap_lateral_medial, + params_inflated_dorsal_lateral_medial_ventral, +) + + +def plot_panels( + volume, + panels, + figsize=(16, 9), + windowsize=(1600 * 4, 900 * 4), + save_name=None, + sleep=10, + viewer_params=dict(labels_visible=[], overlays_visible=["rois"]), + interpolation="nearest", + layers=1, +): """Plot on the same figure a number of views, as defined by a list of panel Parameters @@ -52,6 +65,14 @@ def plot_panels(volume, panels, figsize=(16, 9), windowsize=(1600*4, 900*4), viewer_params: dict Parameters passed to the viewer. + interpolation: str + Interpolation used to visualize the data. Possible choices are "nearest", + "trilinear". (Default: "nearest"). + + layers: int + Number of layers between the white and pial surfaces to average prior to + plotting the data. (Default: 1). + Returns ------- fig : matplotlib.Figure @@ -64,37 +85,46 @@ def plot_panels(volume, panels, figsize=(16, 9), windowsize=(1600*4, 900*4), """ # list of couple of angles and surfaces - angles_and_surfaces = [(panel['view']['angle'], panel['view']['surface']) - for panel in panels] + angles_and_surfaces = [ + (panel["view"]["angle"], panel["view"]["surface"]) for panel in panels + ] # remove redundant couples, e.g. left and right angles_and_surfaces = list(set(angles_and_surfaces)) list_angles, list_surfaces = list(zip(*angles_and_surfaces)) # create all images temp_dir = tempfile.mkdtemp() - base_name = os.path.join(temp_dir, 'fig') - filenames = save_3d_views(volume, base_name, list_angles=list_angles, - list_surfaces=list_surfaces, trim=True, - size=windowsize, sleep=sleep, - viewer_params=viewer_params) + base_name = os.path.join(temp_dir, "fig") + filenames = save_3d_views( + volume, + base_name, + list_angles=list_angles, + list_surfaces=list_surfaces, + trim=True, + size=windowsize, + sleep=sleep, + viewer_params=viewer_params, + interpolation=interpolation, + layers=layers, + ) fig = plt.figure(figsize=figsize) for panel in panels: - + # load image - angle_and_surface = (panel['view']['angle'], panel['view']['surface']) + angle_and_surface = (panel["view"]["angle"], panel["view"]["surface"]) index = angles_and_surfaces.index(angle_and_surface) image = plt.imread(filenames[index]) # chose hemisphere - if 'hemisphere' in panel['view']: + if "hemisphere" in panel["view"]: left, right = np.split(image, [image.shape[1] // 2], axis=1) - if panel['view']['angle'] == 'medial_pivot': + if panel["view"]["angle"] == "medial_pivot": # inverted view, we need to swap left and right left, right = right, left - if panel['view']['hemisphere'] == 'left': + if panel["view"]["hemisphere"] == "left": image = left else: image = right @@ -104,25 +134,25 @@ def plot_panels(volume, panels, figsize=(16, 9), windowsize=(1600*4, 900*4), image = image[:, image.sum(axis=0).sum(axis=1) > 0] # zoom - if 'zoom' in panel['view']: - left, bottom, width, height = panel['view']['zoom'] + if "zoom" in panel["view"]: + left, bottom, width, height = panel["view"]["zoom"] left = int(left * image.shape[1]) width = int(width * image.shape[1]) bottom = int(bottom * image.shape[0]) height = int(height * image.shape[0]) - image = image[bottom:bottom + height] - image = image[:, left:left + width] + image = image[bottom : bottom + height] + image = image[:, left : left + width] # add ax and image - ax = plt.axes(panel['extent']) - ax.axis('off') + ax = plt.axes(panel["extent"]) + ax.axis("off") ax.imshow(image) # note that you might get a slightly different layout with `plt.show()` # since it might use a different backend if save_name is not None: - fig.savefig(save_name, bbox_inches='tight', dpi=100) - + fig.savefig(save_name, bbox_inches="tight", dpi=100) + # delete temporary directory try: shutil.rmtree(temp_dir) @@ -132,151 +162,3 @@ def plot_panels(volume, panels, figsize=(16, 9), windowsize=(1600*4, 900*4), raise return fig - - -params_flatmap_lateral_medial = { - 'figsize': [16, 9], - 'panels': [ - { - 'extent': [0.000, 0.200, 1.000, 0.800], - 'view': { - 'angle': 'flatmap', - 'surface': 'flatmap' - }, - }, - { - 'extent': [0.300, 0.000, 0.200, 0.200], - 'view': { - 'hemisphere': 'left', - 'angle': 'medial_pivot', - 'surface': 'inflated' - } - }, - { - 'extent': [0.500, 0.000, 0.200, 0.200], - 'view': { - 'hemisphere': 'right', - 'angle': 'medial_pivot', - 'surface': 'inflated' - }, - }, - { - 'extent': [0.000, 0.000, 0.300, 0.300], - 'view': { - 'hemisphere': 'left', - 'angle': 'lateral_pivot', - 'surface': 'inflated' - } - }, - { - 'extent': [0.700, 0.000, 0.300, 0.300], - 'view': { - 'hemisphere': 'right', - 'angle': 'lateral_pivot', - 'surface': 'inflated' - }, - }, - ] -} - -params_occipital_triple_view = { - 'figsize': [16, 9], - 'panels': [{ - 'extent': [0.260, 0.000, 0.480, 1.000], - 'view': { - 'angle': 'flatmap', - 'surface': 'flatmap', - 'zoom': [0.250, 0.000, 0.500, 1.000] - } - }, { - 'extent': [0.000, 0.000, 0.250, 0.333], - 'view': { - 'hemisphere': 'left', - 'angle': 'bottom_pivot', - 'surface': 'inflated' - } - }, { - 'extent': [0.000, 0.333, 0.250, 0.333], - 'view': { - 'hemisphere': 'left', - 'angle': 'medial_pivot', - 'surface': 'inflated' - } - }, { - 'extent': [0.000, 0.666, 0.250, 0.333], - 'view': { - 'hemisphere': 'left', - 'angle': 'lateral_pivot', - 'surface': 'inflated' - } - }, { - 'extent': [0.750, 0.000, 0.250, 0.333], - 'view': { - 'hemisphere': 'right', - 'angle': 'bottom_pivot', - 'surface': 'inflated' - } - }, { - 'extent': [0.750, 0.333, 0.250, 0.333], - 'view': { - 'hemisphere': 'right', - 'angle': 'medial_pivot', - 'surface': 'inflated' - } - }, { - 'extent': [0.750, 0.666, 0.250, 0.333], - 'view': { - 'hemisphere': 'right', - 'angle': 'lateral_pivot', - 'surface': 'inflated' - } - }] -} - -params_inflated_lateral_medial_ventral = { - 'figsize': [10, 9], - 'panels': [ - { - 'extent': [0.0, 0.0, 0.5, 1/3.], - 'view': { - 'hemisphere': 'left', - 'angle': 'bottom_pivot', - 'surface': 'inflated_less' - } - }, { - 'extent': [0.000, 1/3., 0.5, 1/3.], - 'view': { - 'hemisphere': 'left', - 'angle': 'medial_pivot', - 'surface': 'inflated_less' - } - }, { - 'extent': [0.000, 2/3., 0.5, 1/3.], - 'view': { - 'hemisphere': 'left', - 'angle': 'lateral_pivot', - 'surface': 'inflated_less' - } - }, { - 'extent': [0.5, 0.0, 0.5, 1/3.], - 'view': { - 'hemisphere': 'right', - 'angle': 'bottom_pivot', - 'surface': 'inflated_less' - } - }, { - 'extent': [0.5, 1/3., 0.5, 1/3.], - 'view': { - 'hemisphere': 'right', - 'angle': 'medial_pivot', - 'surface': 'inflated_less' - } - }, { - 'extent': [0.5, 2/3., 0.5, 1/3.], - 'view': { - 'hemisphere': 'right', - 'angle': 'lateral_pivot', - 'surface': 'inflated_less' - } - }] -} diff --git a/cortex/export/save_views.py b/cortex/export/save_views.py index 219f34f9b..9c319e4a5 100644 --- a/cortex/export/save_views.py +++ b/cortex/export/save_views.py @@ -6,11 +6,18 @@ file_pattern = "{base}_{view}_{surface}.png" -def save_3d_views(volume, base_name='fig', list_angles=['lateral_pivot'], - list_surfaces=['inflated'], - viewer_params=dict(labels_visible=[], - overlays_visible=['rois']), - size=(1024 * 4, 768 * 4), trim=True, sleep=10): +def save_3d_views( + volume, + base_name="fig", + list_angles=["lateral_pivot"], + list_surfaces=["inflated"], + viewer_params=dict(labels_visible=[], overlays_visible=["rois"]), + interpolation="nearest", + layers=1, + size=(1024 * 4, 768 * 4), + trim=True, + sleep=10, +): """Saves 3D views of `volume` under multiple specifications. Needs to be run on a system with a display (will launch webgl viewer). @@ -41,6 +48,14 @@ def save_3d_views(volume, base_name='fig', list_angles=['lateral_pivot'], viewer_params: dict Parameters passed to the viewer. + interpolation: str + Interpolation used to visualize the data. Possible choices are "nearest", + "trilinear". (Default: "nearest"). + + layers: int + Number of layers between the white and pial surfaces to average prior to + plotting the data. (Default: 1). + size: tuple of int Size of produced image (before trimming). @@ -63,12 +78,18 @@ def save_3d_views(volume, base_name='fig', list_angles=['lateral_pivot'], # Wait for the viewer to be loaded time.sleep(sleep) + # Add interpolation and layers params + interpolation_params = { + "surface.{subject}.sampler": interpolation, + "surface.{subject}.layers": layers + } + file_names = [] for view, surface in zip(list_angles, list_surfaces): if isinstance(view, str): - if view == 'flatmap' or surface == 'flatmap': + if view == "flatmap" or surface == "flatmap": # force flatmap correspondence - view = surface = 'flatmap' + view = surface = "flatmap" view_params = angle_view_params[view] else: view_params = view @@ -79,6 +100,7 @@ def save_3d_views(volume, base_name='fig', list_angles=['lateral_pivot'], # Combine view parameters this_view_params = default_view_params.copy() + this_view_params.update(interpolation_params) this_view_params.update(view_params) this_view_params.update(surface_params) print(this_view_params) @@ -89,17 +111,16 @@ def save_3d_views(volume, base_name='fig', list_angles=['lateral_pivot'], # wait for the view to have changed for _ in range(100): for k, v in this_view_params.items(): - k = k.format(subject=volume.subject) if '{subject}' in k else k + k = k.format(subject=volume.subject) if "{subject}" in k else k if handle.ui.get(k)[0] != v: - print('waiting for', k, handle.ui.get(k)[0], '->', v) + print("waiting for", k, handle.ui.get(k)[0], "->", v) time.sleep(0.1) continue break time.sleep(0.1) # Save image, store file_name - file_name = file_pattern.format(base=base_name, view=view, - surface=surface) + file_name = file_pattern.format(base=base_name, view=view, surface=surface) file_names.append(file_name) handle.getImage(file_name, size) @@ -112,6 +133,7 @@ def save_3d_views(volume, base_name='fig', list_angles=['lateral_pivot'], if trim: try: import subprocess + subprocess.call(["convert", "-trim", file_name, file_name]) except Exception as e: print(str(e)) @@ -123,87 +145,66 @@ def save_3d_views(volume, base_name='fig', list_angles=['lateral_pivot'], handle.server.stop() except Exception as e: print(str(e)) - print('Could not close viewer.') + print("Could not close viewer.") return file_names default_view_params = { - 'camera.azimuth': 45, - 'camera.altitude': 75, - 'camera.target': [0, 0, 0], - 'surface.{subject}.unfold': 0, - 'surface.{subject}.pivot': 0, - 'surface.{subject}.shift': 0, - 'surface.{subject}.specularity': 0, + "camera.azimuth": 45, + "camera.altitude": 75, + "camera.target": [0, 0, 0], + "surface.{subject}.unfold": 0, + "surface.{subject}.pivot": 0, + "surface.{subject}.shift": 0, + "surface.{subject}.specularity": 0, } angle_view_params = { - 'left': { - 'camera.azimuth': 90, - 'camera.altitude': 90, - }, - 'right': { - 'camera.azimuth': 270, - 'camera.altitude': 90, - }, - 'front': { - 'camera.azimuth': 0, - 'camera.altitude': 90, - }, - 'back': { - 'camera.azimuth': 180, - 'camera.altitude': 90, + "left": {"camera.azimuth": 90, "camera.altitude": 90,}, + "right": {"camera.azimuth": 270, "camera.altitude": 90,}, + "front": {"camera.azimuth": 0, "camera.altitude": 90,}, + "back": {"camera.azimuth": 180, "camera.altitude": 90,}, + "top": {"camera.azimuth": 180, "camera.altitude": 0,}, + "bottom": {"camera.azimuth": 0, "camera.altitude": 180,}, + "flatmap": { + "camera.azimuth": 180, + "camera.altitude": 0, + "surface.{subject}.pivot": 180, + "surface.{subject}.shift": 0, }, - 'top': { - 'camera.azimuth': 180, - 'camera.altitude': 0, + "medial_pivot": { + "camera.azimuth": 0, + "camera.altitude": 90, + "surface.{subject}.pivot": 180, + "surface.{subject}.shift": 10, }, - 'bottom': { - 'camera.azimuth': 0, - 'camera.altitude': 180, + "lateral_pivot": { + "camera.azimuth": 180, + "camera.altitude": 90, + "surface.{subject}.pivot": 180, + "surface.{subject}.shift": 10, }, - 'flatmap': { - 'camera.azimuth': 180, - 'camera.altitude': 0, - 'surface.{subject}.pivot': 180, - 'surface.{subject}.shift': 0, + "bottom_pivot": { + "camera.azimuth": 180, + "camera.altitude": 180, + "camera.target": [0, -100, 0], + "surface.{subject}.pivot": 180, + "surface.{subject}.shift": 10, }, - 'medial_pivot': { - 'camera.azimuth': 0, - 'camera.altitude': 90, - 'surface.{subject}.pivot': 180, - 'surface.{subject}.shift': 10, - }, - 'lateral_pivot': { - 'camera.azimuth': 180, - 'camera.altitude': 90, - 'surface.{subject}.pivot': 180, - 'surface.{subject}.shift': 10, - }, - 'bottom_pivot': { - 'camera.azimuth': 180, - 'camera.altitude': 180, - 'camera.target': [0, -100, 0], - 'surface.{subject}.pivot': 180, - 'surface.{subject}.shift': 10, + "top_pivot": { + "camera.azimuth": 180, + "camera.altitude": 0, + "camera.target": [0, -100, 0], + "surface.{subject}.pivot": 180, + "surface.{subject}.shift": 10, }, } unfold_view_params = { - 'fiducial': { - 'surface.{subject}.unfold': 0, - }, - 'inflated_less': { - 'surface.{subject}.unfold': 0.25, - }, - 'inflated': { - 'surface.{subject}.unfold': 0.5, - }, - 'inflated_cut': { - 'surface.{subject}.unfold': 0.501, - }, - 'flatmap': { - 'surface.{subject}.unfold': 1, - }, + "fiducial": {"surface.{subject}.unfold": 0,}, + "inflated_less": {"surface.{subject}.unfold": 0.25,}, + "inflated": {"surface.{subject}.unfold": 0.5,}, + "inflated_cut": {"surface.{subject}.unfold": 0.501,}, + "flatmap": {"surface.{subject}.unfold": 1,}, }