Beispiel #1
0
    def export_gj_connectivity(self, phase: SimPhase,
                               conf: SimConfExportPlotCells) -> None:
        '''
        Plot the **gap junction connectivity network** (i.e., graph of all gap
        junctions connecting cell membranes) for the cell cluster.

        This plot is irrespective of time step.
        '''

        # Prepare to export the current plot.
        self._export_prep(phase)

        fig = pyplot.figure()
        ax_x = pyplot.subplot(111)

        if phase.p.showCells:
            base_points = mathunit.upscale_coordinates(phase.cells.cell_verts)
            col_cells = PolyCollection(base_points,
                                       facecolors='k',
                                       edgecolors='none')
            col_cells.set_alpha(0.3)
            ax_x.add_collection(col_cells)

        connects = mathunit.upscale_coordinates(phase.cells.nn_edges)
        collection = LineCollection(connects, linewidths=1.0, color='b')
        ax_x.add_collection(collection)
        pyplot.axis('equal')
        pyplot.axis(phase.cache.upscaled.extent)

        ax_x.set_xlabel('Spatial x [um]')
        ax_x.set_ylabel('Spatial y [um')
        ax_x.set_title('Cell Connectivity Network')

        # Export this plot to disk and/or display.
        self._export(phase=phase, basename='gj_connectivity_network')
Beispiel #2
0
    def _layer_first(self) -> None:

        # Localize attributes for brevity.
        cells = self._phase.cells

        # Ouiver plot of all vector components plotted for this time step. See
        # the matplotlib.quiver.quiver() docstring for further details.
        self._quiver_plot = self._visual.axes.quiver(
            # Positional arguments. See
            # LayerCellsFieldQuiverCells._layer_first() for further discussion.

            # Upscaled X and Y coordinates of all cell membrane midpoints.
            mathunit.upscale_coordinates(
                cells.cell_centres[:, 0][cells.mem_to_cells]),
            mathunit.upscale_coordinates(
                cells.cell_centres[:, 1][cells.mem_to_cells]),

            # X and Y components of this vector field spatially situated at cell
            # membrane midpoints extending to cell centres for this time step.
            self._field_time_x,
            self._field_time_y,

            # Keyword arguments. All remaining arguments *MUST* be passed as
            # keyword arguments.

            # Matplotlib-specific color code of all vector arrows.
            color=self._phase.p.vcolor,

            # Number of data units per arrow length unit.
            scale=mathunit.upscale_coordinates(self._phase.p.wsx * 0.8),

            # Z-order of this plot with respect to other artists.
            zorder=self._zorder,
        )
Beispiel #3
0
    def _layer_first(self) -> None:
        '''
        Simulate and layer streamlines of this vector field for the first time
        step onto the figure axes of the current plot or animation.
        '''

        # Arrays of the upscaled X and Y coordinates of all grid spaces.
        grid_x = mathunit.upscale_coordinates(self._phase.cells.X)
        grid_y = mathunit.upscale_coordinates(self._phase.cells.Y)

        # Vector field whose X and Y components are spatially situated at grid
        # space centres.
        field = self._field.times_grids_centre

        # Arrays of all magnitudes *AND* normalized X and Y components of this
        # vector field for this time step.
        field_magnitudes = field.magnitudes[self._visual.time_step]
        field_unit_x = field.unit_x[self._visual.time_step]
        field_unit_y = field.unit_y[self._visual.time_step]

        # Maximum magnitude of this vector field for this time step.
        field_magnitude_max = np.max(field_magnitudes)

        # One-dimensional array of the visual widths of all vectors of this
        # vector field for this time step.
        streamlines_width = (
            3.0 * field_magnitudes / field_magnitude_max) + 0.5

        # Streamplot of all streamlines plotted for this time step. See the
        # matplotlib.streamplot.streamplot() docstring for further details.
        self._stream_plot = self._visual.axes.streamplot(
            # X and Y coordinates of all grid points.
            x=grid_x,
            y=grid_y,

            # X and Y normalized components of this vector field.
            u=field_unit_x,
            v=field_unit_y,

            # Matplotlib-specific color code of all streamlines.
            color=self._phase.p.vcolor,

            # Density of streamlines in both the X and Y dimensions.
            density=self._phase.p.stream_density,

            # Line widths of all streamlines.
            linewidth=streamlines_width,

            #FIXME: For still frames, an arrow size of about 5.0 is best; for
            #rendered video, these blow up and a size of 3.0 is better. Not that
            #this is important enough to ever get to it. :)

            # Factor by which to upscale the size of all streamline arrowheads.
            # arrowsize=3.0,

            # Z-order of these streamlines with respect to other artists.
            zorder=self._zorder,
        )
