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:])
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:])
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)
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)