示例#1
0
文件: simres.py 项目: dietmarw/FCSys
        def _ystrings(ynames, ylabel, yunit, legends):
            """Generate a y-axis label and set of legend entries.
            """
            if ynames:
                if ylabel is None: # Try to create a suitable axis label.
                    descriptions = self.get_description(ynames)
                    # If the descriptions are the same, label the y axis with
                    # the 1st one.
                    ylabel = descriptions[0]
                    if len(set(descriptions)) <> 1:
                        print("The y-axis variable descriptions are not all "
                              "the same.  The first has been used.  Please "
                              "provide the proper name via ylabel1 or ylabel2.")
                if legends == []:
                    legends = ynames
                if incl_prefix:
                    legends = [self.fbase + ': ' + leg for leg in legends]
                if suffix:
                    legends = ([leg + ' (%s)' % suffix for leg in legends]
                               if use_paren else
                               [leg + suffix for leg in legends])
                assert len(set(self.get_dimension(ynames))) == 1, \
                    "The variables on the y-axis do not have the same physical dimension."
                if yunit is None:
                    # Use the unit of the 1st variable.
                    yunit = self.get_unit(ynames[0])
                if ylabel <> "":
                    ylabel = label_number(ylabel, yunit)

            return ylabel, yunit, legends
示例#2
0
        def _ystrings(ynames, ylabel, yunit, legends):
            """Generate a y-axis label and set of legend entries.
            """
            if ynames:
                if ylabel is None:  # Try to create a suitable axis label.
                    descriptions = self.get_description(ynames)
                    # If the descriptions are the same, label the y axis with
                    # the 1st one.
                    ylabel = descriptions[0]
                    if len(set(descriptions)) <> 1:
                        print(
                            "The y-axis variable descriptions are not all "
                            "the same.  The first has been used.  Please "
                            "provide the proper name via ylabel1 or ylabel2.")
                if legends == []:
                    legends = ynames
                if incl_prefix:
                    legends = [self.fbase + ': ' + leg for leg in legends]
                if suffix:
                    legends = ([leg + ' (%s)' % suffix
                                for leg in legends] if use_paren else
                               [leg + suffix for leg in legends])
                assert len(set(self.get_dimension(ynames))) == 1, \
                    "The variables on the y-axis do not have the same physical dimension."
                if yunit is None:
                    # Use the unit of the 1st variable.
                    yunit = self.get_unit(ynames[0])
                if ylabel <> "":
                    ylabel = label_number(ylabel, yunit)

            return ylabel, yunit, legends
示例#3
0
    def currdenfig(self, title=None, times=[0], z_index=0, leg_kwargs={},
                   **kwargs):
        """Plot current densities of the cell segments at times.

        **Arguments:**

        - *title*: Title for the figure

        - *times*: List of times at which the data should be sampled

             If multiple times are given, then subfigures will be generated.

        - *z_index*: z-index at which the current densities are taken

        - *leg_kwargs*: Dictionary of keyword arguments for
          :meth:`matplotlib.pyplot.legend`

             If *leg_kwargs* is *None*, then no legend will be shown.

        - *\*\*kwargs*: Additional arguments for  :meth:`barfig`
        """
        # Process the arguments.
        xlabel = kwargs.pop('xlabel', 'y-axis index (inlet to outlet)')
        name_template = self.cell + ('iprimeprime_seg[%i, ' + '%i]'
            % (z_index+1))
        #description = self.get_description(name_template % 1)
        #unit = self.get_unit(name_template % 1)
        unit = self.get_unit(name_template % 1)
        #ylabel = kwargs.pop('ylabel', label_number(description, unit))
        ylabel = kwargs.pop('ylabel', label_number("Current density", unit))

        # Create the plot.
        ax = self.barfig(names=[name_template % (i_y+1) for i_y in range(1)],
                         times=times, xlabel=xlabel, ylabel=ylabel,
                         leg_kwargs=None, **kwargs)
        for a, time in zip(ax, times):
            a.axhline(self.get_values('cell.iprimeprime', time),
                      linestyle='--', color='k', label='Entire cell')

        # Decorate.
        if title is None:
            if self.n_z == 1:
                plt.title("Current Distribution of Cell Segments")
            else:
                plt.title("Current Distribution of Cell Segments\n"
                          "z-axis index %i (of %i)" % (z_index+1, self.n_z))
        if leg_kwargs is not None:
            loc = leg_kwargs.pop('loc', 'best')
            if len(ax) == 1:
                ax[0].legend(loc=loc, **leg_kwargs)
            else:
                plt.figlegend(ax[0].lines, **leg_kwargs)
