Example #1
0
 def gen_subtitles_time(self, times):
     """Generate titles for subplots at a list of times.
     """
     time_unit = unit2tex(self.get_unit('Time'))
     subtitles = ["t = %s" % (time if time == 0 else
         label_quantity(time, time_unit)) for time in times]
     start_time, stop_time = self.get_times('Time', [0, -1])
     for i, time in enumerate(times):
         if time == start_time:
             subtitles[i] += " (initial)"
         elif time == stop_time:
             subtitles[i] += " (final)"
     return subtitles
Example #2
0
 def gen_subtitles_time(self, times):
     """Generate titles for subplots at a list of times.
     """
     time_unit = unit2tex(self.get_unit('Time'))
     subtitles = [
         "t = %s" % (time if time == 0 else label_quantity(time, time_unit))
         for time in times
     ]
     start_time, stop_time = self.get_times('Time', [0, -1])
     for i, time in enumerate(times):
         if time == start_time:
             subtitles[i] += " (initial)"
         elif time == stop_time:
             subtitles[i] += " (final)"
     return subtitles
Example #3
0
    def quiverfig_subregions(self,
                             vect,
                             times=[0],
                             n_rows=1,
                             title="",
                             subtitles=None,
                             label="quiver",
                             slice_axis='z',
                             slice_index=0,
                             xlabel=None,
                             xticklabels=None,
                             ylabel=None,
                             yticklabels=None,
                             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'],
                             wspace=0.1,
                             hspace=0.25,
                             **kwargs):
        """Create a figure with 2D vector data at given time(s) as arrows in 2D
        Cartesian coordinates.

        **Arguments:**

        - *vect*: Name of the vector to be plotted

             *vect* should contain "%i" where the vector indices should be
             inserted; the vector will be indexed according to the choice of
             *slice_axis* (see below).  *vect* will be appended to the names of
             the subregions (separated by '.') in order to determine the full
             names of the vectors.

        - *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)" is 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)

             If *xlabel* is *None*, then the axis is labeled with "X Axis",
             "Y Axis", or "Z Axis" (as appropriate).

        - *xticklabels*: Labels for the x-axis ticks

             X-axis ticks are only shown for the subplots on the bottom row.
             If *xticklabels* is *None*, then the tick labels are "1", "2", ...

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

             If *ylabel* is *None*, then the axis is labeled with "X Axis",
             "Y Axis", or "Z Axis" (as appropriate).

        - *yticklabels*: Labels for the y-axis ticks

             Y-axis ticks are only shown for the subplots on the left column.
             If *None*, then the tick labels are "1", "2", ...

        - *margin_left*: Left margin

        - *margin_right*: Right margin

        - *margin_bottom*: Bottom margin

        - *margin_top*: Top margin

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

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

        - *\*\*kwargs*: Additional arguments for  :meth:`modelicares.base.quiver` (and
          thus to :meth:`matplotlib.pyplot.quiver`)
        """
        # The quiver() scaling is static and manual; therefore, it shouldn't be
        # necessary to coordinate the scaling among subplots like it is for
        # colorfig().

        # TODO 10/31/11:
        # 1) Move the dots and the pivots to the centers of masses of the
        #    subregions.
        # 2) Use and show a grid that is in scale with the geometry of the
        #    subregions (create a separate method for this it so that it can be
        #    used for colorfig too; x and y scales would need to be different).
        # 3) Overlay the velocities at the faces with the velocities of the
        #    subregions (by calling this method again with hold on?).

        from res import quiver

        # Change the default quiver color.
        color = kwargs.pop('color', 'b')

        # Slice the subregions and retrieve the data.
        (us, vs), (n_x, n_y), unit, blanks = self.get_vector_comps2D(
            slice_axis, slice_index, vect, times)

        # Generate xlabel, xticks, and xticklabels.
        if xlabel is None:
            xlabel = ('y-axis index' if slice_axis == 'x' else
                      'z-axis index' if slice_axis == 'y' else 'x-axis index')
        if xticklabels is None:
            xticklabels = [str(i + 1) for i in range(n_x)]
        xticks = range(n_x)
        #xticks = [0,1,2,10] # TODO temp

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

        # Set up the subplots.
        n_plots = len(times)  # Number of plots
        if not subtitles:
            subtitles = self.gen_subtitles_time(times)
        axs, n_cols = 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,
                                     margin_left=margin_left,
                                     margin_right=margin_right,
                                     margin_bottom=margin_bottom,
                                     margin_top=margin_top,
                                     wspace=wspace,
                                     hspace=hspace)

        # Create the plots.
        # scale = 1e-6 # 1 um/s; Zero may cause trouble wth quiverkey() TODO ?
        quivers = []
        scale = 0
        for ax, u, v in zip(axs, us, vs):
            quivers.append(quiver(ax, u, v, pad=2 * 0.5, color=color,
                                  **kwargs))
            # TODO test moving the locations
            #quivers.append(quiver(ax, x = [0,1,2,10], y = [0], u=u, v=v,
            #    **kwargs))

            # Add dots at the pivots.
            for i_x in range(n_x):
                for i_y in range(n_y):
                    ax.plot(i_x,
                            i_y,
                            marker='o',
                            color='k',
                            markerfacecolor='w' if blanks[i_x][i_y] else 'k')

            # Find the maximum magnitude of the data.
            scale = max(scale, np.amax(np.abs(u)), np.amax(np.abs(v)))
        # TODO: Hack: For some reason, the last plot is badly scaled.  Update
        # it to match the one before it.
        if n_plots > 1:
            axs[-1].axis(axs[-2].axis())

        # Add the key.
        # Round the scale to one significant digit.
        pow10 = get_pow10(scale)
        scale = np.round(scale / 10**pow10) * 10**pow10
        axs[n_cols - 1].quiverkey(Q=quivers[n_cols - 1],
                                  X=1,
                                  Y=1.15,
                                  U=scale,
                                  label=label_quantity(scale, unit),
                                  labelpos='W')

        # Label the layers.
        self.label_layers(axs[len(axs) - n_cols:])