Beispiel #4
0
    def grids_centre_y(self) -> ndarray:
        '''
        One-dimensional Numpy array of the upscaled X coordinates of all
        environmental grid space centres for this cell cluster.
        '''

        return mathunit.upscale_coordinates(self._phase.cells.xypts[:, 1])
Beispiel #5
0
    def export_diffusion_extra(self, phase: SimPhase,
                               conf: SimConfExportPlotCells) -> None:
        '''
        Plot all logarithm-scaled extracellular diffusion weights for the
        environment at the last time step.
        '''

        # Prepare to export the electric plot.
        self._export_prep(phase)

        fig = pyplot.figure()
        ax99 = pyplot.subplot(111)
        pyplot.imshow(
            np.log10(phase.sim.D_env_weight.reshape(phase.cells.X.shape)),
            origin='lower',
            extent=phase.cache.upscaled.extent,
            cmap=phase.p.background_cm,
        )
        pyplot.colorbar()

        cell_edges_flat = mathunit.upscale_coordinates(
            phase.cells.mem_edges_flat)
        coll = LineCollection(cell_edges_flat, colors='k')
        coll.set_alpha(1.0)
        ax99.add_collection(coll)

        pyplot.title('Logarithm of Environmental Diffusion Weight Matrix')

        # Export this plot to disk and/or display.
        self._export(phase=phase, basename='env_diffusion_weights')
Beispiel #6
0
    def prep(self, *args, **kwargs) -> None:

        # Prepare our superclass.
        super().prep(*args, **kwargs)

        # Upscale all cell radii.
        self._cells_radius = mathunit.upscale_coordinates(
            self._phase.cells.R[self._phase.cells.mem_to_cells])
Beispiel #7
0
    def cells_centre_y(self) -> ndarray:
        '''
        One-dimensional Numpy array of the upscaled Y coordinates of all cell
        centres for this cell cluster.
        '''

        return mathunit.upscale_coordinates(self._phase.cells.cell_centres[:,
                                                                           1])
Beispiel #8
0
    def deform_total(self) -> VectorFieldCellsCache:
        '''
        Vector field cache of all upscaled **total cellular displacements**
        (i.e., summations of all cellular deformations due to galvanotropic and
        osmotic pressure body forces) over all sampled time steps of the current
        simulation phase, originally spatially situated at cell centres.

        For readability of units in exported visuals (e.g., plots), this cache
        additionally upscales these displacements from meters to micrometers.
        '''

        return VectorFieldCellsCache(
            x=VectorCellsCache(phase=self._phase,
                               times_cells_centre=mathunit.upscale_coordinates(
                                   self._phase.sim.dx_cell_time)),
            y=VectorCellsCache(phase=self._phase,
                               times_cells_centre=mathunit.upscale_coordinates(
                                   self._phase.sim.dy_cell_time)),
        )
Beispiel #9
0
    def _layer_first(self) -> None:

        # For the 0-based index and 2-tuple of X and Y coordinates of the center
        # of each cell, display this index centered at these coordinates.
        for cell_index, cell_center in enumerate(
                self._phase.cells.cell_centres):
            self._visual.axes.text(
                # Text to be displayed.
                s=cell_index,

                # X and Y coordinates to display this text at.
                x=mathunit.upscale_coordinates(cell_center[0]),
                y=mathunit.upscale_coordinates(cell_center[1]),

                # Alignment of this text at these coordinates.
                horizontalalignment='center',
                verticalalignment='center',

                # Z-order of this text with respect to other artists.
                zorder=self._zorder,
            )