示例#4
0
文件: simres.py 项目: dietmarw/FCSys
    def plot(self, ynames1=[], ylabel1=None, yunit1=None, legends1=[],
             leg1_kwargs={'loc': 'best'}, ax1=None,
             ynames2=[], ylabel2=None, yunit2=None, legends2=[],
             leg2_kwargs={'loc': 'best'}, ax2=None,
             xname='Time', xlabel=None, xunit=None,
             title=None, label="xy", incl_prefix=False, suffix=None,
             use_paren=True, **kwargs):
        r"""Plot data as points and/or curves in 2D Cartesian coordinates.

        A new figure is created if necessary.

        **Arguments:**

        - *ynames1*: Names of variables for the primary y axis

             If any names are invalid, then they will be skipped.

        - *ylabel1*: Label for the primary y axis

             If *ylabel1* is *None* (default) and all of the variables have the
             same Modelica_ description string, then the common description
             will be used.  Use '' for no label.

        - *yunit1*: String indicating the unit for the primary y-axis (see note
          for *xunit*)

             If *yunit1* is *None*, the Modelica_ *displayUnit* of the first
             entry of *ynames1* or the default unit (from *fcres.ini*) based on
             that variable's dimension will be used (in decreasing priority).

             .. Note:: Dimension checking is not currently performed, so it is
                important to ensure that a proper unit is chosen.

        - *legends1*: List of legend entries for variables assigned to the
          primary y axis

             If *legends1* is an empty list ([]), ynames1 will be used.  If
             *legends1* is *None* and all of the variables on the primary axis
             have the same unit, then no legend will be shown.

        - *leg1_kwargs*: Dictionary of keyword arguments for the primary legend

        - *ax1*: Primary y axes

             If *ax1* is not provided, then axes will be created in a new
             figure.

        - *ynames2*, *ylabel2*, *yunit2*, *legends2*, *leg2_kwargs*, and *ax2*:
          Similar to *ynames1*, *ylabel1*, *yunit1*, *legends1*, *leg1_kwargs*,
          and *ax1* but for the secondary y axis

        - *xname*: Name of the x-axis data

        - *xlabel*: Label for the x axis

             If *xlabel* is *None* (default), the variable's Modelica_
             description string will be applied.  Use '' for no label.

        - *xunit*: String indicating the unit for the x axis  (see note
          for *yunit1*)

             If *xunit* is *None*, the Modelica_ variable's *displayUnit* or
             the default unit (from *fcres.ini*) based on the variable's
             dimension will be used (in decreasing priority).

        - *title*: Title for the figure

             If *title* is *None* (default), then the title will be the base
             filename.  Use '' for no title.

        - *label*: Label for the figure (ignored if ax is provided)
             This will be used as a base filename if the figure is saved.

        - *incl_prefix*: If *True*, prefix the legend strings with the base
          filename of the class.

        - *suffix*: String that will be added at the end of the legend entries

        - *use_paren*: Add parentheses around the suffix

        - *\*\*kwargs*: Additional arguments for  :meth:`base.plot` (and thus to
          :meth:`matplotlib.pyplot.plot`)

             If both y axes are used (primary and secondary), then the *dashes*
             argument is ignored.  The curves on the primary axis will be solid
             and the curves on the secondary axis will be dotted.

        **Returns:**

        1. *ax1*: Primary y axes

        2. *ax2*: Secondary y axes

        **Example:**

        .. testsetup::
           >>> from fcres import closeall
           >>> closeall()

        .. code-block:: python

           >>> from fcres import SimRes, saveall

           >>> sim = SimRes('examples/SaturationPressure')
           >>> sim.plot(xname="subregion.gas.H2O.T",
           ...          ynames1=["subregion.gas.H2O.p", "p_sat"],
           ...          legends1=["FCSys (from Gibbs equilibrium)",
           ...                    "Modelica.Media (correlated function)"],
           ...          ylabel1='Saturation pressure',
           ...          title="Water Saturation Pressure",
           ...          label='examples/SaturationPressure') # doctest: +ELLIPSIS
           (<matplotlib.axes._subplots.AxesSubplot object at 0x...>, None)

           >>> saveall()
           Saved examples/SaturationPressure.pdf
           Saved examples/SaturationPressure.png

        .. only:: html

           .. image:: ../examples/SaturationPressure.png
              :scale: 70 %
              :alt: plot of water saturation pressure

        .. only:: latex

           .. figure:: ../examples/SaturationPressure.pdf
              :scale: 70 %

              Plot of water saturation pressure
        """
        # Note:  ynames1 is the first argument (besides self) so that plot()
        # can be called with simply a variable name.

        def _ystrings(ynames, ylabel, yunit, legends):
            """Generate a y-axis label and set of legend entries.
            """
            if ynames:
                if ylabel is None: # Try to create a suitable axis label.
                    descriptions = self.get_description(ynames)
                    # If the descriptions are the same, label the y axis with
                    # the 1st one.
                    ylabel = descriptions[0]
                    if len(set(descriptions)) <> 1:
                        print("The y-axis variable descriptions are not all "
                              "the same.  The first has been used.  Please "
                              "provide the proper name via ylabel1 or ylabel2.")
                if legends == []:
                    legends = ynames
                if incl_prefix:
                    legends = [self.fbase + ': ' + leg for leg in legends]
                if suffix:
                    legends = ([leg + ' (%s)' % suffix for leg in legends]
                               if use_paren else
                               [leg + suffix for leg in legends])
                assert len(set(self.get_dimension(ynames))) == 1, \
                    "The variables on the y-axis do not have the same physical dimension."
                if yunit is None:
                    # Use the unit of the 1st variable.
                    yunit = self.get_unit(ynames[0])
                if ylabel <> "":
                    ylabel = label_number(ylabel, yunit)

            return ylabel, yunit, legends

        # Process the inputs.
        ynames1 = base.flatten_list(ynames1)
        ynames2 = base.flatten_list(ynames2)
        assert ynames1 or ynames2, "No signals were provided."
        if title is None:
            title = self.fbase

        # Create primary and secondary axes if necessary.
        if not ax1:
            fig = base.figure(label)
            ax1 = fig.add_subplot(111)
        if ynames2 and not ax2:
            ax2 = ax1.twinx()

        # Generate the x-axis label.
        if xlabel is None:
            xlabel = 'Time' if xname == 'Time' else self.get_description(xname)
            # With Dymola 7.4, the description of the time variable will be
            # "Time in", which isn't good.
        if xunit is None:
            xunit = self.get_unit(xname)
        if xlabel<> "":
            xlabel = label_number(xlabel, xunit)

        # Generate the y-axis labels and sets of legend entries.
        ylabel1, yunit1, legends1 = _ystrings(ynames1, ylabel1, yunit1, legends1)
        ylabel2, yunit2, legends2 = _ystrings(ynames2, ylabel2, yunit2, legends2)

        # Read the data.
        if xname == 'Time':
            t_scale = lambda t: t*self._unitvalue('s')/self._unitvalue(xunit)
            y_1 = self.get_values(ynames1, f=self.to_unit(yunit1))
            y_2 = self.get_values(ynames2, f=self.to_unit(yunit2))
        else:
            x = self.get_values(xname, f=self.to_unit(xunit))
            times = self.get_times(xname)
            y_1 = self.get_values_at_times(ynames1, times, f=self.to_unit(yunit1))
            y_2 = self.get_values_at_times(ynames2, times, f=self.to_unit(yunit2))

        # Plot the data.
        if ynames1:
            if ynames2:
                # Use solid lines for primary axis and dotted lines for
                # secondary.
                kwargs['dashes'] = [(None, None)]
                base.plot(y_1, self.get_times(ynames1, f=t_scale) if xname == 'Time'
                          else x, ax1, label=legends1, **kwargs)
                kwargs['dashes'] = [(3, 3)]
                base.plot(y_2, self.get_times(ynames2, f=t_scale) if xname == 'Time'
                          else x, ax2, label=legends2, **kwargs)
            else:
                base.plot(y_1, self.get_times(ynames1, f=t_scale) if xname == 'Time'
                          else x, ax1, label=legends1, **kwargs)
        elif ynames2:
            base.plot(y_2, self.get_times(ynames2, f=t_scale) if xname == 'Time'
                      else x, ax2, label=legends2, **kwargs)

        # Decorate the figure.
        ax1.set_title(title)
        ax1.set_xlabel(xlabel)
        if ylabel1:
            ax1.set_ylabel(ylabel1)
        if ylabel2:
            ax2.set_ylabel(ylabel2)
        if legends1:
            if legends2:
                # Put the primary legend in the upper left and secondary in
                # upper right.
                leg1_kwargs['loc'] = 2
                leg2_kwargs['loc'] = 1
                ax1.legend(**leg1_kwargs)
                ax2.legend(**leg2_kwargs)
            else:
                ax1.legend(**leg1_kwargs)
        elif legends2:
            ax2.legend(**leg2_kwargs)

        return ax1, ax2