Example #4
0
def annotate_conditions(conditions,
                        temp=True,
                        composition=True,
                        pressure=True,
                        humidity=True,
                        flow=True):
    r"""Create a description of the operating conditions (e.g., to be used as a
    subtitle).

    **Arguments:**

    - *conditions*: Dictionary of operating conditions

         The dictionary may include the keys *T*, *p_an_out*, *p_ca_out*,
         *n_O2*, *p_an_out*, *p_ca_out*, *T_an_in*, *T_ca_in*, *anInletRH*,
         *caInletRH*, *anStoich*, and *caStoich*.  Any entry is missing, it will
         not be exclued.  Each entry is a tuple of (number, unit string) that
         describes a condition.

    - *temp*: *True*, if temperature should be included in the description

    - *composition*: *True*, if composition should be included in the
      description

    - *pressure*: *True*, if pressure should be included in the description

    - *humidity*: *True*, if humidity should be included in the description

    - *flow*: *True*, if the flow conditions (stoichiometry) should be included
      in the description

    **Example:**

       >>> conditions = dict(T = (60, 'degC'),
       ...                   p = (150, 'kPa'),
       ...                   n_O2 = (21, '%'),
       ...                   anInletRH = (80, '%'),
       ...                   caInletRH = (50, '%'),
       ...                   anStoich = (1.5, '1'),
       ...                   caStoich = (2.0, '1'))
       >>> annotate_conditions(conditions)
       '60$\\,^{\\circ}\\!C$, 150$\\,kPa$; An|Ca: $H_2$|Air, 80|50$\\!$$\\,\\%$$\\,$RH, 1.5|2.0$\\,$stoich'
    """
    # Main description
    main_desc = []
    if temp:
        try:
            main_desc += [label_quantity(*conditions['T'])]
            temp = False
            if 'T_an_in' in conditions:
                print("T_an_in will be ignored.")
            if 'T_ca_in' in conditions:
                print("T_ca_in will be ignored.")
        except KeyError:
            pass
    if pressure:
        try:
            main_desc += [label_quantity(*conditions['p'])]
            pressure = False
            if 'p_an_out' in conditions:
                print("p_an_out will be ignored.")
            if 'p_ca_out' in conditions:
                print("p_ca_out will be ignored.")
        except KeyError:
            pass
    main_desc = ", ".join(main_desc)

    # Anode/cathode description
    anca_desc = []
    if flow:
        try:
            anca_desc += [
                '%s|%sstoich' %
                (label_quantity(conditions['anStoich'][0], format='%.1f'),
                 label_quantity(*conditions['caStoich'], format='%.1f'))
            ]
        except KeyError:
            pass
    if composition:
        try:
            if conditions['n_O2'][0] == 1.0:
                anca_desc += ['$H_2$|$O_2$']
            else:
                anca_desc += ['$H_2$|Air']
        except KeyError:
            pass
    if temp:
        try:
            anca_desc += [
                '%s|%s' %
                (label_quantity(conditions['T_an_in'][0], format='%.0f'),
                 label_quantity(*conditions['T_ca_in'], format='%.0f'))
            ]
        except KeyError:
            pass
    if pressure:
        try:
            anca_desc += [
                '%s|%s' %
                (label_quantity(conditions['p_an_out'][0], format='%.1f'),
                 label_quantity(*conditions['p_ca_out'], format='%.1f'))
            ]
        except KeyError:
            pass
    if humidity:
        try:
            anca_desc += [
                '%s|%s$\,$RH' %
                (label_quantity(conditions['anInletRH'][0], format='%.0f'),
                 label_quantity(*conditions['caInletRH'], format='%.0f'))
            ]
        except KeyError:
            pass
    anca_desc = ", ".join(anca_desc)
    if anca_desc:
        anca_desc = "An|Ca: " + anca_desc

    # Finish.
    if not anca_desc:
        return main_desc
    if not main_desc:
        return anca_desc
    return main_desc + "; " + anca_desc