Beispiel #10
0
    def times_cells_vertices_coords(self) -> ndarray:
        '''
        Four-dimensional Numpy array of the upscaled coordinates of all cell
        membrane vertices for this cell cluster over all time steps under the
        assumption that these vertices are deformed over these time steps.

        See Also
        ----------
        :attrs:`betse.science.sim.Simulator.cell_verts_time`
            Further details.
        '''

        return mathunit.upscale_coordinates(self._phase.sim.cell_verts_time)
Beispiel #11
0
    def cells_vertices_coords(self) -> ndarray:
        '''
        Three-dimensional Numpy array of the upscaled coordinates of all cell
        membrane vertices for this cell cluster under the assumption that these
        vertices are *not* deformed at any time step and hence are fixed over
        all time steps.

        See Also
        ----------
        :attrs:`betse.science.cells.Cells.cell_verts`
            Further details.
        '''

        return mathunit.upscale_coordinates(self._phase.cells.cell_verts)
Beispiel #12
0
    def _layer_first_color_mappables(self) -> IterableTypes:

        # X and Y coordinates of all cell membrane midpoints.
        membranes_midpoint_x = mathunit.upscale_coordinates(
            self._phase.cells.mem_mids_flat[:,0])
        membranes_midpoint_y = mathunit.upscale_coordinates(
            self._phase.cells.mem_mids_flat[:,1])

        # Membrane midpoint-centred data for this time step.
        membranes_midpoint_data = self._vector.times_membranes_midpoint[
            self._visual.time_step]

        # Gouraud-shaded triangulation mesh for this cell cluster, computed from
        # the Delaunay hull of the non-triangular centers of these regions.
        self._cluster_tri_mesh = self._visual.axes.tripcolor(
            # Positional arguments. Thanks to internal flaws in the
            # matplotlib.tri.tripcolor() function parsing arguments passed
            # to the matplotlib.axes.tripcolor() method called here, the first
            # four arguments *MUST* be passed as positional arguments.
            membranes_midpoint_x, membranes_midpoint_y, membranes_midpoint_data,

            # Keyword arguments. All remaining arguments *MUST* be passed as
            # keyword arguments.
            shading='gouraud',
            vmin=self._visual.color_min,
            vmax=self._visual.color_max,

            # Colormap converting input data values into output color values.
            cmap=self._visual.colormap,

            # Z-order of this mesh with respect to other artists.
            zorder=self._zorder,
        )

        # Map this triangulation mesh onto the figure colorbar, returned as a
        # 1-tuple to comply with the superclass API.
        return (self._cluster_tri_mesh,)