示例#5
0
    def currdenfig(self,
                   title=None,
                   times=[0],
                   z_index=0,
                   leg_kwargs={},
                   **kwargs):
        """Plot current densities of the cell segments at times.

        **Arguments:**

        - *title*: Title for the figure

        - *times*: List of times at which the data should be sampled

             If multiple times are given, then subfigures will be generated.

        - *z_index*: z-index at which the current densities are taken

        - *leg_kwargs*: Dictionary of keyword arguments for
          :meth:`matplotlib.pyplot.legend`

             If *leg_kwargs* is *None*, then no legend will be shown.

        - *\*\*kwargs*: Additional arguments for  :meth:`barfig`
        """
        # Process the arguments.
        xlabel = kwargs.pop('xlabel', 'y-axis index (inlet to outlet)')
        name_template = self.cell + ('iprimeprime_seg[%i, ' + '%i]' %
                                     (z_index + 1))
        #description = self.get_description(name_template % 1)
        #unit = self.get_unit(name_template % 1)
        unit = self.get_unit(name_template % 1)
        #ylabel = kwargs.pop('ylabel', label_number(description, unit))
        ylabel = kwargs.pop('ylabel', label_number("Current density", unit))

        # Create the plot.
        ax = self.barfig(names=[name_template % (i_y + 1) for i_y in range(1)],
                         times=times,
                         xlabel=xlabel,
                         ylabel=ylabel,
                         leg_kwargs=None,
                         **kwargs)
        for a, time in zip(ax, times):
            a.axhline(self.get_values('cell.iprimeprime', time),
                      linestyle='--',
                      color='k',
                      label='Entire cell')

        # Decorate.
        if title is None:
            if self.n_z == 1:
                plt.title("Current Distribution of Cell Segments")
            else:
                plt.title("Current Distribution of Cell Segments\n"
                          "z-axis index %i (of %i)" % (z_index + 1, self.n_z))
        if leg_kwargs is not None:
            loc = leg_kwargs.pop('loc', 'best')
            if len(ax) == 1:
                ax[0].legend(loc=loc, **leg_kwargs)
            else:
                plt.figlegend(ax[0].lines, **leg_kwargs)
