def test_curvelinear3(): fig = plt.figure(figsize=(5, 5)) fig.clf() tr = (mtransforms.Affine2D().scale(np.pi / 180, 1) + mprojections.PolarAxes.PolarTransform()) grid_locator1 = angle_helper.LocatorDMS(15) tick_formatter1 = angle_helper.FormatterDMS() grid_locator2 = FixedLocator([2, 4, 6, 8, 10]) grid_helper = GridHelperCurveLinear(tr, extremes=(0, 360, 10, 3), grid_locator1=grid_locator1, grid_locator2=grid_locator2, tick_formatter1=tick_formatter1, tick_formatter2=None) ax1 = FloatingSubplot(fig, 111, grid_helper=grid_helper) fig.add_subplot(ax1) r_scale = 10 tr2 = mtransforms.Affine2D().scale(1, 1 / r_scale) + tr grid_locator2 = FixedLocator([30, 60, 90]) grid_helper2 = GridHelperCurveLinear(tr2, extremes=(0, 360, 10 * r_scale, 3 * r_scale), grid_locator2=grid_locator2) ax1.axis["right"] = axis = grid_helper2.new_fixed_axis("right", axes=ax1) ax1.axis["left"].label.set_text("Test 1") ax1.axis["right"].label.set_text("Test 2") for an in ["left", "right"]: ax1.axis[an].set_visible(False) axis = grid_helper.new_floating_axis(1, 7, axes=ax1, axis_direction="bottom") ax1.axis["z"] = axis axis.toggle(all=True, label=True) axis.label.set_text("z = ?") axis.label.set_visible(True) axis.line.set_color("0.5") ax2 = ax1.get_aux_axes(tr) xx, yy = [67, 90, 75, 30], [2, 5, 8, 4] ax2.scatter(xx, yy) l, = ax2.plot(xx, yy, "k-") l.set_clip_path(ax1.patch)
def test_curvelinear4(): # Remove this line when this test image is regenerated. plt.rcParams['text.kerning_factor'] = 6 fig = plt.figure(figsize=(5, 5)) tr = (mtransforms.Affine2D().scale(np.pi / 180, 1) + mprojections.PolarAxes.PolarTransform()) grid_locator1 = angle_helper.LocatorDMS(5) tick_formatter1 = angle_helper.FormatterDMS() grid_locator2 = FixedLocator([2, 4, 6, 8, 10]) grid_helper = GridHelperCurveLinear(tr, extremes=(120, 30, 10, 0), grid_locator1=grid_locator1, grid_locator2=grid_locator2, tick_formatter1=tick_formatter1, tick_formatter2=None) ax1 = FloatingSubplot(fig, 111, grid_helper=grid_helper) fig.add_subplot(ax1) ax1.axis["left"].label.set_text("Test 1") ax1.axis["right"].label.set_text("Test 2") for an in ["top"]: ax1.axis[an].set_visible(False) axis = grid_helper.new_floating_axis(1, 70, axes=ax1, axis_direction="bottom") ax1.axis["z"] = axis axis.toggle(all=True, label=True) axis.label.set_axis_direction("top") axis.label.set_text("z = ?") axis.label.set_visible(True) axis.line.set_color("0.5") ax2 = ax1.get_aux_axes(tr) xx, yy = [67, 90, 75, 30], [2, 5, 8, 4] ax2.scatter(xx, yy) l, = ax2.plot(xx, yy, "k-") l.set_clip_path(ax1.patch)
def test_curvelinear3(): fig = plt.figure(figsize=(5, 5)) tr = (mtransforms.Affine2D().scale(np.pi / 180, 1) + mprojections.PolarAxes.PolarTransform()) grid_locator1 = angle_helper.LocatorDMS(15) tick_formatter1 = angle_helper.FormatterDMS() grid_locator2 = FixedLocator([2, 4, 6, 8, 10]) grid_helper = GridHelperCurveLinear( tr, extremes=(0, 360, 10, 3), grid_locator1=grid_locator1, grid_locator2=grid_locator2, tick_formatter1=tick_formatter1, tick_formatter2=None, ) ax1 = FloatingSubplot(fig, 111, grid_helper=grid_helper) fig.add_subplot(ax1) r_scale = 10 tr2 = mtransforms.Affine2D().scale(1, 1 / r_scale) + tr grid_locator2 = FixedLocator([30, 60, 90]) grid_helper2 = GridHelperCurveLinear(tr2, extremes=(0, 360, 10 * r_scale, 3 * r_scale), grid_locator2=grid_locator2) ax1.axis["right"] = axis = grid_helper2.new_fixed_axis("right", axes=ax1) ax1.axis["left"].label.set_text("Test 1") ax1.axis["right"].label.set_text("Test 2") for an in ["left", "right"]: ax1.axis[an].set_visible(False) axis = grid_helper.new_floating_axis(1, 7, axes=ax1, axis_direction="bottom") ax1.axis["z"] = axis axis.toggle(all=True, label=True) axis.label.set_text("z = ?") axis.label.set_visible(True) axis.line.set_color("0.5") ax2 = ax1.get_aux_axes(tr) xx, yy = [67, 90, 75, 30], [2, 5, 8, 4] ax2.scatter(xx, yy) (l, ) = ax2.plot(xx, yy, "k-") l.set_clip_path(ax1.patch)
def __init__(self, figure): self.figure = figure self.the_min = 0 self.the_max = 360 self.r_min = 0 self.r_max = 20 self.the_label = 'The' self.r_label = 'R' # --- tr_scale = Affine2D().scale(np.pi / 180., 1.) tr = tr_scale + PolarAxes.PolarTransform() grid_helper = GridHelperCurveLinear(tr) a = FloatingSubplot(self.figure, 111, grid_helper=grid_helper) self.figure.add_subplot(a) # --- # adjust x axis (theta): a["bottom"].set_visible(False) a.axis["top"].set_axis_direction("bottom") # tick direction a.axis["top"].major_ticklabels.set_axis_direction("top") a.axis["top"].label.set_axis_direction("top") # adjust y axis (r): a.axis["left"].set_axis_direction("bottom") # tick direction a.axis["right"].set_axis_direction("top") # tick direction # --- # create a parasite axes whose transData is theta, r: self.plt = a.get_aux_axes(tr) # make aux_ax to have a clip path as in a?: self.patch = a.patch # this has a side effect that the patch is drawn twice, and possibly over some other # artists. So, we decrease the zorder a bit to prevent this: a.patch.zorder = -2 self.plt.add_artist(plt.Circle([0, 0]))
def plot_polar_heatmap(data, name, interp_factor=5., color_limits=False, hide_colorbar=False, vmin=None, vmax=None, log_scale=True, dpi=200, output_dir=None): """Plots the polar heatmap describing azimuth and latitude / elevation components. Plots the polar heatmap where each cell of the heatmap corresponds to the specific element of the array provided by `gather_polar_errors` function. Parameters ---------- data : 2D array Indicates the array containing the sum of angular errors within the specified angular ranges. It is usually provided by `gather_polar_errors` function. name : str Indicates the name of the output png file. interp_factor : float Indicates the interpolation factor of the heatmap. color_limits : boolean Specifies if the determined intensity limits should be returned. hide_colorbar : boolean Specifies if the colorbar should be hidden. vmin : float Indicates the minimum value of the colorbar. vmax : float Indicates the maximum value of the colorbar. log_scale : float Specifies if the heatmap sould be in the logarithmic scale. dpi : integer Indicates the DPI of the output image. output_dir : str Indicates the path to the output folder where the image will be stored. """ th0, th1 = 0., 180. r0, r1 = 0, 90 thlabel, rlabel = 'Azimuth', 'Elevation' tr_scale = Affine2D().scale(np.pi / 180., 1.) tr = tr_scale + PolarAxes.PolarTransform() lat_ticks = [(.0 * 90., '0$^{\circ}$'), (.33 * 90., '30$^{\circ}$'), (.66 * 90., '60$^{\circ}$'), (1. * 90., '90$^{\circ}$')] r_grid_locator = FixedLocator([v for v, s in lat_ticks]) r_grid_formatter = DictFormatter(dict(lat_ticks)) angle_ticks = [(0 * 180., '90$^{\circ}$'), (.25 * 180., '45$^{\circ}$'), (.5 * 180., '0$^{\circ}$'), (.75 * 180., '-45$^{\circ}$'), (1. * 180., '-90$^{\circ}$')] theta_grid_locator = FixedLocator([v for v, s in angle_ticks]) theta_tick_formatter = DictFormatter(dict(angle_ticks)) grid_helper = GridHelperCurveLinear(tr, extremes=(th0, th1, r0, r1), grid_locator1=theta_grid_locator, grid_locator2=r_grid_locator, tick_formatter1=theta_tick_formatter, tick_formatter2=r_grid_formatter) fig = plt.figure() ax = floating_axes.FloatingSubplot(fig, 111, grid_helper=grid_helper) fig.add_subplot(ax) ax.set_facecolor('white') ax.axis["bottom"].set_visible(False) ax.axis["top"].toggle(ticklabels=True, label=True) ax.axis["top"].set_axis_direction("bottom") ax.axis["top"].major_ticklabels.set_axis_direction("top") ax.axis["top"].label.set_axis_direction("top") ax.axis["left"].set_axis_direction("bottom") ax.axis["right"].set_axis_direction("top") ax.axis["top"].label.set_text(thlabel) ax.axis["left"].label.set_text(rlabel) aux_ax = ax.get_aux_axes(tr) aux_ax.patch = ax.patch ax.patch.zorder = 0.9 rad = np.linspace(0, 90, data.shape[1]) azm = np.linspace(0, 180, data.shape[0]) f = interpolate.interp2d(rad, azm, data, kind='linear', bounds_error=True, fill_value=0) new_rad = np.linspace(0, 90, 180 * interp_factor) new_azm = np.linspace(0, 180, 360 * interp_factor) new_data_angle_dist = f(new_rad, new_azm) new_r, new_th = np.meshgrid(new_rad, new_azm) new_data_angle_dist += 1. if log_scale: data_mesh = aux_ax.pcolormesh( new_th, new_r, new_data_angle_dist, cmap='jet', norm=colors.LogNorm( vmin=1. if vmin is None else vmin, vmax=new_data_angle_dist.max() if vmax is None else vmax)) else: data_mesh = aux_ax.pcolormesh(new_th, new_r, new_data_angle_dist, cmap='jet', vmin=vmin, vmax=vmax) cbar = plt.colorbar(data_mesh, orientation='vertical', shrink=.88, pad=.1, aspect=15) cbar.ax.set_ylabel('Absolute error, [deg.]') if hide_colorbar: cbar.remove() ax.grid(False) plt.show() if output_dir is not None: if not os.path.exists(output_dir): os.makedirs(output_dir) fig.savefig(os.path.join(output_dir, f'{name}_chart.png'), transparent=False, bbox_inches='tight', pad_inches=0.1, dpi=dpi) if color_limits: return 1., new_data_angle_dist.max()
def fractional_polar_axes(f, thlim=(0, 180), rlim=(0, 1), step=(30, 0.25), thlabel='theta', rlabel='r', ticklabels=True, rlabels = None, subplot=111): '''Return polar axes that adhere to desired theta (in deg) and r limits. steps for theta and r are really just hints for the locators.''' th0, th1 = thlim # deg r0, r1 = rlim thstep, rstep = step # scale degrees to radians: tr_scale = Affine2D().scale(np.pi/180., 1.) pa = PolarAxes tr = tr_scale + pa.PolarTransform() theta_grid_locator = angle_helper.LocatorDMS((th1-th0)//thstep) r_grid_locator = MaxNLocator((r1-r0)//rstep) theta_tick_formatter = angle_helper.FormatterDMS() if rlabels: rlabels = DictFormatter(rlabels) grid_helper = GridHelperCurveLinear(tr, extremes=(th0, th1, r0, r1), grid_locator1=theta_grid_locator, grid_locator2=r_grid_locator, tick_formatter1=theta_tick_formatter, tick_formatter2=rlabels) a = FloatingSubplot(f, subplot, grid_helper=grid_helper) f.add_subplot(a) # adjust x axis (theta): a.axis["bottom"].set_visible(False) a.axis["top"].set_axis_direction("bottom") # tick direction a.axis["top"].toggle(ticklabels=ticklabels, label=bool(thlabel)) a.axis["top"].major_ticklabels.set_axis_direction("top") a.axis["top"].label.set_axis_direction("top") a.axis["top"].major_ticklabels.set_pad(10) # adjust y axis (r): a.axis["left"].set_axis_direction("bottom") # tick direction a.axis["right"].set_axis_direction("top") # tick direction a.axis["left"].toggle(ticklabels=True, label=bool(rlabel)) # add labels: a.axis["top"].label.set_text(thlabel) a.axis["left"].label.set_text(rlabel) # create a parasite axes whose transData is theta, r: auxa = a.get_aux_axes(tr) # make aux_ax to have a clip path as in a?: auxa.patch = a.patch # this has a side effect that the patch is drawn twice, and possibly over some other # artists. So, we decrease the zorder a bit to prevent this: a.patch.zorder = -2 # add sector lines for both dimensions: thticks = grid_helper.grid_info['lon_info'][0] rticks = grid_helper.grid_info['lat_info'][0] for th in thticks[1:-1]: # all but the first and last auxa.plot([th, th], [r0, r1], ':', c='grey', zorder=-1, lw=0.5) for ri, r in enumerate(rticks): # plot first r line as axes border in solid black only if it isn't at r=0 if ri == 0 and r != 0: ls, lw, color = 'solid', 1, 'black' else: ls, lw, color = 'dashed', 0.5, 'grey' # From http://stackoverflow.com/a/19828753/2020363 auxa.add_artist(plt.Circle([0, 0], radius=r, ls=ls, lw=lw, color=color, fill=False, transform=auxa.transData._b, zorder=-1)) return auxa
def cone( ra, z, scale=0.5, orientation='horizontal', raaxis='min', ralim=None, zlim=None, hms=False, # cosmology=None, lookbtime=False, plot=None, fig=None, subnum=None, xlabel=r"$\alpha$", ylabel=r"$\mathsf{redshift}$", **kwargs): """ Make a wedge plot of RA/Dec vs redshift z, where RA/DEC are in degrees Parameters ---------- Input data angle : (n, ) array RA in degrees redshift : (n, ) array scale: 0.5 orientation: 'horizontal': increasing z along +ve xaxis 'vertical': increasing z along +ve yaxis angle in degrees: increasing z along the tilted axis raxis: 'min' | 'mid' | float default is 'min' RA value along which the cone plot is orientated horizontal or vertical ralim, zlim: list [ramin, rmax], list [zmin, zmax] default is taken from the lower/upper bound of the input data scatter: any kwargs compatible with plt.scatter hms: show RA labels in units of hours (if True) or degrees (if False) lookbtime: True/False plot: None 'scatter' | 'hexbin' etc fig: supply figure instance default None subnum: subplot number e.g. 111, 221 etc default None xlabel: r"$\alpha$" ylabel: r"$\mathsf{redshift}$" cosmology: dict Uses cosmolopy package to compute look-back time default cosmology is {'omega_M_0': 0.3, 'omega_lambda_0': 0.7, 'h': 0.72} kwargs ------ scatter = {'s': 4, 'marker': ','} Notes ----- --Decorations that can be done outside the code: Draw grids: ax.grid(True, alpha=0.2) Set title: ax.set_title('Wedge plot') --Look-back time as twin axis to redshift not yet implemented --In future plan is to able to put colorbar in the plot too. Using cmap option. """ # ------ Extents of ra and z if ralim: ramin, ramax = ralim else: ramin, ramax = ra.min(), ra.max() if zlim: zmin, zmax = zlim else: zmin, zmax = z.min(), z.max() # ----- Scale and Orientation of the wedge if orientation == 'horizontal': dirn = 0. elif orientation == 'vertical': dirn = 90. else: dirn = orientation if raaxis == 'min': raaxis = ramin elif raaxis == 'mid': raaxis = 0.5 * (ramin + ramax) # Tilt of a cone relative to minimum RA tr_rotate = Affine2D().translate(dirn / scale - raaxis, 0.0) # Scaling the opening angle tr_scale = Affine2D().scale(scale * np.pi / 180., 1.0) tr = tr_rotate + tr_scale + PolarAxes.PolarTransform() # ---- Grids if hms is True: grid_locator1 = angle_helper.LocatorHMS(4.0) tick_formatter1 = angle_helper.FormatterHMS() else: grid_locator1 = angle_helper.LocatorDMS(4.0) tick_formatter1 = angle_helper.FormatterDMS() grid_locator2 = MaxNLocator(10) grid_helper = GridHelperCurveLinear(tr, extremes=(ramin, ramax, zmin, zmax), grid_locator1=grid_locator1, grid_locator2=grid_locator2, tick_formatter1=tick_formatter1, tick_formatter2=None) # Figure properties if not fig: fig = plt.figure(figsize=(8, 7)) subnum = 111 ax = FloatingSubplot(fig, subnum, grid_helper=grid_helper) fig.add_subplot(ax) # adjust axis # Left, right, top represent z, lookbacktime, RA respectively. # right axes is for look-back time yet to be coded ax.axis["left"].set_axis_direction("bottom") ax.axis["right"].set_axis_direction("top") ax.axis["bottom"].set_visible(False) ax.axis["top"].set_axis_direction("bottom") ax.axis["top"].toggle(ticklabels=True, label=True) ax.axis["top"].major_ticklabels.set_axis_direction("top") ax.axis["top"].label.set_axis_direction("top") ax.axis["left"].label.set_text(ylabel) ax.axis["top"].label.set_text(xlabel) # create a parasite axes that transData in RA, z aux = ax.get_aux_axes(tr) aux.patch = ax.patch # for aux_ax to have a clip path as in ax ax.patch.zorder = 0.9 # but this has a side effect that the patch is # drawn twice, and possibly over some other # artists. So, we decrease the zorder a bit to # prevent this. if plot == 'scatter': aux.scatter(ra, z, **kwargs) # plt.tight_layout() # plt.show() return ax, aux, fig
def fractional_polar_axes(f, thlim=(0, 180), rlim=(0, 1), step=(30, 0.01), thlabel=r'$\alpha$', rlabel='z', ticklabels=True): import matplotlib.pyplot as plt from matplotlib.transforms import Affine2D from matplotlib.projections import PolarAxes from mpl_toolkits.axisartist import angle_helper from mpl_toolkits.axisartist.grid_finder import MaxNLocator from mpl_toolkits.axisartist.floating_axes import GridHelperCurveLinear, FloatingSubplot from mpl_toolkits.axisartist.grid_finder import (FixedLocator, MaxNLocator, DictFormatter) """Return polar axes that adhere to desired theta (in deg) and r limits. steps for theta and r are really just hints for the locators. Using negative values for rlim causes problems for GridHelperCurveLinear for some reason""" th0, th1 = thlim # deg r0, r1 = rlim thstep, rstep = step # scale degrees to radians: tr_scale = Affine2D().scale(np.pi/180., 1.) tr = tr_scale + PolarAxes.PolarTransform() theta_grid_locator = angle_helper.LocatorDMS((th1-th0) // thstep) r_grid_locator = MaxNLocator((r1-r0) // rstep) theta_tick_formatter = angle_helper.FormatterDMS() theta_tick_formatter = None theta_ticks = [(0, r"$90^{\circ}$"), (30, r"$120^{\circ}$"), (60, r"$150^{\circ}$"), (90, r"$180^{\circ}$"), (120, r"$210^{\circ}$"), (150, r"$270^{\circ}$"), (180, r"$0^{\circ}$")] theta_tick_formatter = DictFormatter(dict(theta_ticks)) grid_helper = GridHelperCurveLinear(tr, extremes=(th0, th1, r0, r1), grid_locator1=theta_grid_locator, grid_locator2=r_grid_locator, tick_formatter1=theta_tick_formatter, tick_formatter2=None) a = FloatingSubplot(f, 111, grid_helper=grid_helper) f.add_subplot(a) # adjust x axis (theta): a.axis["bottom"].set_visible(False) a.axis["top"].set_axis_direction("bottom") # tick direction a.axis["top"].toggle(ticklabels=ticklabels, label=bool(thlabel)) a.axis["top"].major_ticklabels.set_axis_direction("top") a.axis["top"].label.set_axis_direction("top") # adjust y axis (r): a.axis["left"].set_axis_direction("bottom") # tick direction a.axis["right"].set_axis_direction("top") # tick direction a.axis["left"].toggle(ticklabels=ticklabels, label=bool(rlabel)) # add labels: a.axis["top"].label.set_text(thlabel) a.axis["left"].label.set_text(rlabel) # create a parasite axes whose transData is theta, r: auxa = a.get_aux_axes(tr) # make aux_ax to have a clip path as in a?: auxa.patch = a.patch # this has a side effect that the patch is drawn twice, and possibly over some other # artists. So, we decrease the zorder a bit to prevent this: a.patch.zorder = -2 # add sector lines for both dimensions: thticks = grid_helper.grid_info['lon_info'][0] rticks = grid_helper.grid_info['lat_info'][0] for th in thticks[1:-1]: # all but the first and last auxa.plot([th, th], [r0, r1], '--', c='grey', zorder=-1) for ri, r in enumerate(rticks): # plot first r line as axes border in solid black only if it isn't at r=0 if ri == 0 and r != 0: ls, lw, color = 'solid', 2, 'black' else: ls, lw, color = 'dashed', 1, 'grey' # From http://stackoverflow.com/a/19828753/2020363 auxa.add_artist(plt.Circle([0, 0], radius=r, ls=ls, lw=lw, color=color, fill=False, transform=auxa.transData._b, zorder=-1)) return auxa