def secondary_locator(ax, renderer): # delay evaluating transform until draw time because the # parent transform may have changed (i.e. if window reesized) bb = mtransforms.TransformedBbox(_rect, parent.transAxes) tr = parent.figure.transFigure.inverted() bb = mtransforms.TransformedBbox(bb, tr) return bb
def _connect_spines(left_ax, right_ax, left_y, right_y, linestyle="solid", **line_kwds): """ Connects the y-spines between two Axes Parameters ---------- left_ax, right_ax : matplotlib Axes objects The Axes that need to be connected. left_y, right_y : float Values on the spines that wil be connected. linestyle : string, optional (default = 'solid') The line style to use. Valid values are 'solid', 'dashed', 'dashdot', 'dotted'. **line_kwds : keyword arguments Additional options for style the line. Returns ------- connector : BboxConnector The weird mpl-line-like-thingy that connects the spines. """ import matplotlib.transforms as mtrans import mpl_toolkits.axes_grid1.inset_locator as inset left_trans = mtrans.blended_transform_factory(left_ax.transData, left_ax.transAxes) right_trans = mtrans.blended_transform_factory(right_ax.transData, right_ax.transAxes) left_data_trans = left_ax.transScale + left_ax.transLimits right_data_trans = right_ax.transScale + right_ax.transLimits left_pos = left_data_trans.transform((0, left_y))[1] right_pos = right_data_trans.transform((0, right_y))[1] bbox = mtrans.Bbox.from_extents(0, left_pos, 0, right_pos) right_bbox = mtrans.TransformedBbox(bbox, right_trans) left_bbox = mtrans.TransformedBbox(bbox, left_trans) # deal with the linestyle connector = inset.BboxConnector(left_bbox, right_bbox, loc1=3, loc2=2, linestyle=linestyle, **line_kwds) connector.set_clip_on(False) left_ax.add_line(connector) return connector
def plot_barbs(self, p, u, v, c=None, xloc=1.0, x_clip_radius=0.08, y_clip_radius=0.08, **kwargs): r"""Plot wind barbs. Adds wind barbs to the skew-T plot. This is a wrapper around the `barbs` command that adds to appropriate transform to place the barbs in a vertical line, located as a function of pressure. Parameters ---------- p : array_like pressure values u : array_like U (East-West) component of wind v : array_like V (North-South) component of wind c: An optional array used to map colors to the barbs xloc : float, optional Position for the barbs, in normalized axes coordinates, where 0.0 denotes far left and 1.0 denotes far right. Defaults to far right. x_clip_radius : float, optional Space, in normalized axes coordinates, to leave before clipping wind barbs in the x-direction. Defaults to 0.08. y_clip_radius : float, optional Space, in normalized axes coordinates, to leave above/below plot before clipping wind barbs in the y-direction. Defaults to 0.08. kwargs Other keyword arguments to pass to :func:`~matplotlib.pyplot.barbs` Returns ------- matplotlib.quiver.Barbs instance created See Also -------- :func:`matplotlib.pyplot.barbs` """ # Assemble array of x-locations in axes space x = np.empty_like(p) x.fill(xloc) # Do barbs plot at this location if c is not None: b = self.ax.barbs(x, p, u, v, c, transform=self.ax.get_yaxis_transform(which='tick2'), clip_on=True, **kwargs) else: b = self.ax.barbs(x, p, u, v, transform=self.ax.get_yaxis_transform(which='tick2'), clip_on=True, **kwargs) # Override the default clip box, which is the axes rectangle, so we can have # barbs that extend outside. ax_bbox = transforms.Bbox([[xloc - x_clip_radius, -y_clip_radius], [xloc + x_clip_radius, 1.0 + y_clip_radius]]) b.set_clip_box(transforms.TransformedBbox(ax_bbox, self.ax.transAxes)) return b
def _set_lim_and_transforms(self): """ Override transform initialization """ # axis coords to display coords self.transAxes = transforms.BboxTransformTo(self.bbox) # X and Y axis scaling self.transScale = transforms.TransformWrapper( transforms.IdentityTransform()) # transform from given Bbox to unit Bbox # the given transformedBbox is updated every time the # viewLim changes or the transScale changes self.transLimits = transforms.BboxTransformFrom( transforms.TransformedBbox(self.viewLim, self.transScale)) # data to display coordinates self.transData = self.transScale + (self.transLimits + self.transAxes) # blended transforms for xaxis and yaxis self._xaxis_transform = transforms.blended_transform_factory( self.transData, self.transAxes) self._yaxis_transform = transforms.blended_transform_factory( self.transAxes, self.transData)
def axline(ax, slope, intercept, **kwargs): ''' originally described (July '18) in ../pluto/hole_areas.ipynb see https://github.com/dstansby/matplotlib/blob/49da75e46ccc4714009b124a58784eaeaea53970/lib/matplotlib/axes/_axes.py and https://github.com/matplotlib/matplotlib/pull/9321 ''' import matplotlib.transforms as mtransforms import matplotlib.lines as mlines if "transform" in kwargs: raise ValueError("'transform' is not allowed as a kwarg; " "axline generates its own transform.") xtrans = mtransforms.BboxTransformTo(ax.viewLim) viewLimT = mtransforms.TransformedBbox( ax.viewLim, mtransforms.Affine2D().rotate_deg(90).scale(-1, 1)) ytrans = (mtransforms.BboxTransformTo(viewLimT) + mtransforms.Affine2D().scale(slope).translate(0, intercept)) trans = mtransforms.blended_transform_factory(xtrans, ytrans) line = mlines.Line2D([0, 1], [0, 1], transform=trans + ax.transData, **kwargs) ax.add_line(line) return line
def plot_colorbars(fig, all_colorbars): """ Plot colorbars *after* tight_layout(), otherwise it will move them around. """ # Ignore warning issued by colorbar. with warnings.catch_warnings(): warnings.simplefilter("ignore") fig.tight_layout() # Plot colorbar down here so tight_layout won't move it around. for (plot_colorbar, sca, trans, v_min_mp, v_max_mp) in all_colorbars: if plot_colorbar is True: import matplotlib.transforms as mts # Position and dimensions relative to the axes. x0, y0, width, height = [0.74, 0.93, 0.2, 0.04] # Transform them to get the ABSOLUTE POSITION AND DIMENSIONS Bbox = mts.Bbox.from_bounds(x0, y0, width, height) l, b, w, h = mts.TransformedBbox(Bbox, trans).bounds # Create the axes and the colorbar. cbaxes = fig.add_axes([l, b, w, h]) cbar = plt.colorbar(sca, cax=cbaxes, ticks=[v_min_mp, v_max_mp], orientation='horizontal') cbar.ax.minorticks_off()
def make_image(self, magnification=1.0): if self._A is None: raise RuntimeError('You must first set the image' ' array or the image attribute') # image is created in the canvas coordinate. x1, x2, y1, y2 = self.get_extent() trans = self.get_transform() xy = trans.transform(np.array([(x1, y1), (x2, y2), ])) _x1, _y1 = xy[0] _x2, _y2 = xy[1] transformed_viewLim = mtransforms.TransformedBbox(self.axes.viewLim, trans) im, xmin, ymin, dxintv, dyintv, sx, sy = \ self._get_unsampled_image(self._A, [_x1, _x2, _y1, _y2], transformed_viewLim) fc = self.axes.patch.get_facecolor() bg = mcolors.colorConverter.to_rgba(fc, 0) im.set_bg(*bg) # image input dimensions im.reset_matrix() numrows, numcols = im.get_size() if numrows < 1 or numcols < 1: # out of range return None im.set_interpolation(self._interpd[self._interpolation]) im.set_resample(self._resample) # the viewport translation if dxintv == 0.0: tx = 0.0 else: tx = (xmin-transformed_viewLim.x0)/dxintv * numcols if dyintv == 0.0: ty = 0.0 else: ty = (ymin-transformed_viewLim.y0)/dyintv * numrows im.apply_translation(tx, ty) l, b, r, t = self.axes.bbox.extents widthDisplay = ((round(r*magnification) + 0.5) - (round(l*magnification) - 0.5)) heightDisplay = ((round(t*magnification) + 0.5) - (round(b*magnification) - 0.5)) # resize viewport to display rx = widthDisplay / numcols ry = heightDisplay / numrows im.apply_scaling(rx*sx, ry*sy) im.resize(int(widthDisplay+0.5), int(heightDisplay+0.5), norm=self._filternorm, radius=self._filterrad) return im
def axaline(m, y0, ax=None, **kwargs): if not ax: ax = plt.gca() tr = mtransforms.BboxTransformTo( mtransforms.TransformedBbox(ax.viewLim, ax.transScale)) + \ ax.transScale.inverted() aff = mtransforms.Affine2D.from_values(1, m, 0, 0, 0, y0) trinv = ax.transData line = plt.Line2D([0, 1], [0, 0], transform=tr + aff + trinv, **kwargs) ax.add_line(line)
def get_extent(self, renderer): bb = mtrans.TransformedBbox(self.axes.viewLim, self.parent_axes.transData) x, y, w, h = bb.bounds xd, yd = 0, 0 fontsize = renderer.points_to_pixels(self.prop.get_size_in_points()) pad = self.pad * fontsize return w*self.zoom+2*pad, h*self.zoom+2*pad, xd+pad, yd+pad
def _set_lim_and_transforms(self): super()._set_lim_and_transforms() transTernaryScale = TernaryScaleTransform(self.ternary_scale) transTLimits = mtransforms.BboxTransformFrom( mtransforms.TransformedBbox(self.viewTLim, self.transScale)) transLLimits = mtransforms.BboxTransformFrom( mtransforms.TransformedBbox(self.viewLLim, self.transScale)) transRLimits = mtransforms.BboxTransformFrom( mtransforms.TransformedBbox(self.viewRLim, self.transScale)) corners_axes = self.corners_axes taxis_transform = TernaryTransform(corners_axes, 0) laxis_transform = TernaryTransform(corners_axes, 1) raxis_transform = TernaryTransform(corners_axes, 2) self._taxis_transform = transTLimits + taxis_transform + self.transAxes self._laxis_transform = transLLimits + laxis_transform + self.transAxes self._raxis_transform = transRLimits + raxis_transform + self.transAxes # For axis labels t_l_t = TernaryPerpendicularTransform(self.transAxes, corners_axes, 0) l_l_t = TernaryPerpendicularTransform(self.transAxes, corners_axes, 1) r_l_t = TernaryPerpendicularTransform(self.transAxes, corners_axes, 2) self._taxis_label_transform = t_l_t self._laxis_label_transform = l_l_t self._raxis_label_transform = r_l_t # From ternary coordinates to the original data coordinates self.transProjection = (transTernaryScale + BarycentricTransform(self.corners_data)) # From ternary coordinates to the original Axes coordinates self._ternary_axes_transform = self.transProjection + self.transLimits # From barycentric coordinates to the original Axes coordinates self.transAxesProjection = BarycentricTransform(self.corners_axes) # From barycentric coordinates to display coordinates self.transTernaryAxes = self.transAxesProjection + self.transAxes
def __call__(self, ax, renderer): fontsize = renderer.points_to_pixels(self.prop.get_size_in_points()) self._update_offset_func(renderer, fontsize) width, height, xdescent, ydescent = self.get_extent(renderer) px, py = self.get_offset(width, height, 0, 0, renderer) bbox_canvas = mtrans.Bbox.from_bounds(px, py, width, height) tr = ax.figure.transFigure.inverted() bb = mtrans.TransformedBbox(bbox_canvas, tr) return bb
def _make_secondary_locator(rect, parent): """ Helper function to locate the secondary axes. A locator gets used in `Axes.set_aspect` to override the default locations... It is a function that takes an axes object and a renderer and tells `set_aspect` where it is to be placed. This locator make the transform be in axes-relative co-coordinates because that is how we specify the "location" of the secondary axes. Here *rect* is a rectangle [l, b, w, h] that specifies the location for the axes in the transform given by *trans* on the *parent*. """ _rect = mtransforms.Bbox.from_bounds(*rect) bb = mtransforms.TransformedBbox(_rect, parent.transAxes) tr = parent.figure.transFigure.inverted() bb = mtransforms.TransformedBbox(bb, tr) def secondary_locator(ax, renderer): return bb return secondary_locator
def connect_spines(left_ax, right_ax, left_y, right_y, **line_kwds): left_trans = mtrans.blended_transform_factory(left_ax.transData, left_ax.transAxes) right_trans = mtrans.blended_transform_factory(right_ax.transData, right_ax.transAxes) left_data_trans = left_ax.transScale + left_ax.transLimits right_data_trans = right_ax.transScale + right_ax.transLimits left_pos = left_data_trans.transform((0, left_y))[1] right_pos = right_data_trans.transform((0, right_y))[1] bbox = mtrans.Bbox.from_extents(0, left_pos, 0, right_pos) right_bbox = mtrans.TransformedBbox(bbox, right_trans) left_bbox = mtrans.TransformedBbox(bbox, left_trans) connecter = inset.BboxConnector(left_bbox, right_bbox, loc1=3, loc2=2, **line_kwds) connecter.set_clip_on(False) return connecter
def axline(ax, slope, intercept, **kwargs): if "transform" in kwargs: raise ValueError("'transform' is not allowed as a kwarg; " "axline generates its own transform.") xtrans = mtransforms.BboxTransformTo(ax.viewLim) viewLimT = mtransforms.TransformedBbox( ax.viewLim, mtransforms.Affine2D().rotate_deg(90).scale(-1, 1)) ytrans = (mtransforms.BboxTransformTo(viewLimT) + mtransforms.Affine2D().scale(slope).translate(0, intercept)) trans = mtransforms.blended_transform_factory(xtrans, ytrans) l = mlines.Line2D([0, 1], [0, 1], transform=trans + ax.transData, **kwargs) ax.add_line(l) return l
def axcolorbar(cbobj, pos=[0.7, 0.8, 0.2, 0.04], ax=None, fig=None, orientation='horizontal', **kwargs): """ Inserts a colorbar with a position relative to an axes and not a figure Inputs: cbobj - plot object for colorbar pos - position vector [x0, y0, width, height] in dimensionless coordinates ax - axes to insert colobar figure - figure **kwargs - arguments for plt.colorbar Returns a colorbar object Derived from this post: http://stackoverflow.com/questions/22413211/cant-fix-position-of-colorbar-in-image-with-multiple-subplots """ if fig == None: fig = plt.gcf() if ax == None: ax = plt.gca() fig.tight_layout( ) # You call fig.tight_layout BEFORE creating the colorbar # You input the POSITION AND DIMENSIONS RELATIVE TO THE AXES x0, y0, width, height = pos # and transform them after to get the ABSOLUTE POSITION AND DIMENSIONS Bbox = transforms.Bbox.from_bounds(x0, y0, width, height) trans = ax.transAxes + fig.transFigure.inverted() l, b, w, h = transforms.TransformedBbox(Bbox, trans).bounds # Now just create the axes and the colorbar cbaxes = fig.add_axes([l, b, w, h]) cbar = plt.colorbar(cbobj, cax=cbaxes, orientation=orientation, **kwargs) cbar.ax.tick_params(labelsize=9) return cbar
def plot_observed_cluster(fig, gs, gs_y1, gs_y2, x_ax, y_ax, cl_max_mag, x_min_cmd, x_max_cmd, y_min_cmd, y_max_cmd, err_lst, v_min_mp, v_max_mp, obs_x, obs_y, obs_MPs, cl_sz_pt, hess_xedges, hess_yedges, x_isoch, y_isoch, phot_Nsigma): """ This function is called separately since we need to retrieve some information from it to plot that #$%&! colorbar. """ err_bar = prep_plots.error_bars(cl_max_mag, x_min_cmd, err_lst) # pl_mps_phot_diag plot_colorbar, sca, trans = mp_bestfit_CMD.pl_mps_phot_diag( gs, gs_y1, gs_y2, fig, x_min_cmd, x_max_cmd, y_min_cmd, y_max_cmd, x_ax, y_ax, v_min_mp, v_max_mp, obs_x, obs_y, obs_MPs, err_bar, cl_sz_pt, hess_xedges, hess_yedges, x_isoch, y_isoch, phot_Nsigma) # Ignore warning issued by colorbar plotted in photometric diagram with # membership probabilities. with warnings.catch_warnings(): warnings.simplefilter("ignore") fig.tight_layout() # Force to not plot colorbar after the first row. plot_colorbar = False if gs_y1 != 0 else plot_colorbar # Plot colorbar down here so tight_layout won't move it around. if plot_colorbar is True: import matplotlib.transforms as mts # Position and dimensions relative to the axes. x0, y0, width, height = [0.74, 0.93, 0.2, 0.04] # Transform them to get the ABSOLUTE POSITION AND DIMENSIONS Bbox = mts.Bbox.from_bounds(x0, y0, width, height) l, b, w, h = mts.TransformedBbox(Bbox, trans).bounds # Create the axes and the colorbar. cbaxes = fig.add_axes([l, b, w, h]) cbar = plt.colorbar(sca, cax=cbaxes, ticks=[v_min_mp, v_max_mp], orientation='horizontal') cbar.ax.minorticks_off()
def get_figure_bbox(fig, bbox) -> Tuple[float, float, float, float]: """Transforms a bounding box into units matching the dimension of `fig`. This can be used to transform pixel values to inches, which are internally used by Matplotlib. Args: fig (matplotlib.figure.Figure): A Matplotlib figure. bbox (matplotlib.transforms.Bbox): A bounding box. Returns: Tuple[float, float, float, float]: A bounding box in inches represented as a tuple `(x, y, width, height)`. """ trans_bbox = trans.TransformedBbox(bbox, fig.transFigure.inverted()) x = trans_bbox.xmin y = trans_bbox.ymin width = trans_bbox.width height = trans_bbox.height return (x, y, width, height)
def __init__(self, ax, img=None, mask_shape=None, canmove=True, size=None): self.canmove = canmove self.ax = ax if size is None: size = 10 self.bbox = mtrans.Bbox(np.array([[0, 0], [10, 10]])) bbox = mtrans.TransformedBbox(self.bbox, ax.transData) self.mask_img = mimage.BboxImage(bbox, animated=True, alpha=0.6, zorder=1000) self.ax.add_artist(self.mask_img) self.create_mask(img, mask_shape) self.canvas = ax.figure.canvas self.event_ids = [ self.canvas.mpl_connect('motion_notify_event', self.on_move), self.canvas.mpl_connect('draw_event', self.on_draw), self.canvas.mpl_connect('button_press_event', self.on_press), self.canvas.mpl_connect('button_release_event', self.on_release), self.canvas.mpl_connect('scroll_event', self.on_scroll), ] self.circle = mpatches.Circle((0, 0), size, facecolor="red", alpha=0.5, animated=True) self.ax.add_patch(self.circle) self.mask_circle = mpatches.Circle((0, 0), 10, facecolor="white", lw=0) self.mask_line = plt.Line2D((0, 0), (0, 0), lw=18, solid_capstyle="round", color="white") self.background = None self.last_pos = None self.timer = Timer(40, self.check_dirty)
def __call__(self, ax, renderer): bbox_parent = self.parent.get_position(original=False) trans = mtrans.BboxTransformTo(bbox_parent) bbox_inset = mtrans.Bbox.from_bounds(*self.lbwh) bb = mtrans.TransformedBbox(bbox_inset, trans) return bb
def plot_barbs(self, pressure, u, v, c=None, xloc=1.0, x_clip_radius=0.1, y_clip_radius=0.08, **kwargs): r"""Plot wind barbs. Adds wind barbs to the skew-T plot. This is a wrapper around the `barbs` command that adds to appropriate transform to place the barbs in a vertical line, located as a function of pressure. Parameters ---------- pressure : array_like pressure values u : array_like U (East-West) component of wind v : array_like V (North-South) component of wind c: An optional array used to map colors to the barbs xloc : float, optional Position for the barbs, in normalized axes coordinates, where 0.0 denotes far left and 1.0 denotes far right. Defaults to far right. x_clip_radius : float, optional Space, in normalized axes coordinates, to leave before clipping wind barbs in the x-direction. Defaults to 0.1. y_clip_radius : float, optional Space, in normalized axes coordinates, to leave above/below plot before clipping wind barbs in the y-direction. Defaults to 0.08. plot_units: `pint.unit` Units to plot in (performing conversion if necessary). Defaults to given units. kwargs Other keyword arguments to pass to :func:`~matplotlib.pyplot.barbs` Returns ------- matplotlib.quiver.Barbs instance created See Also -------- :func:`matplotlib.pyplot.barbs` """ # If plot_units specified, convert the data to those units plotting_units = kwargs.pop('plot_units', None) if plotting_units: if hasattr(u, 'units') and hasattr(v, 'units'): u = u.to(plotting_units) v = v.to(plotting_units) else: raise ValueError( 'To convert to plotting units, units must be attached to ' 'u and v wind components.') # Assemble array of x-locations in axes space x = np.empty_like(pressure) x.fill(xloc) # Do barbs plot at this location if c is not None: b = self.ax.barbs( x, pressure, u, v, c, transform=self.ax.get_yaxis_transform(which='tick2'), clip_on=True, zorder=2, **kwargs) else: b = self.ax.barbs( x, pressure, u, v, transform=self.ax.get_yaxis_transform(which='tick2'), clip_on=True, zorder=2, **kwargs) # Override the default clip box, which is the axes rectangle, so we can have # barbs that extend outside. ax_bbox = transforms.Bbox([[xloc - x_clip_radius, -y_clip_radius], [xloc + x_clip_radius, 1.0 + y_clip_radius]]) b.set_clip_box(transforms.TransformedBbox(ax_bbox, self.ax.transAxes)) return b
def axline(a, b, **kwargs): """ Add an infinite straight line across an axis. Parameters ---------- a, b: scalar or tuple Acceptable forms are y0, b: y = y0 + b * x (x0, y0), b: y = y0 + b * (x - x0) (x0, y0), (x1, y1): y = y0 + (y1 - y0) / (x1 - x0) * (x - x0) Additional arguments are passed to the <matplotlib.lines.Line2D> constructor. Returns ------- :class:`~matplotlib.lines.Line2D` Other Parameters ---------------- Valid kwargs are :class:`~matplotlib.lines.Line2D` properties, with the exception of 'transform': %(Line2D)s Examples -------- * Draw a thick red line with slope 1 and y-intercept 0:: >>> axline(0, 1, linewidth=4, color='r') * Draw a default line with slope 1 and y-intercept 1:: >>> axline(1, 1) See Also -------- axhline : for horizontal lines axvline : for vertical lines Notes ----- Currently this method does not work properly with log scaled axes. Taken from https://github.com/matplotlib/matplotlib/pull/9321 """ from matplotlib import pyplot as plt import matplotlib.transforms as mtransforms import matplotlib.lines as mlines if np.isscalar(a): if not np.isscalar(b): raise ValueError("Invalid line parameters.") point, slope = (0, a), b elif np.isscalar(b): if not len(a) == 2: raise ValueError("Invalid line parameters.") point, slope = a, b else: if not len(a) == len(b) == 2: raise ValueError("Invalid line parameters.") if b[0] != a[0]: point, slope = a, (b[1] - a[1]) / (b[0] - a[0]) else: point, slope = a, np.inf ax = plt.gca() if "transform" in kwargs: raise ValueError("'transform' is not allowed as a kwarg; " "axline generates its own transform.") if slope == 0: return ax.axhline(point[1], **kwargs) elif np.isinf(slope): return ax.axvline(point[0], **kwargs) xtrans = mtransforms.BboxTransformTo(ax.viewLim) viewLimT = mtransforms.TransformedBbox( ax.viewLim, mtransforms.Affine2D().rotate_deg(90).scale(-1, 1)) ytrans = (mtransforms.BboxTransformTo(viewLimT) + mtransforms.Affine2D().scale(slope).translate(*point)) trans = mtransforms.blended_transform_factory(xtrans, ytrans) line = mlines.Line2D([0, 1], [0, 1], transform=trans + ax.transData, **kwargs) ax.add_line(line) return line
def _set_lim_and_transforms(self): # A view limit where the minimum radius can be locked if the user # specifies an alternate origin. self._originViewLim = mtransforms.LockableBbox(self.viewLim) # Handle angular offset and direction. self._direction = mtransforms.Affine2D() \ .scale(self._default_theta_direction, 1.0) self._theta_offset = mtransforms.Affine2D() \ .translate(self._default_theta_offset, 0.0) self.transShift = self._direction + self._theta_offset # A view limit shifted to the correct location after accounting for # orientation and offset. self._realViewLim = mtransforms.TransformedBbox( self.viewLim, self.transShift) # Transforms the x and y axis separately by a scale factor # It is assumed that this part will have non-linear components self.transScale = mtransforms.TransformWrapper( mtransforms.IdentityTransform()) # Scale view limit into a bbox around the selected wedge. This may be # smaller than the usual unit axes rectangle if not plotting the full # circle. self.axesLim = _WedgeBbox((0.5, 0.5), self._realViewLim, self._originViewLim) # Scale the wedge to fill the axes. self.transWedge = mtransforms.BboxTransformFrom(self.axesLim) # Scale the axes to fill the figure. self.transAxes = mtransforms.BboxTransformTo(self.bbox) # A (possibly non-linear) projection on the (already scaled) # data. This one is aware of rmin self.transProjection = self.PolarTransform( self, _apply_theta_transforms=False) # Add dependency on rorigin. self.transProjection.set_children(self._originViewLim) # An affine transformation on the data, generally to limit the # range of the axes self.transProjectionAffine = self.PolarAffine(self.transScale, self._originViewLim) # The complete data transformation stack -- from data all the # way to display coordinates self.transData = ( self.transScale + self.transShift + self.transProjection + (self.transProjectionAffine + self.transWedge + self.transAxes)) # This is the transform for theta-axis ticks. It is # equivalent to transData, except it always puts r == 0.0 and r == 1.0 # at the edge of the axis circles. self._xaxis_transform = (mtransforms.blended_transform_factory( mtransforms.IdentityTransform(), mtransforms.BboxTransformTo(self.viewLim)) + self.transData) # The theta labels are flipped along the radius, so that text 1 is on # the outside by default. This should work the same as before. flipr_transform = mtransforms.Affine2D() \ .translate(0.0, -0.5) \ .scale(1.0, -1.0) \ .translate(0.0, 0.5) self._xaxis_text_transform = flipr_transform + self._xaxis_transform # This is the transform for r-axis ticks. It scales the theta # axis so the gridlines from 0.0 to 1.0, now go from thetamin to # thetamax. self._yaxis_transform = (mtransforms.blended_transform_factory( mtransforms.BboxTransformTo(self.viewLim), mtransforms.IdentityTransform()) + self.transData) # The r-axis labels are put at an angle and padded in the r-direction self._r_label_position = mtransforms.Affine2D() \ .translate(self._default_rlabel_position, 0.0) self._yaxis_text_transform = mtransforms.TransformWrapper( self._r_label_position + self.transData)
def main(output_subdir, clust_name, x_data, y_data, bin_width, center_params, rdp_params, field_dens, radius_params, cont_index, mag_data, col_data, err_plot, err_flags, kp_params, cl_region, stars_out, stars_in_rjct, stars_out_rjct, integr_return, n_memb, n_memb_da, flag_no_fl_regs, field_regions, flag_pval_test, pval_test_params, decont_algor_return, lum_func, completeness, ip_list, red_return, err_lst, bf_return): ''' Make all plots. ''' # Unpack params. # Parameters from get_center function. cent_bin, center_cl, e_cent, approx_cents, st_dev_lst, hist_2d_g, \ kde_pl = center_params[:7] # RDP params. radii, ring_density, poisson_error = rdp_params[:3] # Parameters from get_radius function. clust_rad, e_rad = radius_params[:2] # Luminosity functions. x_cl, y_cl, x_fl, y_fl = lum_func # Best fitting process results. isoch_fit_params, isoch_fit_errors, shift_isoch, synth_clst, syn_b_edges =\ bf_return # Plot all outputs # figsize(x1, y1), GridSpec(y2, x2) --> To have square plots: x1/x2 = # y1/y2 = 2.5 fig = plt.figure(figsize=(30, 25)) # create the top-level container gs = gridspec.GridSpec(10, 12) # create a GridSpec object # Add version number to top left. ver = '[ASteCA ' + __version__ + ']' x_coord = 0.957 - (len(__version__) - 6) * 0.001 plt.figtext(x_coord, .988, ver, fontsize=9, color='#585858') # Obtain plotting parameters and data. x_min, x_max, y_min, y_max = prep_plots.frame_max_min(x_data, y_data) asp_ratio = prep_plots.aspect_ratio(x_min, x_max, y_min, y_max) coord, x_name, y_name = prep_plots.coord_syst() x_zmin, x_zmax, y_zmin, y_zmax = prep_plots.frame_zoomed( x_min, x_max, y_min, y_max, center_cl, clust_rad) x_ax, y_ax, x_ax0, y_axis = prep_plots.ax_names() phot_x, phot_y = prep_plots.ax_data(mag_data, col_data) x_max_cmd, x_min_cmd, y_min_cmd, y_max_cmd = prep_plots.diag_limits( y_axis, phot_x, phot_y) x_data_z, y_data_z, mag_data_z, stars_f_rjct, stars_f_acpt = \ prep_plots.separate_stars(x_data, y_data, mag_data, x_zmin, x_zmax, y_zmin, y_zmax, stars_out_rjct, field_regions) st_sizes_arr = prep_plots.star_size(mag_data) st_sizes_arr_z = prep_plots.star_size(mag_data_z) f_sz_pt = prep_plots.phot_diag_st_size(len(stars_f_acpt[0])) cl_sz_pt = prep_plots.phot_diag_st_size(len(cl_region)) v_min_mp, v_max_mp, plot_colorbar, chart_fit_inv, chart_no_fit_inv, \ out_clust_rad, diag_fit_inv, diag_no_fit_inv, err_bar = \ prep_plots.da_plots(center_cl, clust_rad, stars_out, x_zmin, x_zmax, y_zmin, y_zmax, x_max_cmd, col_data, err_lst, red_return) # # Structure plots. arglist = [ # pl_hist_g: 2D Gaussian convolved histogram. [gs, fig, asp_ratio, x_name, y_name, coord, cent_bin, clust_rad, bin_width, hist_2d_g], # pl_centers: 2D Gaussian histograms' centers. [gs, x_name, y_name, coord, x_min, x_max, y_min, y_max, asp_ratio, approx_cents, bin_width, st_dev_lst], # pl_full_frame: x,y finding chart of full frame. [gs, fig, x_name, y_name, coord, x_min, x_max, y_min, y_max, asp_ratio, center_cl, clust_rad, e_cent, kp_params, mag_data, x_data, y_data, st_sizes_arr], # pl_rad_dens: Radial density plot. [gs, radii, ring_density, field_dens, coord, clust_name, kp_params, clust_rad, e_rad, poisson_error, bin_width], # pl_zoom_frame: Zoom on x,y finding chart. [gs, fig, x_name, y_name, coord, x_zmin, x_zmax, y_zmin, y_zmax, cont_index, kde_pl, x_data_z, y_data_z, st_sizes_arr_z, center_cl, clust_rad], # pl_cl_fl_regions: Cluster and field regions defined. [gs, fig, x_name, y_name, coord, x_min, x_max, y_min, y_max, asp_ratio, center_cl, clust_rad, field_regions, cl_region, flag_no_fl_regs] ] for n, args in enumerate(arglist): # with timeblock("{}".format(n)): mp_structure.plot(n, *args) # # Photometric analysis plots. arglist = [ # pl_phot_err: Photometric error rejection. [gs, fig, 'up', x_ax, y_ax, mag_data, err_plot, err_flags, cl_region, stars_in_rjct, stars_out, stars_out_rjct], [gs, fig, 'low', x_ax, y_ax, mag_data, err_plot, err_flags, cl_region, stars_in_rjct, stars_out, stars_out_rjct], # pl_fl_diag: Field stars CMD/CCD diagram. [gs, x_min_cmd, x_max_cmd, y_min_cmd, y_max_cmd, x_ax, y_ax, stars_f_rjct, stars_f_acpt, f_sz_pt], # pl_cl_diag: Cluster's stars diagram (stars inside cluster's radius) [gs, x_min_cmd, x_max_cmd, y_min_cmd, y_max_cmd, x_ax, y_ax, stars_in_rjct, cl_region, n_memb, cl_sz_pt], # pl_lum_func: LF of stars in cluster region and outside. [gs, mag_data, y_ax, x_cl, y_cl, flag_no_fl_regs, x_fl, y_fl, completeness], # pl_integ_mag: Integrated magnitudes. [gs, integr_return, y_ax, x_ax0, flag_no_fl_regs], # pl_p_vals: Distribution of KDE p_values. [gs, flag_pval_test, pval_test_params] ] for n, args in enumerate(arglist): mp_phot_analysis.plot(n, *args) # # Decontamination algorithm plots. flag_decont_skip = decont_algor_return[1] mode_red_memb = g.rm_params[0] bf_flag = g.bf_params[0] # If the DA and the best fit functions were skipped and the reduced # membership mode is any mode but 'local', do not plot. if flag_decont_skip and bf_flag is False and mode_red_memb != 'local': pass else: arglist = [ [gs, n_memb_da, red_return, decont_algor_return], [gs, fig, x_name, y_name, coord, x_zmin, x_zmax, y_zmin, y_zmax, center_cl, clust_rad, field_dens, flag_decont_skip, v_min_mp, v_max_mp, chart_fit_inv, chart_no_fit_inv, out_clust_rad] ] for n, args in enumerate(arglist): mp_decont_algor.plot(n, *args) # This function is called separately since we need to retrieve some # information from it to plot that #$%&! colorbar. try: sca, trans = mp_decont_algor.pl_mps_phot_diag( gs, fig, x_min_cmd, x_max_cmd, y_min_cmd, y_max_cmd, x_ax, y_ax, v_min_mp, v_max_mp, red_return, diag_fit_inv, diag_no_fit_inv, shift_isoch, err_bar) except: # import traceback # print traceback.format_exc() print(" WARNING: error when plotting MPs on cluster's " "photom diagram.") # # Best fit plots. if bf_flag: arglist = [ # pl_bf_synth_cl: Best fit synthetic cluster obtained. [gs, x_min_cmd, x_max_cmd, y_min_cmd, y_max_cmd, x_ax, y_ax, synth_clst, syn_b_edges, isoch_fit_params[0], isoch_fit_errors, shift_isoch] ] for n, args in enumerate(arglist): mp_best_fit.plot(n, *args) # Best fitting process plots for GA. best_fit_algor = g.bf_params[1] if bf_flag and best_fit_algor == 'genet': min_max_p = prep_plots.param_ranges(ip_list) # Get special axis ticks for metallicity. xp_min, xp_max = min_max_p[0] # The maximum number of characters in the axis, '30', is HARD-CODED. # Add values to the end of this list. min_max_p.append(prep_plots.BestTick(xp_min, xp_max, 30)) # Unpack. lkl_old, new_bs_indx, model_done = isoch_fit_params[1:4] l_min_max = prep_plots.likl_y_range(lkl_old) arglist = [ # pl_ga_lkl: Likelihood evolution for the GA. [gs, l_min_max, lkl_old, model_done, new_bs_indx], # pl_2_param_dens: Parameter vs parameters solutions scatter map. [gs, 'age-metal', min_max_p, isoch_fit_params, isoch_fit_errors, model_done], [gs, 'dist-ext', min_max_p, isoch_fit_params, isoch_fit_errors, model_done], [gs, 'metal-dist', min_max_p, isoch_fit_params, isoch_fit_errors, model_done], [gs, 'mass-binar', min_max_p, isoch_fit_params, isoch_fit_errors, model_done], # pl_lkl_dens: Parameter likelihood density plot. [gs, '$z$', min_max_p, isoch_fit_params, isoch_fit_errors, model_done], [gs, '$log(age)$', min_max_p, isoch_fit_params, isoch_fit_errors, model_done], [gs, '$E_{{(B-V)}}$', min_max_p, isoch_fit_params, isoch_fit_errors, model_done], [gs, '$(m-M)_o$', min_max_p, isoch_fit_params, isoch_fit_errors, model_done], [gs, '$M\,(M_{{\odot}})$', min_max_p, isoch_fit_params, isoch_fit_errors, model_done], [gs, '$b_{{frac}}$', min_max_p, isoch_fit_params, isoch_fit_errors, model_done] ] for n, args in enumerate(arglist, 1): mp_best_fit.plot(n, *args) # Ignore warning issued by colorbar plotted in photometric diagram with # membership probabilities. with warnings.catch_warnings(): warnings.simplefilter("ignore") fig.tight_layout() # Plot colorbar down here so tight_layout won't move it around. try: if plot_colorbar is True: import matplotlib.transforms as mts # Position and dimensions relative to the axes. x0, y0, width, height = [0.67, 0.92, 0.2, 0.04] # Transform them to get the ABSOLUTE POSITION AND DIMENSIONS Bbox = mts.Bbox.from_bounds(x0, y0, width, height) l, b, w, h = mts.TransformedBbox(Bbox, trans).bounds # Create the axes and the colorbar. cbaxes = fig.add_axes([l, b, w, h]) cbar = plt.colorbar(sca, cax=cbaxes, ticks=[v_min_mp, v_max_mp], orientation='horizontal') cbar.ax.tick_params(labelsize=9) except: # import traceback # print traceback.format_exc() print(" WARNING: error when plotting colorbar on cluster's " "photometric diagram.") # Generate output file for each data file. pl_fmt, pl_dpi = g.pl_params[1:3] plt.savefig(join(output_subdir, str(clust_name) + '.' + pl_fmt), dpi=pl_dpi) # Close to release memory. plt.clf() plt.close() print 'Plots created.'