示例#6
0
    def colorfig(self,
                 suffix,
                 times=[0],
                 n_rows=1,
                 title="",
                 subtitles=[],
                 label="color",
                 slice_axis='z',
                 slice_index=0,
                 xlabel="",
                 xticklabels=[],
                 xticks=[],
                 ylabel="",
                 yticklabels=[],
                 yticks=[],
                 clabel="",
                 cbar_orientation='vertical',
                 margin_left=rcParams['figure.subplot.left'],
                 margin_right=1 - rcParams['figure.subplot.right'],
                 margin_bottom=rcParams['figure.subplot.bottom'],
                 margin_top=1 - rcParams['figure.subplot.top'],
                 margin_cbar=0.2,
                 wspace=0.1,
                 hspace=0.25,
                 cbar_space=0.1,
                 cbar_width=0.05,
                 **kwargs):
        """Create a figure with 2D scalar data at given time(s) on a color axis
        in 2D Cartesian coordinates.

        **Arguments:**

        - *suffix*: Name of the variable to be plotted (relative to the names
          of the subregions)

        - *times*: List of times at which the data should be sampled

             If multiple times are given, then subfigures will be generated.

        - *n_rows*: Number of rows of (sub)plots

        - *title*: Title for the figure

        - *subtitles*: List of subtitles (i.e., titles for each subplot)

             If not provided, "t = xx s" will be used, where xx is the time of
             each entry.  "(initial)" or "(final)" are appended if appropriate.

        - *label*: Label for the figure

             This will be used as a base filename if the figure is saved.

        - *slice_axis*: Axis normal to the screen or page ('x', 'y', or 'z')

        - *slice_index*: Position along slice_axis

        - *xlabel*: Label for the x-axes (only shown for the subplots on the
          bottom row)

        - *xticklabels*: Labels for the x-axis ticks (only shown for the
          subplots on the bottom row)

        - *xticks*: Positions of the x-axis ticks

        - *ylabel*: Label for the y axis (only shown for the subplots on the
          left column)

        - *yticklabels*: Labels for the y-axis ticks (only shown for the
          subplots on the left column)

        - *yticks*: Positions of the y-axis ticks

        - *clabel*: Label for the color- or c-bar axis

        - *cbar_orientation*: Orientation of the colorbar ("vertical" or
          "horizontal")

        - *margin_left*: Left margin

        - *margin_right*: Right margin (ignored if ``cbar_orientation ==
          'vertical'``)

        - *margin_bottom*: Bottom margin (ignored if ``cbar_orientation ==
          'horizontal'``)

        - *margin_top*: Top margin

        - *margin_cbar*: Margin reserved for the colorbar (right margin if
          ``cbar_orientation == 'vertical'`` and bottom margin if
          ``cbar_orientation == 'horizontal'``)

        - *wspace*: The amount of width reserved for blank space between
          subplots

        - *hspace*: The amount of height reserved for white space between
          subplots

        - *cbar_space*: Space between the subplot rectangles and the colorbar

        - *cbar_width*: Width of the colorbar if vertical (or height if
          horizontal)

        - *\*\*kwargs*: Additional arguments for  :meth:`modelicares.base.color`
        """
        # The procedure for coordinating the images with a single colorbar was
        # copied and modified from
        # http://matplotlib.sourceforge.net/examples/pylab_examples/multi_image.html,
        # accessed 11/8/10.

        # 5/26/11: TODO: This method needs to be updated. Use quiverfig() as a
        # reference.

        from res import color

        # Get the data.
        n_plots = len(times)
        if slice_axis == 'x':
            names = presuffix(self.subregions[slice_index], suffix=suffix)
        elif slice_axis == 'y':
            names = presuffix(self.subregions[:][slice_index], suffix=suffix)
        else:
            names = presuffix(self.subregions[:][:][slice_index],
                              suffix=suffix)
        c = self.get_values_at_times(names, times)

        # Cast the data into a list of matrices (one at each sample time).
        if slice_axis == 'x':
            c = [
                np.array([[
                    c[i_y + self.n_y * i_z][i]
                    for i_y in range(self.n_y - 1, -1, -1)
                ] for i_z in range(self.n_z)]) for i in range(n_plots)
            ]
        elif slice_axis == 'y':
            c = [
                np.array([[
                    c[i_z + self.n_z * i_x][i]
                    for i_z in range(self.n_z - 1, -1, -1)
                ] for i_x in range(self.n_x)]) for i in range(n_plots)
            ]
        else:
            c = [
                np.array([[
                    c[i_y + self.n_y * i_x][i]
                    for i_z in range(self.n_y - 1, -1, -1)
                ] for i_x in range(self.n_x)]) for i in range(n_plots)
            ]
        [start_time, stop_time] = self.get_times('Time', [0, -1])

        # Generate xlabel, xticks, and xticklabels.
        if not xlabel:
            if slice_axis == 'x':
                xlabel = 'z-axis index'
            elif slice_axis == 'y':
                xlabel = 'x-axis index'
            elif slice_axis == 'z':
                xlabel = 'y-axis index'
        if not xticklabels:
            if slice_axis == 'x':
                xticklabels = [str(i + 1) for i in range(self.n_z)]
            elif slice_axis == 'y':
                xticklabels = [str(i + 1) for i in range(self.n_x)]
            else:
                xticklabels = [str(i + 1) for i in range(self.n_x)]
        if not xticks:
            if slice_axis == 'x':
                xticks = range(self.n_z)
            elif slice_axis == 'y':
                xticks = range(self.n_x)
            else:
                xticks = range(self.n_x)

        # Generate ylabel, yticks, and yticklabels.
        if not ylabel:
            if slice_axis == 'x':
                ylabel = 'y-axis index'
            elif slice_axis == 'y':
                ylabel = 'z-axis index'
            else:
                ylabel = 'x-axis index'
        if not yticklabels:
            if slice_axis == 'x':
                yticklabels = [str(i + 1) for i in range(self.n_y)]
            elif slice_axis == 'y':
                yticklabels = [str(i + 1) for i in range(self.n_z)]
            else:
                yticklabels = [str(i + 1) for i in range(self.n_y)]
        if not yticks:
            if slice_axis == 'x':
                yticks = range(self.n_y)
            elif slice_axis == 'y':
                yticks = range(self.n_z)
            else:
                yticks = range(self.n_y)

        # Generate clabel.
        if not clabel:
            clabels = self.get_description(names)
            # If all of the descriptions are the same, use the first one.
            if len(set(clabels)) == 1:
                clabel = clabels[0]
            else:
                clabel = "Value"
        #units = self.get_unit(names)
        units = self.get_unit(names)
        if len(set(units)) == 1:
            clabel += label_number("", units[0])
        else:
            raise UserWarning(
                "The variables have inconsistent units.  The "
                "colorbar unit will not match the units of all of the "
                "variables.")

        # Set up the subplots.
        if not subtitles:
            #unit = unit2tex(self.get_unit('Time'))
            unit = unit2tex(self.get_unit('Time'))
            subtitles = [
                "t = " + label_quantity(times[i], unit) for i in n_plots
            ]
            for i, time in enumerate(times):
                if time == start_time:
                    subtitle += " (initial)"
                elif time == stop_time:
                    subtitle += " (final)"
        ax, cax = setup_subplots(n_plots=n_plots,
                                 n_rows=n_rows,
                                 title=title,
                                 subtitles=subtitles,
                                 label=label,
                                 xlabel=xlabel,
                                 xticklabels=xticklabels,
                                 xticks=xticks,
                                 ylabel=ylabel,
                                 yticklabels=yticklabels,
                                 yticks=yticks,
                                 ctype=cbar_orientation,
                                 clabel=clabel,
                                 margin_left=margin_left,
                                 margin_right=margin_right,
                                 margin_bottom=margin_bottom,
                                 margin_top=margin_top,
                                 margin_cbar=margin_cbar,
                                 wspace=wspace,
                                 hspace=hspace,
                                 cbar_space=cbar_space,
                                 cbar_width=cbar_width)

        # Create the plots.
        profiles = []
        c_min = np.inf
        c_max = -np.inf
        for i, time in enumerate(times):
            profiles.append(color(ax[i], c[i], **kwargs))

            # Find the minimum and maximum of the color-axis data.
            c_min = min(c_min, np.amin(c[i]))
            c_max = max(c_max, np.amax(c[i]))

        # Set the first image as the master, with all the others observing it
        # for changes in norm.
        class ImageFollower:
            """Update image in response to changes in clim on another image.
            """
            def __init__(self, follower):
                self.follower = follower

            def __call__(self, leader):
                self.follower.set_clim(leader.get_clim())

        norm = Normalize(c_min=c_min, c_max=c_max)
        for i, profile in enumerate(profiles):
            profile.set_norm(norm)
            if i > 0:
                profiles[0].callbacksSM.connect('changed',
                                                ImageFollower(profile))

        # Add the colorbar. (It is also based on the master image.)
        cbar = fig.colorbar(images[0], cax, orientation=cbar_orientation)

        # Scale the colorbar.
        if c_min == c_max:
            yticks = [c_min]
            for i in range(len(cbar.ax.get_yticks()) - 1):
                yticks.append(None)
            cbar.set_ticks(yticks)