Beispiel #13
0
    def export_cell_series(self, phase: SimPhase,
                           conf: SimConfExportCSV) -> None:
        '''
        Save a plaintext file in comma-separated value (CSV) format containing
        several cell-specific time series (e.g., ion concentrations, membrane
        voltages, voltage-gated ion channel pump rates) for the single cell
        indexed ``plot cell index`` in the current simulation configuration.
        '''

        # 0-based index of the cell to serialize time data for.
        cell_index = phase.p.visual.single_cell_index

        # Sequence of key-value pairs containing all simulation data to be
        # exported for this cell, suitable for passing to the
        # OrderedArgsDict.__init__() method calleb below.
        csv_column_name_values = []

        # One-dimensional Numpy array of null data of the required length,
        # suitable for use as CSV column data for columns whose corresponding
        # simulation feature (e.g., deformations) is disabled.
        column_data_empty = np.zeros(len(phase.sim.time))

        # ................{ TIME STEPS                      }..................
        csv_column_name_values.extend(('time_s', phase.sim.time))

        # ................{ VMEM                            }..................
        csv_column_name_values.extend(
            ('Vmem_mV', self._get_cell_times_vmems(phase)))

        # ................{ VMEM ~ goldman                  }..................
        if phase.p.GHK_calc:
            vm_goldman = mathunit.upscale_units_milli([
                vm_GHK_time_cells[cell_index]
                for vm_GHK_time_cells in phase.sim.vm_GHK_time
            ])
        else:
            vm_goldman = column_data_empty

        csv_column_name_values.extend(('Goldman_Vmem_mV', vm_goldman))

        # ................{ Na K PUMP RATE                  }..................
        if phase.p.is_ecm:
            pump_rate = [
                pump_array[phase.cells.cell_to_mems[cell_index][0]]
                for pump_array in phase.sim.rate_NaKATP_time
            ]
        else:
            pump_rate = [
                pump_array[cell_index]
                for pump_array in phase.sim.rate_NaKATP_time
            ]

        csv_column_name_values.extend(('NaK-ATPase_Rate_mol/m2s', pump_rate))

        # ................{ ION CONCENTRATIONS              }..................
        # Create the header starting with cell concentrations.
        for i in range(len(phase.sim.ionlabel)):
            csv_column_name = 'cell_{}_mmol/L'.format(phase.sim.ionlabel[i])
            cc_m = [arr[i][cell_index] for arr in phase.sim.cc_time]
            csv_column_name_values.extend((csv_column_name, cc_m))

        # ................{ MEMBRANE PERMEABILITIES         }..................
        # Create the header starting with membrane permeabilities.
        for i in range(len(phase.sim.ionlabel)):
            if phase.p.is_ecm:
                dd_m = [
                    arr[i][phase.cells.cell_to_mems[cell_index][0]]
                    for arr in phase.sim.dd_time
                ]
            else:
                dd_m = [arr[i][cell_index] for arr in phase.sim.dd_time]

            csv_column_name = 'Dm_{}_m2/s'.format(phase.sim.ionlabel[i])
            csv_column_name_values.extend((csv_column_name, dd_m))

        # ................{ TRANSMEMBRANE CURRENTS          }..................
        if phase.p.is_ecm:
            Imem = [
                memArray[phase.cells.cell_to_mems[cell_index][0]]
                for memArray in phase.sim.I_mem_time
            ]
        else:
            Imem = [memArray[cell_index] for memArray in phase.sim.I_mem_time]

        csv_column_name_values.extend(('I_A/m2', Imem))

        # ................{ HYDROSTATIC PRESSURE            }..................
        p_hydro = [arr[cell_index] for arr in phase.sim.P_cells_time]
        csv_column_name_values.extend(('HydroP_Pa', p_hydro))

        # ................{ OSMOTIC PRESSURE                }..................
        if phase.p.deform_osmo:
            p_osmo = [arr[cell_index] for arr in phase.sim.osmo_P_delta_time]
        else:
            p_osmo = column_data_empty

        csv_column_name_values.extend(('OsmoP_Pa', p_osmo))

        # ................{ DEFORMATION                     }..................
        if (phase.p.deformation and phase.kind is SimPhaseKind.SIM):
            # Extract time-series deformation data for the plot cell:
            dx = nparray.from_iterable(
                [arr[cell_index] for arr in phase.sim.dx_cell_time])
            dy = nparray.from_iterable(
                [arr[cell_index] for arr in phase.sim.dy_cell_time])

            # Get the total magnitude.
            disp = mathunit.upscale_coordinates(np.sqrt(dx**2 + dy**2))
        else:
            disp = column_data_empty

        csv_column_name_values.extend(('Displacement_um', disp))

        # ................{ CSV EXPORT                      }..................
        # Ordered dictionary mapping from CSV column names to data arrays.
        csv_column_name_to_values = OrderedArgsDict(*csv_column_name_values)

        # Export this data to this CSV file.
        npcsv.write_csv(
            filename=self._get_csv_filename(
                phase=phase, basename_sans_filetype='ExportedData'),
            column_name_to_values=csv_column_name_to_values,
        )
