def plot(self, ax=None, pt_size=9, color='0'): """ Set up uncertainty distribution plot :param ax: matplotlib axes object :param pt_size: character point size :param color: colour :return: none """ if not ax: ax = plt.subplot(1, 1, 1) linewidth = .5 * pt_size / 9 t = self.t([.003, .16, .5, .84, .997]) p = np.searchsorted(self.ts, t) - 1 max_ticks = 3 xt = gm.ticks(np.append(0, t), max_ticks) max_t = np.max(xt) max_text = cst.str_age(max_t, simple=True) a = max_text.split(' ') xt_units = float(a[0]) / max_t * xt xt_label = ['{:g}'.format(e) for e in xt_units] xt_label[-1] = " " + xt_label[-1] + " " + a[ 1] # add unit to last label, e.g. "Ga" ax.plot(self.ts, self.pdf, lw=linewidth * 1.5, color=color) ax.patch.set_facecolor( 'none') # make region transparent over background graphics ax.fill_between(self.ts[p[1]:p[3]], self.pdf[p[1]:p[3]], 0, color=color, alpha=0.35, edgecolor=color, lw=linewidth) #'.7' ax.fill_between(self.ts[p[2]:p[2] + 1], self.pdf[p[2]:p[2] + 1], edgecolor=color, lw=linewidth, alpha=.5) ax.get_yaxis().set_visible(False) for e in ['right', 'left', 'top']: ax.spines[e].set_visible(False) ax.spines['bottom'].set_linewidth(linewidth) ax.spines['bottom'].set_color(color) ax.set_xbound(lower=0, upper=xt[1]) ax.set_xticks(xt) ax.tick_params(axis='x', which='both', width=linewidth, length=pt_size * .2, pad=pt_size * .1, color=color) ax.tick_params(axis='x', which='minor', length=pt_size * .1) ax.xaxis.set_minor_locator(ticker.AutoMinorLocator()) ax.set_xticklabels(xt_label, fontsize=pt_size * .7, color=color) #,horizontalalignment='left')
def test_str_age(self): self.assertEqual(cst.str_age(.314, .11, .14), '$314^{+110}_{-140}$ Ma') self.assertEqual(cst.str_age(.314, .11, .14, ga=True, mu=True), '$\mu0.314^{+0.11}_{-0.14}$ Ga') self.assertEqual(cst.str_age(.314, simple=True), '314 Ma') self.assertEqual(cst.str_age(1.), '$1.00$ Ga') self.assertEqual(cst.str_age(1., simple=True), '1 Ga') self.assertEqual(cst.str_age(.314, .11, .14, sf=2), '$310^{+100}_{-100}$ Ma')
def plot_isochrons(self): """ Overplot predefined isochrons with annotations :return: none """ isochrons = [(abs(float(e.rstrip('ash'))), 'h' in e, 'a' in e, 's' in e) for e in self.isochrons.split(',')] for t, hide, above, small in isochrons: a0 = self.cf.a0(t) iso = self.pf.getisochron(self.presentation, a0, self.ef) d10 = np.log10(iso['d']) self.ax.plot(d10, iso['y'], color=self.grey[0], lw=.5) q = gm.where( np.abs(np.log10(iso['y']) - (self.yrange[1] - .1)) < .1) if not q or (d10[q[0]] < self.xrange[0]): # (d10[q[0][0]] < self.xrange[0]): q = gm.where( abs(d10 - np.max([self.xrange[0] + .15, d10[0]])) < .1) if q and not hide: sx = np.mean(d10[q]) sy = np.log10(self.pf.evaluate(self.presentation, 10**sx, a0)) - .05 y_factor = self.data_aspect th = np.rad2deg( np.arctan2( np.log10( self.pf.evaluate(self.presentation, 10**(sx + .3), a0)) - sy, .3 * y_factor)) self.ax.text(sx, 10**sy, cst.str_age(t, simple=True), color=self.grey[0], size=self.scaled_pt_size * (.5 if small else .7), rotation=th, rotation_mode='anchor', verticalalignment='bottom' if above else 'top', horizontalalignment='left', bbox=dict(facecolor='none', edgecolor='none', boxstyle='square,pad=0.5'))
def overplot(self, cps): """ Add overplot elements into figure :param cps: Craterplotset instance :return: none """ if not self.cratercount or self.hide: return p = self.cratercount.getplotdata( cps.presentation, self.binning, range=self.range, resurfacing=self.resurf_showall if self.resurf and self.type == 'c-fit' else None, pf=cps.pf) self.n = p['n'] self.n_event = p['n_event'] legend_label = [] if self.error_bars: cps.ax.errorbar(np.log10(p['d']), p['y'], yerr=p['err'], fmt='none', linewidth=.7, ecolor=cps.grey[0]) if self.type in ['c-fit', 'd-fit', 'poisson', 'b-poisson']: self.calculate_age(cps) if self.isochron: iso = cps.pf.getisochron(cps.presentation, self.a0[0], cps.ef) cps.ax.plot(np.log10(iso['d']), iso['y'], label=None, color=cps.grey[0], lw=.4, zorder=.9) expansion = np.array([.99, 1.01]) fit = cps.pf.getplotdata(cps.presentation, self.a0[0], range=self.range * expansion) cps.ax.plot(np.log10(fit['d']), fit['y'], label='fit', color=cps.palette[self.colour], lw=.7) if self.display_age: st = cst.str_age(self.t[0], self.t[2] - self.t[0], self.t[0] - self.t[1], cps.sig_figs, mu=cps.mu) xy = cps.data_to_axis((np.log10(fit['d'][0]), fit['y'][0])) x, y = xy + 0.02 * np.ones(2) * ( -1 if self.age_left else 1) + np.array(self.offset_age) / ( cps.decades[0] * 20) #(cps.decades[0]*10). cps.ax.text( x, y, st, transform=cps.ax.transAxes, color=cps.palette[self.colour], size=cps.scaled_pt_size * 1.2, horizontalalignment='right' if self.age_left else 'left', ) if self.type in ['poisson', 'b-poisson']: text_extent = TextPath( (0, 0), st, size=cps.scaled_pt_size * 1.2).get_extents() h, w = text_extent.height, text_extent.width f = 1 / (cps.cm2inch * (cps.position[2] - cps.position[0]) * 100 ) #conversion for axes coord offset = self.pdf.offset( self.age_left ) # normalised units of mini-plot width in +x direction box = np.array([ .12, .05 ]) * cps.pt_size / 9. # dimensions of plot box if self.age_left: # offset from string write position dx = -(f * w + .03) + (-1 + offset) * box[0] else: dx = f * w + .03 + offset * box[0] dy = f * h / 2 pos = np.array( [x + dx, y - dy, x + dx + box[0], y - dy + box[1]]) pos2 = cps.axis_to_fig(pos) pos3 = np.concatenate([pos2[0:2], pos2[2:4] - pos2[0:2]]) ax = cps.fig.add_axes(pos3) self.pdf.plot(ax, pt_size=cps.scaled_pt_size, color=cps.palette[self.colour]) if '#' in cps.legend: if self.cratercount.buffered: legend_label += ['{:.1f}'.format(self.n_event)] else: if np.abs(self.n_event - self.n) < .001: legend_label += ['{:0g}'.format(self.n)] else: legend_label += [ '{0:.1f} (of {1:d})'.format(self.n, self.n_event) ] legend_label[-1] += " craters" if 'r' in cps.legend: if not self.cratercount.prebinned and self.type in [ 'poisson', 'b-poisson' ]: r = self.range else: r = gm.range( self.cratercount.generate_bins(self.binning, self.range, expand=False)) legend_label += [cst.str_diameter_range(r)] if 'N' in cps.legend: legend_label += [ 'N({0:0g})'.format(cps.ref_diameter) + '$=' + gm.scientific_notation(self.n_d, sf=3) + '$ km$^{-2}$' ] if self.type == 'data': if 'n' in cps.legend: legend_label += [ self.name if self.name != '' else gm.filename( self.source, "n") ] if 'a' in cps.legend: legend_label += [ '$' + gm.scientific_notation(self.cratercount.area, sf=3) + '$ km$^{2}$' ] cps.ax.plot(np.log10(p['d']), p['y'], label=', '.join(legend_label) if legend_label else None, **cps.marker_def[self.psym], ls='', color=cps.palette[self.colour], markeredgewidth=.5)