示例#7
0
    def colorfig(self, suffix, times=[0], n_rows=1, title="", subtitles=[],
                 label="color", slice_axis='z', slice_index=0,
                 xlabel="", xticklabels=[], xticks=[],
                 ylabel="", yticklabels=[], yticks=[],
                 clabel="", cbar_orientation='vertical',
                 margin_left=rcParams['figure.subplot.left'],
                 margin_right=1-rcParams['figure.subplot.right'],
                 margin_bottom=rcParams['figure.subplot.bottom'],
                 margin_top=1-rcParams['figure.subplot.top'],
                 margin_cbar=0.2,
                 wspace=0.1, hspace=0.25,
                 cbar_space=0.1, cbar_width=0.05,
                 **kwargs):
        """Create a figure with 2D scalar data at given time(s) on a color axis
        in 2D Cartesian coordinates.

        **Arguments:**

        - *suffix*: Name of the variable to be plotted (relative to the names
          of the subregions)

        - *times*: List of times at which the data should be sampled

             If multiple times are given, then subfigures will be generated.

        - *n_rows*: Number of rows of (sub)plots

        - *title*: Title for the figure

        - *subtitles*: List of subtitles (i.e., titles for each subplot)

             If not provided, "t = xx s" will be used, where xx is the time of
             each entry.  "(initial)" or "(final)" are appended if appropriate.

        - *label*: Label for the figure

             This will be used as a base filename if the figure is saved.

        - *slice_axis*: Axis normal to the screen or page ('x', 'y', or 'z')

        - *slice_index*: Position along slice_axis

        - *xlabel*: Label for the x-axes (only shown for the subplots on the
          bottom row)

        - *xticklabels*: Labels for the x-axis ticks (only shown for the
          subplots on the bottom row)

        - *xticks*: Positions of the x-axis ticks

        - *ylabel*: Label for the y axis (only shown for the subplots on the
          left column)

        - *yticklabels*: Labels for the y-axis ticks (only shown for the
          subplots on the left column)

        - *yticks*: Positions of the y-axis ticks

        - *clabel*: Label for the color- or c-bar axis

        - *cbar_orientation*: Orientation of the colorbar ("vertical" or
          "horizontal")

        - *margin_left*: Left margin

        - *margin_right*: Right margin (ignored if ``cbar_orientation ==
          'vertical'``)

        - *margin_bottom*: Bottom margin (ignored if ``cbar_orientation ==
          'horizontal'``)

        - *margin_top*: Top margin

        - *margin_cbar*: Margin reserved for the colorbar (right margin if
          ``cbar_orientation == 'vertical'`` and bottom margin if
          ``cbar_orientation == 'horizontal'``)

        - *wspace*: The amount of width reserved for blank space between
          subplots

        - *hspace*: The amount of height reserved for white space between
          subplots

        - *cbar_space*: Space between the subplot rectangles and the colorbar

        - *cbar_width*: Width of the colorbar if vertical (or height if
          horizontal)

        - *\*\*kwargs*: Additional arguments for  :meth:`modelicares.base.color`
        """
        # The procedure for coordinating the images with a single colorbar was
        # copied and modified from
        # http://matplotlib.sourceforge.net/examples/pylab_examples/multi_image.html,
        # accessed 11/8/10.

        # 5/26/11: TODO: This method needs to be updated. Use quiverfig() as a
        # reference.

        from res import color

        # Get the data.
        n_plots = len(times)
        if slice_axis == 'x':
            names = presuffix(self.subregions[slice_index], suffix=suffix)
        elif slice_axis == 'y':
            names = presuffix(self.subregions[:][slice_index], suffix=suffix)
        else:
            names = presuffix(self.subregions[:][:][slice_index],
                              suffix=suffix)
        c = self.get_values_at_times(names, times)

        # Cast the data into a list of matrices (one at each sample time).
        if slice_axis == 'x':
            c = [np.array([[c[i_y + self.n_y*i_z][i]
                 for i_y in range(self.n_y-1,-1,-1)]
                 for i_z in range(self.n_z)]) for i in range(n_plots)]
        elif slice_axis == 'y':
            c = [np.array([[c[i_z + self.n_z*i_x][i]
                 for i_z in range(self.n_z-1,-1,-1)]
                 for i_x in range(self.n_x)]) for i in range(n_plots)]
        else:
            c = [np.array([[c[i_y + self.n_y*i_x][i]
                 for i_z in range(self.n_y-1,-1,-1)]
                 for i_x in range(self.n_x)]) for i in range(n_plots)]
        [start_time, stop_time] = self.get_times('Time', [0,-1])

        # Generate xlabel, xticks, and xticklabels.
        if not xlabel:
            if slice_axis == 'x':
                xlabel = 'z-axis index'
            elif slice_axis == 'y':
                xlabel = 'x-axis index'
            elif slice_axis == 'z':
                xlabel = 'y-axis index'
        if not xticklabels:
            if slice_axis == 'x':
                xticklabels = [str(i+1) for i in range(self.n_z)]
            elif slice_axis == 'y':
                xticklabels = [str(i+1) for i in range(self.n_x)]
            else:
                xticklabels = [str(i+1) for i in range(self.n_x)]
        if not xticks:
            if slice_axis == 'x':
                xticks = range(self.n_z)
            elif slice_axis == 'y':
                xticks = range(self.n_x)
            else:
                xticks = range(self.n_x)

        # Generate ylabel, yticks, and yticklabels.
        if not ylabel:
            if slice_axis == 'x':
                ylabel = 'y-axis index'
            elif slice_axis == 'y':
                ylabel = 'z-axis index'
            else:
                ylabel = 'x-axis index'
        if not yticklabels:
            if slice_axis == 'x':
                yticklabels = [str(i+1) for i in range(self.n_y)]
            elif slice_axis == 'y':
                yticklabels = [str(i+1) for i in range(self.n_z)]
            else:
                yticklabels = [str(i+1) for i in range(self.n_y)]
        if not yticks:
            if slice_axis == 'x':
                yticks = range(self.n_y)
            elif slice_axis == 'y':
                yticks = range(self.n_z)
            else:
                yticks = range(self.n_y)

        # Generate clabel.
        if not clabel:
            clabels = self.get_description(names)
            # If all of the descriptions are the same, use the first one.
            if len(set(clabels)) == 1:
                clabel = clabels[0]
            else:
                clabel = "Value"
        #units = self.get_unit(names)
        units = self.get_unit(names)
        if len(set(units)) == 1:
            clabel += label_number("", units[0])
        else:
            raise UserWarning("The variables have inconsistent units.  The "
                "colorbar unit will not match the units of all of the "
                "variables.")

        # Set up the subplots.
        if not subtitles:
            #unit = unit2tex(self.get_unit('Time'))
            unit = unit2tex(self.get_unit('Time'))
            subtitles = ["t = " + label_quantity(times[i], unit)
                for i in n_plots]
            for i, time in enumerate(times):
                if time == start_time:
                    subtitle += " (initial)"
                elif time == stop_time:
                    subtitle += " (final)"
        ax, cax = setup_subplots(n_plots=n_plots, n_rows=n_rows,
            title=title, subtitles=subtitles, label=label,
            xlabel=xlabel, xticklabels=xticklabels, xticks=xticks,
            ylabel=ylabel, yticklabels=yticklabels, yticks=yticks,
            ctype=cbar_orientation, clabel=clabel,
            margin_left=margin_left, margin_right=margin_right,
            margin_bottom=margin_bottom, margin_top=margin_top,
            margin_cbar=margin_cbar, wspace=wspace, hspace=hspace,
            cbar_space=cbar_space, cbar_width=cbar_width)

        # Create the plots.
        profiles = []
        c_min = np.inf
        c_max = -np.inf
        for i, time in enumerate(times):
            profiles.append(color(ax[i], c[i], **kwargs))

            # Find the minimum and maximum of the color-axis data.
            c_min = min(c_min, np.amin(c[i]))
            c_max = max(c_max, np.amax(c[i]))

        # Set the first image as the master, with all the others observing it
        # for changes in norm.
        class ImageFollower:
            """Update image in response to changes in clim on another image.
            """
            def __init__(self, follower):
                self.follower = follower
            def __call__(self, leader):
                self.follower.set_clim(leader.get_clim())
        norm = Normalize(c_min=c_min, c_max=c_max)
        for i, profile in enumerate(profiles):
            profile.set_norm(norm)
            if i > 0:
                profiles[0].callbacksSM.connect('changed',
                                                ImageFollower(profile))

        # Add the colorbar. (It is also based on the master image.)
        cbar = fig.colorbar(images[0], cax, orientation=cbar_orientation)

        # Scale the colorbar.
        if c_min == c_max:
            yticks = [c_min]
            for i in range(len(cbar.ax.get_yticks()) - 1):
                yticks.append(None)
            cbar.set_ticks(yticks)