Beispiel #14
0
    def _export_cells_times_data(
        self,
        phase: SimPhase,
        cells_times_data: SequenceTypes,
        csv_column_name: str,
        csv_dir_basename: str,
        csv_basename_prefix: str,
    ) -> None:
        '''
        Save one plaintext file in comma-separated value (CSV) format
        containing arbitrary simulation data spatially situated at cell centres
        for each sampled time step of the current simulation phase.

        Parameters
        ----------
        phase : SimPhase
            Current simulation phase.
        cells_times_data : ndarray
            Two-dimensional Numpy array of arbitrary simulation data spatially
            situated at the centres of all cells for all sampled time steps.
        csv_column_name : str
            Name of the column containing this data in all CSV-formatted files
            exported by this method.
        csv_dir_basename : str
            Basename of the directory containing all CSV-formatted files
            exported by this method.
        csv_basename_prefix : str
            Substring prefixing the basenames of all CSV-formatted files
            exported by this method.
        '''

        # Absolute pathname of the directory containing all CSV files
        # specifically exported by this method.
        csv_dirname = pathnames.join(phase.export_dirname, csv_dir_basename)

        # One-dimensional Numpy arrays of the X and Y coordinates
        # (respectively) of the centres of all cells.
        cell_centres_x = mathunit.upscale_coordinates(
            phase.cells.cell_centres[:, 0])
        cell_centres_y = mathunit.upscale_coordinates(
            phase.cells.cell_centres[:, 1])

        # For the 0-based index of each sampled time step...
        for time_step in range(len(phase.sim.time)):
            # Basename of the CSV-formatted file exported for this time step,
            # excluding suffixing "."-prefixed filetype.
            csv_basename_sans_filetype = '{}{}'.format(csv_basename_prefix,
                                                       time_step)

            # Absolute filename of this CSV file.
            csv_filename = self._get_csv_filename(
                phase=phase,
                basename_sans_filetype=csv_basename_sans_filetype,
                dirname=csv_dirname,
            )

            # Ordered dictionary mapping from CSV column names to data arrays.
            csv_column_name_to_values = OrderedArgsDict(
                'x [um]',
                cell_centres_x,
                'y [um]',
                cell_centres_y,
                csv_column_name,
                cells_times_data[time_step],
            )

            # Export this data to this CSV file.
            npcsv.write_csv(filename=csv_filename,
                            column_name_to_values=csv_column_name_to_values)