Example #5
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)
Example #6
0
    def quiverfig_subregions(self, vect, times=[0], n_rows=1,
                             title="", subtitles=None, label="quiver",
                             slice_axis='z', slice_index=0,
                             xlabel=None, xticklabels=None,
                             ylabel=None, yticklabels=None,
                             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'],
                             wspace=0.1, hspace=0.25,
                             **kwargs):
        """Create a figure with 2D vector data at given time(s) as arrows in 2D
        Cartesian coordinates.

        **Arguments:**

        - *vect*: Name of the vector to be plotted

             *vect* should contain "%i" where the vector indices should be
             inserted; the vector will be indexed according to the choice of
             *slice_axis* (see below).  *vect* will be appended to the names of
             the subregions (separated by '.') in order to determine the full
             names of the vectors.

        - *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)" is 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)

             If *xlabel* is *None*, then the axis is labeled with "X Axis",
             "Y Axis", or "Z Axis" (as appropriate).

        - *xticklabels*: Labels for the x-axis ticks

             X-axis ticks are only shown for the subplots on the bottom row.
             If *xticklabels* is *None*, then the tick labels are "1", "2", ...

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

             If *ylabel* is *None*, then the axis is labeled with "X Axis",
             "Y Axis", or "Z Axis" (as appropriate).

        - *yticklabels*: Labels for the y-axis ticks

             Y-axis ticks are only shown for the subplots on the left column.
             If *None*, then the tick labels are "1", "2", ...

        - *margin_left*: Left margin

        - *margin_right*: Right margin

        - *margin_bottom*: Bottom margin

        - *margin_top*: Top margin

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

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

        - *\*\*kwargs*: Additional arguments for  :meth:`modelicares.base.quiver` (and
          thus to :meth:`matplotlib.pyplot.quiver`)
        """
        # The quiver() scaling is static and manual; therefore, it shouldn't be
        # necessary to coordinate the scaling among subplots like it is for
        # colorfig().

        # TODO 10/31/11:
        # 1) Move the dots and the pivots to the centers of masses of the
        #    subregions.
        # 2) Use and show a grid that is in scale with the geometry of the
        #    subregions (create a separate method for this it so that it can be
        #    used for colorfig too; x and y scales would need to be different).
        # 3) Overlay the velocities at the faces with the velocities of the
        #    subregions (by calling this method again with hold on?).

        from res import quiver

        # Change the default quiver color.
        color = kwargs.pop('color', 'b')

        # Slice the subregions and retrieve the data.
        (us, vs), (n_x, n_y), unit, blanks = self.get_vector_comps2D(
            slice_axis, slice_index, vect, times)

        # Generate xlabel, xticks, and xticklabels.
        if xlabel is None:
            xlabel = ('y-axis index' if slice_axis == 'x' else 'z-axis index'
                      if slice_axis == 'y' else 'x-axis index')
        if xticklabels is None:
            xticklabels = [str(i+1) for i in range(n_x)]
        xticks = range(n_x)
        #xticks = [0,1,2,10] # TODO temp

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

        # Set up the subplots.
        n_plots = len(times) # Number of plots
        if not subtitles:
            subtitles = self.gen_subtitles_time(times)
        axs, n_cols = 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,
            margin_left=margin_left, margin_right=margin_right,
            margin_bottom=margin_bottom, margin_top=margin_top,
            wspace=wspace, hspace=hspace)

        # Create the plots.
        # scale = 1e-6 # 1 um/s; Zero may cause trouble wth quiverkey() TODO ?
        quivers = []
        scale = 0
        for ax, u, v in zip(axs, us, vs):
            quivers.append(quiver(ax, u, v, pad=2*0.5, color=color, **kwargs))
            # TODO test moving the locations
            #quivers.append(quiver(ax, x = [0,1,2,10], y = [0], u=u, v=v,
            #    **kwargs))

            # Add dots at the pivots.
            for i_x in range(n_x):
                for i_y in range(n_y):
                    ax.plot(i_x, i_y, marker='o', color='k',
                            markerfacecolor='w' if blanks[i_x][i_y] else 'k')

            # Find the maximum magnitude of the data.
            scale = max(scale, np.amax(np.abs(u)), np.amax(np.abs(v)))
        # TODO: Hack: For some reason, the last plot is badly scaled.  Update
        # it to match the one before it.
        if n_plots > 1:
            axs[-1].axis(axs[-2].axis())

        # Add the key.
        # Round the scale to one significant digit.
        pow10 = get_pow10(scale)
        scale = np.round(scale/10**pow10)*10**pow10
        axs[n_cols-1].quiverkey(Q=quivers[n_cols-1], X=1, Y=1.15, U=scale,
                                label=label_quantity(scale, unit),
                                labelpos='W')

        # Label the layers.
        self.label_layers(axs[len(axs)-n_cols:])