示例#8
0
    def plot(self,
             ynames1=[],
             ylabel1=None,
             yunit1=None,
             legends1=[],
             leg1_kwargs={'loc': 'best'},
             ax1=None,
             ynames2=[],
             ylabel2=None,
             yunit2=None,
             legends2=[],
             leg2_kwargs={'loc': 'best'},
             ax2=None,
             xname='Time',
             xlabel=None,
             xunit=None,
             title=None,
             label="xy",
             incl_prefix=False,
             suffix=None,
             use_paren=True,
             **kwargs):
        r"""Plot data as points and/or curves in 2D Cartesian coordinates.

        A new figure is created if necessary.

        **Arguments:**

        - *ynames1*: Names of variables for the primary y axis

             If any names are invalid, then they will be skipped.

        - *ylabel1*: Label for the primary y axis

             If *ylabel1* is *None* (default) and all of the variables have the
             same Modelica_ description string, then the common description
             will be used.  Use '' for no label.

        - *yunit1*: String indicating the unit for the primary y-axis (see note
          for *xunit*)

             If *yunit1* is *None*, the Modelica_ *displayUnit* of the first
             entry of *ynames1* or the default unit (from *fcres.ini*) based on
             that variable's dimension will be used (in decreasing priority).

             .. Note:: Dimension checking is not currently performed, so it is
                important to ensure that a proper unit is chosen.

        - *legends1*: List of legend entries for variables assigned to the
          primary y axis

             If *legends1* is an empty list ([]), ynames1 will be used.  If
             *legends1* is *None* and all of the variables on the primary axis
             have the same unit, then no legend will be shown.

        - *leg1_kwargs*: Dictionary of keyword arguments for the primary legend

        - *ax1*: Primary y axes

             If *ax1* is not provided, then axes will be created in a new
             figure.

        - *ynames2*, *ylabel2*, *yunit2*, *legends2*, *leg2_kwargs*, and *ax2*:
          Similar to *ynames1*, *ylabel1*, *yunit1*, *legends1*, *leg1_kwargs*,
          and *ax1* but for the secondary y axis

        - *xname*: Name of the x-axis data

        - *xlabel*: Label for the x axis

             If *xlabel* is *None* (default), the variable's Modelica_
             description string will be applied.  Use '' for no label.

        - *xunit*: String indicating the unit for the x axis  (see note
          for *yunit1*)

             If *xunit* is *None*, the Modelica_ variable's *displayUnit* or
             the default unit (from *fcres.ini*) based on the variable's
             dimension will be used (in decreasing priority).

        - *title*: Title for the figure

             If *title* is *None* (default), then the title will be the base
             filename.  Use '' for no title.

        - *label*: Label for the figure (ignored if ax is provided)
             This will be used as a base filename if the figure is saved.

        - *incl_prefix*: If *True*, prefix the legend strings with the base
          filename of the class.

        - *suffix*: String that will be added at the end of the legend entries

        - *use_paren*: Add parentheses around the suffix

        - *\*\*kwargs*: Additional arguments for  :meth:`base.plot` (and thus to
          :meth:`matplotlib.pyplot.plot`)

             If both y axes are used (primary and secondary), then the *dashes*
             argument is ignored.  The curves on the primary axis will be solid
             and the curves on the secondary axis will be dotted.

        **Returns:**

        1. *ax1*: Primary y axes

        2. *ax2*: Secondary y axes

        **Example:**

        .. testsetup::
           >>> from fcres import closeall
           >>> closeall()

        .. code-block:: python

           >>> from fcres import SimRes, saveall

           >>> sim = SimRes('examples/SaturationPressure')
           >>> sim.plot(xname="subregion.gas.H2O.T",
           ...          ynames1=["subregion.gas.H2O.p", "p_sat"],
           ...          legends1=["FCSys (from Gibbs equilibrium)",
           ...                    "Modelica.Media (correlated function)"],
           ...          ylabel1='Saturation pressure',
           ...          title="Water Saturation Pressure",
           ...          label='examples/SaturationPressure') # doctest: +ELLIPSIS
           (<matplotlib.axes._subplots.AxesSubplot object at 0x...>, None)

           >>> saveall()
           Saved examples/SaturationPressure.pdf
           Saved examples/SaturationPressure.png

        .. only:: html

           .. image:: ../examples/SaturationPressure.png
              :scale: 70 %
              :alt: plot of water saturation pressure

        .. only:: latex

           .. figure:: ../examples/SaturationPressure.pdf
              :scale: 70 %

              Plot of water saturation pressure
        """

        # Note:  ynames1 is the first argument (besides self) so that plot()
        # can be called with simply a variable name.

        def _ystrings(ynames, ylabel, yunit, legends):
            """Generate a y-axis label and set of legend entries.
            """
            if ynames:
                if ylabel is None:  # Try to create a suitable axis label.
                    descriptions = self.get_description(ynames)
                    # If the descriptions are the same, label the y axis with
                    # the 1st one.
                    ylabel = descriptions[0]
                    if len(set(descriptions)) <> 1:
                        print(
                            "The y-axis variable descriptions are not all "
                            "the same.  The first has been used.  Please "
                            "provide the proper name via ylabel1 or ylabel2.")
                if legends == []:
                    legends = ynames
                if incl_prefix:
                    legends = [self.fbase + ': ' + leg for leg in legends]
                if suffix:
                    legends = ([leg + ' (%s)' % suffix
                                for leg in legends] if use_paren else
                               [leg + suffix for leg in legends])
                assert len(set(self.get_dimension(ynames))) == 1, \
                    "The variables on the y-axis do not have the same physical dimension."
                if yunit is None:
                    # Use the unit of the 1st variable.
                    yunit = self.get_unit(ynames[0])
                if ylabel <> "":
                    ylabel = label_number(ylabel, yunit)

            return ylabel, yunit, legends

        # Process the inputs.
        ynames1 = base.flatten_list(ynames1)
        ynames2 = base.flatten_list(ynames2)
        assert ynames1 or ynames2, "No signals were provided."
        if title is None:
            title = self.fbase

        # Create primary and secondary axes if necessary.
        if not ax1:
            fig = base.figure(label)
            ax1 = fig.add_subplot(111)
        if ynames2 and not ax2:
            ax2 = ax1.twinx()

        # Generate the x-axis label.
        if xlabel is None:
            xlabel = 'Time' if xname == 'Time' else self.get_description(xname)
            # With Dymola 7.4, the description of the time variable will be
            # "Time in", which isn't good.
        if xunit is None:
            xunit = self.get_unit(xname)
        if xlabel <> "":
            xlabel = label_number(xlabel, xunit)

        # Generate the y-axis labels and sets of legend entries.
        ylabel1, yunit1, legends1 = _ystrings(ynames1, ylabel1, yunit1,
                                              legends1)
        ylabel2, yunit2, legends2 = _ystrings(ynames2, ylabel2, yunit2,
                                              legends2)

        # Read the data.
        if xname == 'Time':
            t_scale = lambda t: t * self._unitvalue('s') / self._unitvalue(
                xunit)
            y_1 = self.get_values(ynames1, f=self.to_unit(yunit1))
            y_2 = self.get_values(ynames2, f=self.to_unit(yunit2))
        else:
            x = self.get_values(xname, f=self.to_unit(xunit))
            times = self.get_times(xname)
            y_1 = self.get_values_at_times(ynames1,
                                           times,
                                           f=self.to_unit(yunit1))
            y_2 = self.get_values_at_times(ynames2,
                                           times,
                                           f=self.to_unit(yunit2))

        # Plot the data.
        if ynames1:
            if ynames2:
                # Use solid lines for primary axis and dotted lines for
                # secondary.
                kwargs['dashes'] = [(None, None)]
                base.plot(y_1,
                          self.get_times(ynames1, f=t_scale)
                          if xname == 'Time' else x,
                          ax1,
                          label=legends1,
                          **kwargs)
                kwargs['dashes'] = [(3, 3)]
                base.plot(y_2,
                          self.get_times(ynames2, f=t_scale)
                          if xname == 'Time' else x,
                          ax2,
                          label=legends2,
                          **kwargs)
            else:
                base.plot(y_1,
                          self.get_times(ynames1, f=t_scale)
                          if xname == 'Time' else x,
                          ax1,
                          label=legends1,
                          **kwargs)
        elif ynames2:
            base.plot(
                y_2,
                self.get_times(ynames2, f=t_scale) if xname == 'Time' else x,
                ax2,
                label=legends2,
                **kwargs)

        # Decorate the figure.
        ax1.set_title(title)
        ax1.set_xlabel(xlabel)
        if ylabel1:
            ax1.set_ylabel(ylabel1)
        if ylabel2:
            ax2.set_ylabel(ylabel2)
        if legends1:
            if legends2:
                # Put the primary legend in the upper left and secondary in
                # upper right.
                leg1_kwargs['loc'] = 2
                leg2_kwargs['loc'] = 1
                ax1.legend(**leg1_kwargs)
                ax2.legend(**leg2_kwargs)
            else:
                ax1.legend(**leg1_kwargs)
        elif legends2:
            ax2.legend(**leg2_kwargs)

        return ax1, ax2