Beispiel #15
0
    def export_tissue_cuts(self, phase: SimPhase,
                           conf: SimConfExportPlotCells) -> None:
        '''
        Plot a **tissue and cut profile tessellation** (i.e., tiled mosaic of
        all cells spatially subdivided into tissue and cut profile regions such
        that all cells in the same region share the same arbitrary color) for
        the cell cluster.

        This plot is irrespective of time step.
        '''

        # Prepare to export the current plot.
        self._export_prep(phase)

        # Localize frequently accessed fields for convenience.
        p = phase.p
        dyna = phase.dyna
        cells = phase.cells
        colormap = phase.p.background_cm

        col_dic = {}
        cb_ticks = []
        cb_tick_labels = []

        # Ordered dictionary mapping from the name of each tissue and cut
        # profile to a one-dimensional Numpy array of the 0-based indices of
        # all cells owned by this profile.
        #
        # Note that order is absolutely significant. The first tissue profile
        # is a pseudo-tissue defining the cell cluster itself. If order were
        # *NOT* preserved here, this tissue would be assigned an arbitrary
        # z-order, in which case all tissues assigned smaller z-orders would be
        # entirely obscured by that pseudo-tissue covering the cell cluster.
        profile_name_to_cells_index = OrderedDict()

        fig = pyplot.figure()
        ax = pyplot.subplot(111)

        # For the name and object encapsulating each tissue profile...
        for tissue_name, _ in dyna.tissue_name_to_profile.items():
            # One-dimensional Numpy array of the indices of all tissue cells.
            tissue_cells_index = dyna.cell_target_inds[tissue_name]

            # If this tissue contains no cells, skip to the next tissue.
            if not len(tissue_cells_index):
                logs.log_warning('Tissue "%s" contains no cells.', tissue_name)
                continue

            # Else, tissue contains one or more cells. Map this tissue to these
            # indices (for subsequent lookup).
            profile_name_to_cells_index[tissue_name] = tissue_cells_index

        #FIXME: The "p.plot_cutlines" boolean is only ever leveraged here and
        #thus is arguably extraneous. Consider refactoring as follows:
        #
        #* Remove the "p.plot_cutlines" boolean and corresponding
        #  YAML-formetted default configuration option.
        #* Split the existing "tissue_cuts" plot type in the "cell cluster
        #  pipeline" into the following two types:
        #  * "tissue", unconditionally plotting *ONLY* tissue profiles.
        #  * "tissue_cuts", unconditionally plotting both tissue and cut
        #    profiles.
        #* Define a new private _export_profiles() method as follows:
        #      @type_check
        #      _export_profiles(
        #          self,
        #          conf: SimConfExportPlotCells,
        #          is_tissue: bool,
        #          is_cuts: bool
        #       ) -> None:
        #* Implement export_tissue() to call _export_profiles() as:
        #    self._export_profiles(
        #        self,
        #        conf=conf,
        #        is_tissue=True,
        #        is_cuts=False,
        #    )
        #* Implement export_tissue_cuts() similarly.

        # If plotting cut profiles as well *AND* the cutting event is
        # enabled...
        if p.plot_cutlines and dyna.event_cut is not None:
            # For the name and object encapsulating each cut profile...
            for cut_name, cut_profile in dyna.cut_name_to_profile.items():
                # Map this cut to the indices of all cells cut by this profile.
                profile_name_to_cells_index[cut_name] = (
                    cut_profile.picker.pick_cells(cells=cells, p=p))

        # Minimum and maximum 0-based integers uniquely identifying the first
        # and last tissue and cut profile (respoctively), localized for
        # ordering purposes in the colorbar legend.
        profile_zorder = 0
        profile_zorder_max = len(profile_name_to_cells_index)

        # For the name and one-dimensional Numpy array of the 0-based indices
        # of all cells in each tissue and/or cut profile...
        for profile_name, profile_cells_index in (
                profile_name_to_cells_index.items()):
            # logs.log_debug('Plotting tissue "%s"...', profile_name)
            profile_zorder += 1

            profile_points = mathunit.upscale_coordinates(
                cells.cell_verts[profile_cells_index])

            z = np.zeros(len(profile_points))
            z[:] = profile_zorder

            col_dic[profile_name] = PolyCollection(profile_points,
                                                   array=z,
                                                   cmap=colormap,
                                                   edgecolors='none')
            col_dic[profile_name].set_clim(0, profile_zorder_max)

            # col_dic[profile_name].set_alpha(0.8)
            col_dic[profile_name].set_zorder(profile_zorder)
            ax.add_collection(col_dic[profile_name])

            # Add this profile name to the colour legend.
            cb_ticks.append(profile_zorder)
            cb_tick_labels.append(profile_name)

        # logs.log_debug('Plotting colorbar ticks: %r', cb_ticks)
        # logs.log_debug('Plotting colorbar tick labels: %r', cb_tick_labels)

        ax_cb = None
        if dyna.tissue_name_to_profile:
            # Name of the first tissue profile.
            tissue_first_name = iterget.get_item_first(
                dyna.tissue_name_to_profile.keys())

            # Color mappable associated with this tissue profile, guaranteed in
            # this case to be a "PolyCollection" instance.
            tissue_first_mappable = col_dic[tissue_first_name]

            ax_cb = fig.colorbar(tissue_first_mappable, ax=ax, ticks=cb_ticks)
            ax_cb.ax.set_yticklabels(cb_tick_labels)

        if p.visual.is_show_cell_indices:
            for i, cll in enumerate(cells.cell_centres):
                ax.text(p.um * cll[0],
                        p.um * cll[1],
                        i,
                        ha='center',
                        va='center',
                        zorder=20)

        ax.set_xlabel('Spatial Distance [um]')
        ax.set_ylabel('Spatial Distance [um]')
        ax.set_title('Cell Cluster')

        ax.axis('equal')
        ax.axis(phase.cache.upscaled.extent)

        # Export this plot to disk and/or display.
        self._export(phase=phase, basename='cluster_mosaic')