Example #7
0
def annotate_conditions(conditions, temp=True, composition=True,
                        pressure=True, humidity=True, flow=True):
    r"""Create a description of the operating conditions (e.g., to be used as a
    subtitle).

    **Arguments:**

    - *conditions*: Dictionary of operating conditions

         The dictionary may include the keys *T*, *p_an_out*, *p_ca_out*,
         *n_O2*, *p_an_out*, *p_ca_out*, *T_an_in*, *T_ca_in*, *anInletRH*,
         *caInletRH*, *anStoich*, and *caStoich*.  Any entry is missing, it will
         not be exclued.  Each entry is a tuple of (number, unit string) that
         describes a condition.

    - *temp*: *True*, if temperature should be included in the description

    - *composition*: *True*, if composition should be included in the
      description

    - *pressure*: *True*, if pressure should be included in the description

    - *humidity*: *True*, if humidity should be included in the description

    - *flow*: *True*, if the flow conditions (stoichiometry) should be included
      in the description

    **Example:**

       >>> conditions = dict(T = (60, 'degC'),
       ...                   p = (150, 'kPa'),
       ...                   n_O2 = (21, '%'),
       ...                   anInletRH = (80, '%'),
       ...                   caInletRH = (50, '%'),
       ...                   anStoich = (1.5, '1'),
       ...                   caStoich = (2.0, '1'))
       >>> annotate_conditions(conditions)
       '60$\\,^{\\circ}\\!C$, 150$\\,kPa$; An|Ca: $H_2$|Air, 80|50$\\!$$\\,\\%$$\\,$RH, 1.5|2.0$\\,$stoich'
    """
    # Main description
    main_desc = []
    if temp:
        try:
            main_desc += [label_quantity(*conditions['T'])]
            temp = False
            if 'T_an_in' in conditions:
                print("T_an_in will be ignored.")
            if 'T_ca_in' in conditions:
                print("T_ca_in will be ignored.")
        except KeyError:
            pass
    if pressure:
        try:
            main_desc += [label_quantity(*conditions['p'])]
            pressure = False
            if 'p_an_out' in conditions:
                print("p_an_out will be ignored.")
            if 'p_ca_out' in conditions:
                print("p_ca_out will be ignored.")
        except KeyError:
            pass
    main_desc = ", ".join(main_desc)

    # Anode/cathode description
    anca_desc = []
    if flow:
        try:
            anca_desc += ['%s|%sstoich' % (label_quantity(conditions['anStoich'][0],
                                                          format='%.1f'),
                                           label_quantity(*conditions['caStoich'],
                                                          format='%.1f'))]
        except KeyError:
            pass
    if composition:
        try:
            if conditions['n_O2'][0] == 1.0:
                anca_desc += ['$H_2$|$O_2$']
            else:
                anca_desc += ['$H_2$|Air']
        except KeyError:
            pass
    if temp:
        try:
            anca_desc += ['%s|%s' % (label_quantity(conditions['T_an_in'][0],
                                                    format='%.0f'),
                                     label_quantity(*conditions['T_ca_in'],
                                                    format='%.0f'))]
        except KeyError:
            pass
    if pressure:
        try:
            anca_desc += ['%s|%s' % (label_quantity(conditions['p_an_out'][0],
                                                    format='%.1f'),
                                     label_quantity(*conditions['p_ca_out'],
                                                    format='%.1f'))]
        except KeyError:
            pass
    if humidity:
        try:
            anca_desc += ['%s|%s$\,$RH' % (label_quantity(conditions['anInletRH'][0],
                                                       format='%.0f'),
                                        label_quantity(*conditions['caInletRH'],
                                                       format='%.0f'))]
        except KeyError:
            pass
    anca_desc = ", ".join(anca_desc)
    if anca_desc:
        anca_desc = "An|Ca: " + anca_desc

    # Finish.
    if not anca_desc:
        return main_desc
    if not main_desc:
        return anca_desc
    return main_desc + "; " + anca_desc
Example #8
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)