def rectangle_around_axes(bottomleft_ax, topright_ax, pad, ls, label=None): """ pad: tuple, (left, right, bottom, top) """ left, bottom = bottomleft_ax.get_position().get_points()[0] right, top = topright_ax.get_position().get_points()[1] left -= pad[0] right += pad[1] bottom -= pad[2] top += pad[3] transf = plt.gcf().transFigure rec = Rectangle((left, bottom), right - left, top - bottom, transform=transf, fill=False, lw=2, ls=ls) rec = bottomleft_ax.add_patch(rec) rec.set_clip_on(False) if label: middle = (top + bottom) / 2. moreleft = left # pad[0] bottomleft_ax.text(moreleft, middle, label, transform=transf, rotation='vertical', fontstyle='oblique', va='center', ha='right')
def highlight_artist(self, val, artist=None): # print val, artist figure = self.get_figpage()._artists[0] ax = self.get_figaxes() if artist is None: alist = self._artists else: alist = artist if val == True: container = self.get_container() if container is None: return de = self.get_data_extent() from ifigure.matplotlib_mod.art3d_gl import AxesImageGL if isinstance(alist[0], AxesImageGL): hl = alist[0].add_hl_mask() for item in hl: alist[0].figobj_hl.append(item) # hl = alist[0].make_hl_artist(container) # rect_alpha = 0.0 else: x = [de[0], de[1], de[1], de[0], de[0]] y = [de[2], de[2], de[3], de[3], de[2]] hl = container.plot(x, y, marker='s', color='k', linestyle='None', markerfacecolor='None', markeredgewidth=0.5, scalex=False, scaley=False) rect_alpha = 0.3 hlp = Rectangle((de[0], de[2]), de[1] - de[0], de[3] - de[2], alpha=rect_alpha, facecolor='k', figure=figure, transform=container.transData) if ax is not None: x0, y0 = ax._artists[0].transAxes.transform((0, 0)) x1, y1 = ax._artists[0].transAxes.transform((1, 1)) bbox = Bbox([[x0, y0], [x1, y1]]) hlp.set_clip_box(bbox) hlp.set_clip_on(True) figure.patches.append(hlp) for item in (hl[0], hlp): alist[0].figobj_hl.append(item) else: for a in alist: if len(a.figobj_hl) != 0: a.figobj_hl[0].remove() figure.patches.remove(a.figobj_hl[1]) a.figobj_hl = []
def plot_add_border(ax, offset=[0, 0], **rec_args): xmin, xmax, ymin, ymax = ax.axis() xmin, xmax, ymin, ymax = xmin - offset[0], xmax + offset[0], ymin - offset[ 1], ymax + offset[1] rec = Rectangle((xmin, ymin), (xmax - xmin), (ymax - ymin), fill=False, zorder=19, **rec_args) rec = ax.add_patch(rec) rec.set_clip_on(False)
def boundary(sub1): autoAxis = sub1.axis() rec = Rectangle((autoAxis[0] - 0.6, autoAxis[2] - 0.4), (autoAxis[1] - autoAxis[0]) + 1, (autoAxis[3] - autoAxis[2]) + 1, fill=False, lw=2, edgecolor='r') rec = sub1.add_patch(rec) rec.set_clip_on(False)
def highlight_artist(self, val, artist=None): # print val, artist figure=self.get_figpage()._artists[0] ax = self.get_figaxes() if artist is None: alist=self._artists else: alist=artist if val == True: container = self.get_container() if container is None: return de = self.get_data_extent() from ifigure.matplotlib_mod.art3d_gl import AxesImageGL if isinstance(alist[0], AxesImageGL): hl = alist[0].add_hl_mask() for item in hl: alist[0].figobj_hl.append(item) # hl = alist[0].make_hl_artist(container) # rect_alpha = 0.0 else: x=[de[0],de[1],de[1],de[0],de[0]] y=[de[2],de[2],de[3],de[3],de[2]] hl= container.plot(x, y, marker='s', color='k', linestyle='None', markerfacecolor='None', markeredgewidth = 0.5, scalex=False, scaley=False) rect_alpha = 0.3 hlp = Rectangle((de[0],de[2]), de[1]-de[0], de[3]-de[2], alpha=rect_alpha, facecolor='k', figure = figure, transform= container.transData) if ax is not None: x0, y0 = ax._artists[0].transAxes.transform((0,0)) x1, y1 = ax._artists[0].transAxes.transform((1,1)) bbox = Bbox([[x0,y0],[x1,y1]]) hlp.set_clip_box(bbox) hlp.set_clip_on(True) figure.patches.append(hlp) for item in (hl[0], hlp): alist[0].figobj_hl.append(item) else: for a in alist: if len(a.figobj_hl) != 0: a.figobj_hl[0].remove() figure.patches.remove(a.figobj_hl[1]) a.figobj_hl=[]
def draw_box_around_values(start, stop, ls): deltaline = ty[start] - ty[start + 1] top = ty[start] + deltaline # Draw the top border ABOVE the text bottom = ty[stop] rec = Rectangle((left - 0.1, bottom - 0.02), right - left + 0.15, top - bottom + 0.01, fill=False, lw=2, transform=tax.transAxes, ls=ls) rec = tax.add_patch(rec) rec.set_clip_on(False)
def on_click(event): global prev_g_point global prev_b_point global dirty_type global idx_seen # print(idx_seen) if event.button == 1: plt.ion() print('Your decision has been recorded!') btn = event.inaxes spn = (int(btn.get_title()) % 80) // 4 color_id = int(btn.get_title()) % 4 colors_temp = ['green', 'blue', 'gray', 'orange'] req_axis = subplot_axs_list[spn] autoAxis = req_axis.axis() rec = Rectangle((autoAxis[0] - 0.7, autoAxis[2] - 0.2), (autoAxis[1] - autoAxis[0]) + 1, (autoAxis[3] - autoAxis[2]) + 0.4, fill=False, lw=5, color=colors_temp[color_id]) rec = req_axis.add_patch(rec) rec.set_clip_on(False) plt.draw() print('subplot_title: {}'.format(req_axis.get_title())) row_no = int(req_axis.get_title()) dirty_val = int(btn.get_title()) % 4 idx_seen[row_no] = str(dirty_val) if dirty_val == 0: prev_b_point = row_no elif dirty_val == 3: prev_g_point = row_no dirty_type[row_no] = dirty_val rk = spn rv = dirty_val % 4 d = ['{}'.format(path[int(req_axis.get_title())]), '{}'.format(rv)] field_names = ['path', 'dirty_value']
def highlight_artist(self, val, artist=None): figure = self.get_figpage()._artists[0] ax = self.get_figaxes() if val: if len(self._artists[0].figobj_hl) != 0: return box = self.get_artist_extent_all() self._artist_extent = box if box[0] is None: return x = [box[0], box[0], box[1], box[1], box[0]] y = [box[3], box[2], box[2], box[3], box[3]] hl = Line2D(x, y, marker='s', color='k', linestyle='None', markerfacecolor='k', markeredgewidth=0.5, figure=figure, alpha=0.3) figure.lines.append(hl) xy = (box[0], box[2]) w = box[1] - box[0] h = box[3] - box[2] hlp = Rectangle(xy, w, h, alpha=0.3, facecolor='k', figure=figure) if ax is not None: x0, y0 = ax._artists[0].transAxes.transform((0, 0)) x1, y1 = ax._artists[0].transAxes.transform((1, 1)) bbox = Bbox([[x0, y0], [x1, y1]]) hlp.set_clip_box(bbox) hlp.set_clip_on(True) figure.patches.append(hlp) # if ax is not None and ax.get_3d(): # import mpl_toolkits.mplot3d.art3d as art3d # art3d.patch_2d_to_3d(hl) # if len(ax._artists) != 0: # a.axes = self.get_figaxes()._artists[0] self._artists[0].figobj_hl.extend([hl, hlp]) else: if len(self._artists[0].figobj_hl) == 2: figure.lines.remove(self._artists[0].figobj_hl[0]) figure.patches.remove(self._artists[0].figobj_hl[1]) self._artists[0].figobj_hl = []
def highlight_artist(self, val, artist=None): figure=self.get_figpage()._artists[0] ax = self.get_figaxes() if val: if len(self._artists[0].figobj_hl) != 0: return box = self.get_artist_extent_all() self._artist_extent = box if box[0] is None: return x = [box[0], box[0], box[1], box[1], box[0]] y = [box[3], box[2], box[2], box[3], box[3]] hl= Line2D(x, y, marker='s', color='k', linestyle='None', markerfacecolor='k', markeredgewidth = 0.5, figure=figure, alpha=0.3) figure.lines.append(hl) xy = (box[0], box[2]) w = box[1] - box[0] h = box[3] - box[2] hlp = Rectangle(xy, w, h, alpha=0.3, facecolor='k', figure = figure) if ax is not None: x0, y0 = ax._artists[0].transAxes.transform((0,0)) x1, y1 = ax._artists[0].transAxes.transform((1,1)) bbox = Bbox([[x0,y0],[x1,y1]]) hlp.set_clip_box(bbox) hlp.set_clip_on(True) figure.patches.append(hlp) # if ax is not None and ax.get_3d(): # import mpl_toolkits.mplot3d.art3d as art3d # art3d.patch_2d_to_3d(hl) # if len(ax._artists) != 0: # a.axes = self.get_figaxes()._artists[0] self._artists[0].figobj_hl.extend([hl, hlp]) else: if len(self._artists[0].figobj_hl) == 2: figure.lines.remove(self._artists[0].figobj_hl[0]) figure.patches.remove(self._artists[0].figobj_hl[1]) self._artists[0].figobj_hl = []
from pylab import * from matplotlib.lines import Line2D from matplotlib.patches import Rectangle # build a rectangle in axes coords left, width = .25, .5 bottom, height = .25, .5 right = left + width top = bottom + height ax = gca() p = Rectangle((left, bottom), width, height, fill=False, ) p.set_transform(ax.transAxes) p.set_clip_on(False) ax.add_patch(p) ax.text(left, bottom, 'left top', horizontalalignment='left', verticalalignment='top', transform=ax.transAxes) ax.text(left, bottom, 'left bottom', horizontalalignment='left', verticalalignment='bottom', transform=ax.transAxes) ax.text(right, top, 'right bottom', horizontalalignment='right',
def render_profiles(num, seq, reactivity, stderr, rx_rates, bg_rates, dc_rates, rx_depth, bg_depth, dc_depth, rx_simple_depth, bg_simple_depth, dc_simple_depth, fileout, name, qc_pass): # FIXME: this is fairly ugly code - should at least break each panel into a separate func if rx_rates is None and bg_rates is None and dc_rates is None: no_mapped = True else: no_mapped = False legend_labels = [] if rx_rates is not None: legend_labels.append("Modified") rx_err = sqrt(rx_rates) / sqrt(rx_depth) else: rx_rates = np.zeros((len(rx_depth),)) rx_err = np.zeros((len(rx_depth),)) if bg_rates is not None: legend_labels.append("Untreated") bg_err = sqrt(bg_rates) / sqrt(bg_depth) else: bg_rates = np.zeros((len(rx_depth),)) bg_err = np.zeros((len(rx_depth),)) if dc_rates is not None: legend_labels.append("Denatured") dc_err = sqrt(dc_rates) / sqrt(dc_depth) else: dc_rates = np.zeros((len(rx_depth),)) dc_err = np.zeros((len(rx_depth),)) # Add a zeroeth nuc so axis numbering works correctly # There's probably a better way to do this num = np.append(0, num) if reactivity is not None: reactivity = np.append(0, reactivity) stderr = np.append(0, stderr) rx_depth = np.append(0, rx_depth) bg_depth = np.append(0, bg_depth) dc_depth = np.append(0, dc_depth) rx_simple_depth = np.append(0, rx_simple_depth) bg_simple_depth = np.append(0, bg_simple_depth) dc_simple_depth = np.append(0, dc_simple_depth) rx_rates = np.append(0, rx_rates) bg_rates = np.append(0, bg_rates) dc_rates = np.append(0, dc_rates) rx_err = np.append(0, rx_err) bg_err = np.append(0, bg_err) dc_err = np.append(0, dc_err) if reactivity is not None: orange_thresh = 0.4 red_thresh = 0.85 gray_vals = [] gray_nums = [] gray_errs = [] black_vals = [] black_nums = [] black_errs = [] orange_vals = [] orange_nums = [] orange_errs = [] red_vals = [] red_nums = [] red_errs = [] for i in range(len(reactivity)): if isnan(reactivity[i]): gray_vals.append(-1) gray_nums.append(num[i]) gray_errs.append(0) elif reactivity[i] < orange_thresh: black_vals.append(reactivity[i]) black_nums.append(num[i]) black_errs.append(stderr[i]) elif reactivity[i] < red_thresh: orange_vals.append(reactivity[i]) orange_nums.append(num[i]) orange_errs.append(stderr[i]) else: red_vals.append(reactivity[i]) red_nums.append(num[i]) red_errs.append(stderr[i]) yMin, ymax = (-0.5, 4) left_inches = 0.9 right_inches = 0.4 sp_width = len(num)*0.032 fig_width = max(7,sp_width+left_inches+right_inches) fig = plt.figure(figsize=(fig_width,8)) left_percent = left_inches/fig_width right_percent = 1-right_inches/fig_width ax1 = plt.subplot(311) ax2 = plt.subplot(313) ax3 = plt.subplot(312) plt.subplots_adjust(hspace=0.5, left=left_percent,right=right_percent,top=0.94) near_black = (0,0,1/255.0) if reactivity is not None: if len(gray_nums)>0: ax1.bar(gray_nums,gray_vals, align="center", width=1.05, color="0.80", edgecolor="0.80",linewidth=0.0) if len(black_nums)>0: ax1.bar(black_nums,black_vals, align="center", width=1.05, color="black", edgecolor="black",linewidth=0.0, yerr=black_errs,ecolor=near_black,capsize=1) if len(orange_nums)>0: ax1.bar(orange_nums,orange_vals, align="center", width=1.05, color="orange",edgecolor="orange",linewidth=0.0, yerr=orange_errs,ecolor=near_black,capsize=1) if len(red_nums)>0: ax1.bar(red_nums,red_vals, align="center", width=1.05,color="red",edgecolor="red",linewidth=0.0, yerr=red_errs,ecolor=near_black,capsize=1) #print("title: "+name) ax1title = ax1.set_title(name, horizontalalignment="left", fontsize=16) x,y = ax1title.get_position() ax1title.set_position((0,y)) ax1.set_ylim(yMin,ymax) ax1.set_xlim(1,len(num)) #ax1.set_yticks(fontsize=9) if not qc_pass: msg = "Note: possible data quality issue - see log file" return_flag = False if no_mapped: msg = "ERROR: no reads mapped to this RNA" return_flag = True txt = plt.text(30,573, msg, ha='left', va='top', fontsize=16, color='red', transform=mp.transforms.IdentityTransform()) if return_flag: plt.savefig(fileout) return #tickNums = range(num[0]+10,num[-1]+1,10) #tickPos = range(num[0]+9,num[-1],10) #ax1.set_xticks(tickPos,tickNums,fontsize=9,rotation=30) #ax1.set_xticks(fontsize=9) ax1.yaxis.grid(True) ax1.set_axisbelow(True) ax1.spines["right"].set_visible(False) ax1.spines["top"].set_visible(False) for loc, spine in ax1.spines.items(): if loc == 'bottom': spine.set_position(('outward', 6)) # move outward (down) 6 pts spine.set_smart_bounds(True) for loc, spine in ax1.spines.items(): if loc == 'left': spine.set_position(('outward', 6)) # move outward (left) 6 pts spine.set_smart_bounds(True) # need to add labels after moving spines, otherwise they will disappear ax1xlabel = ax1.set_xlabel("Nucleotide", horizontalalignment="left", fontsize=14, labelpad=0) x,y = ax1xlabel.get_position() ax1xlabel.set_position((0,y)) ax1ylabel = ax1.set_ylabel("Shape Reactivity", horizontalalignment="left", fontsize=14) x,y = ax1ylabel.get_position() ax1ylabel.set_position((x,0)) if reactivity is not None: # add a SHAPE colorbar to the vertical axis # uses a little transformation magic to place correctly inv = ax1.transData.inverted() for loc, spine in ax1.spines.items(): if loc == 'left': trans = spine.get_transform() pt = trans.transform_point([0,0]) pt2 = inv.transform_point(pt) rectX = pt2[0] ptA = (0,0) ptB = (6,0) ptA2 = inv.transform_point(ptA) ptB2 = inv.transform_point(ptB) rectW = ptB2[0]-ptA2[0] rect = Rectangle((rectX,-0.5), rectW, orange_thresh+0.5, facecolor="black", edgecolor="none") ax1.add_patch(rect) rect.set_clip_on(False) rect = Rectangle((rectX,orange_thresh), rectW, red_thresh-orange_thresh, facecolor="orange", edgecolor="none") ax1.add_patch(rect) rect.set_clip_on(False) rect = Rectangle((rectX,red_thresh), rectW, 4-red_thresh, facecolor="red", edgecolor="none") ax1.add_patch(rect) rect.set_clip_on(False) ax1.get_xaxis().tick_bottom() # remove unneeded ticks ax1.get_yaxis().tick_left() ax1.tick_params(axis='y',which='minor',left='off') #ax1.tick_params(axis='x',which='minor') ax1.minorticks_on() yticks = ax1.get_yticks() stripped_ticks = [str(val).rstrip('0').rstrip('.') for val in yticks] ax1.set_yticklabels(stripped_ticks) for line in ax1.get_yticklines(): line.set_markersize(6) line.set_markeredgewidth(1) for line in ax1.get_xticklines(): line.set_markersize(7) line.set_markeredgewidth(2) for line in ax1.xaxis.get_ticklines(minor=True): line.set_markersize(5) line.set_markeredgewidth(1) # put nuc sequence below axis font_prop = mp.font_manager.FontProperties(family = "monospace", style="normal",weight="bold",size="4.5") for i in range(seq.shape[0]): nuc = seq[i] if nuc == "T": nuc = "U" color_dict = {"A": "#f20000", "U": "#f28f00", "G": "#00509d", "C": "#00c200"} if nuc in color_dict: col = color_dict[nuc] elif nuc.upper() in color_dict: col = color_dict[nuc.upper()] else: col = "black" ax1.annotate(nuc, xy=(i+1, -0.67),fontproperties=font_prop,color=col,annotation_clip=False, horizontalalignment="center") handles = [] h, = ax2.plot(num, rx_simple_depth, linewidth = 1.5, color=rx_color, alpha=1.0) ax2.plot(num, rx_depth, linewidth = 1.0, color=rx_color, alpha=0.3) handles.append(h) h, = ax2.plot(num, bg_simple_depth, linewidth = 1.5, color=bg_color, alpha=1.0) ax2.plot(num, bg_depth, linewidth = 1.0, color=bg_color, alpha=0.3) handles.append(h) h, = ax2.plot(num, dc_simple_depth, linewidth = 1.5, color=dc_color, alpha=1.0) ax2.plot(num, dc_depth, linewidth = 1.0, color=dc_color, alpha=0.3) handles.append(h) ax2.set_xlim(1,len(num)) #ax2.legend(["+Reagent","Background","Denatured"], bbox_to_anchor=(1.1,1.1)) leg = ax2.legend(handles, legend_labels, loc=2, borderpad=0.8, handletextpad=0.2, framealpha=0.75) xmin, xmax, ymin, ymax = ax2.axis() ax2.set_ylim(0,ymax) #ax2.set_yscale('log') #ax2.set_yscale('symlog')# useful, but disabled because of a matplotlib/pyparsing bug ax2xlabel = ax2.set_xlabel("Nucleotide\n(note: effective read depths shown in lighter colors)", horizontalalignment="left", fontsize=14, labelpad=0) x,y = ax2xlabel.get_position() ax2xlabel.set_position((0,y)) ax2.spines["right"].set_visible(False) ax2.spines["top"].set_visible(False) ax2.get_xaxis().tick_bottom() # remove unneeded ticks ax2.get_yaxis().tick_left() ax2.minorticks_on() ax2.tick_params(axis='y',which='minor',left='off') #ax2.tick_params(axis='x',which='minor') #xlabels = ["%.2f"%v for v in xticks] #ax3.set_xticks(xticks) #ax3.set_xticklabels(xlabels,rotation = -45, horizontalalignment='left') yticks = [int(y) for y in ax2.get_yticks()] formatted_ticks = [] for val in yticks: formatted_ticks.append(metric_abbreviate(val)) ax2.set_yticklabels(formatted_ticks) for line in ax2.get_yticklines(): line.set_markersize(6) line.set_markeredgewidth(1) for line in ax2.get_xticklines(): line.set_markersize(7) line.set_markeredgewidth(2) for line in ax2.xaxis.get_ticklines(minor=True): line.set_markersize(5) line.set_markeredgewidth(1) ax2.yaxis.grid(True) ax2.set_axisbelow(True) ax2ylabel = ax2.set_ylabel("Read depth", horizontalalignment="left", fontsize=14) x, y = ax2ylabel.get_position() ax2ylabel.set_position((x, 0)) # tried to make an offset, smaller font note about effective depths, # but couldn't get positioning/transforms to work properly. # For now just putting in xaxis label # choose a decent range for axis, excluding high-background positions good_indices = [] for i in range(len(bg_rates)): if bg_rates[i]<=0.05 or isnan(bg_rates[i]): good_indices.append(i) temp_rates = [rx_rates[i] for i in good_indices] near_top_rate = percentile(temp_rates,98.0) maxes = [0.32,0.16,0.08,0.04,0.02,0.01] ymax = maxes[0] for i in range(len(maxes)): if near_top_rate<maxes[i]: ymax = maxes[i] rx_upper = rx_rates + rx_err rx_lower = rx_rates - rx_err bg_upper = bg_rates + bg_err bg_lower = bg_rates - bg_err dc_upper = dc_rates + dc_err dc_lower = dc_rates - dc_err ax3xlabel = ax3.set_xlabel("Nucleotide", horizontalalignment="left", fontsize=14, labelpad=0) x,y = ax3xlabel.get_position() ax3xlabel.set_position((0,y)) ax3ylabel = ax3.set_ylabel("Mutation rate (%)", horizontalalignment="left", fontsize=14) x,y = ax3ylabel.get_position() ax3ylabel.set_position((x,0)) ax3.plot(num, rx_rates, zorder=3, color=rx_color, linewidth=1.5) ax3.plot(num, bg_rates, zorder=2, color=bg_color, linewidth=1.5) ax3.plot(num, dc_rates, zorder=2, color=dc_color, linewidth=1.5) ax3.fill_between(num, rx_lower, rx_upper, edgecolor="none", alpha=0.5, facecolor=rx_color) ax3.fill_between(num, bg_lower, bg_upper, edgecolor="none", alpha=0.5, facecolor=bg_color) ax3.fill_between(num, dc_lower, dc_upper, edgecolor="none", alpha=0.5, facecolor=dc_color) ax3.legend(legend_labels, loc=2, borderpad=0.8, handletextpad=0.2, framealpha=0.75) ax3.set_xlim((1,len(rx_rates))) ax3.set_ylim((0,ymax)) ax3.spines["right"].set_visible(False) ax3.spines["top"].set_visible(False) ax3.get_xaxis().tick_bottom() # remove unneeded ticks ax3.get_yaxis().tick_left() ax3.minorticks_on() ax3.tick_params(axis='y',which='minor',left='off') ticks = [x*100 for x in ax3.get_yticks()] ax3.set_yticklabels([str(val).rstrip('0').rstrip('.') for val in ticks]) for line in ax3.get_yticklines(): line.set_markersize(6) line.set_markeredgewidth(1) for line in ax3.get_xticklines(): line.set_markersize(7) line.set_markeredgewidth(2) for line in ax3.xaxis.get_ticklines(minor=True): line.set_markersize(5) line.set_markeredgewidth(1) ax3.yaxis.grid(True) ax3.set_axisbelow(True) # TODO: add a tick for the first nuc - can't seem to add one without screwing # up all the other ticks plt.savefig(fileout)
def draw_border(axis): from matplotlib.patches import Rectangle rec = Rectangle((0, 0), 1, 1, fill=False, lw=2, transform=axis.transAxes) rec = axis.add_patch(rec) rec.set_clip_on(False)
ax.spines['top'].set_visible(False) ax.spines['right'].set_visible(False) ax.legend(loc='lower left', bbox_to_anchor=(1, 0), frameon=False) ax.set_title('Die Spannbreite der Ticketpreise', size=18, horizontalalignment='left') ax.yaxis.set_ticks_position('left') ax.xaxis.set_ticks_position('bottom') ax.tick_params(axis='y', direction='out') #add frames autoAxis = ax.axis() rec = Rectangle((autoAxis[0] - 5, autoAxis[2] - 10), (autoAxis[1] - autoAxis[0]) + 50, (autoAxis[3] - autoAxis[2]) + 30, fill=False, lw=1, edgecolor="darkkhaki") rec = ax.add_patch(rec) rec.set_clip_on(False) rec2 = Rectangle((autoAxis[0] - 5, autoAxis[2] + 142), (autoAxis[1] - autoAxis[0]) + 50, (autoAxis[3] - autoAxis[2]) - 120, fill=True, lw=1, edgecolor="darkkhaki", facecolor="darkkhaki") rec2 = ax.add_patch(rec2) rec2.set_clip_on(False) #save the plot fig.savefig("plot.png")
def writeFigures(num,reactivity,stdev, rxRates,bgRates,dcRates, rxErr,bgErr,dcErr, rxDepth,bgDepth,dcDepth, name,outputDir): errFlag = False try: import matplotlib as mp mp.rcParams["font.sans-serif"].insert(0,"Arial") # If matplotlib can find this font, then Illustrator # should be able to open the correct font on PDF import # rather than replacing it. Matplotlib generally falls # back to Bitstream fonts, which Illustrator usually # can't locate by default. mp.rcParams["font.family"] = "sans-serif" mp.rcParams["pdf.fonttype"] = 42 # use TrueType fonts when exporting pdfs (embeds most fonts) mp.rcParams['xtick.direction'] = 'out' mp.rcParams['ytick.direction'] = 'out' mp.rcParams['legend.fontsize'] = 14 mp.rcParams['grid.color'] = ".8" mp.rcParams['grid.linestyle'] = '-' mp.rcParams['grid.linewidth'] = 1 mp.use('Agg') import matplotlib.pyplot as plt from matplotlib.patches import Rectangle except ImportError: sys.stderr.write("Warning: matplotlib python module was not found, so no figures were rendered for %i.\n"%(name)) errFlag = True version = [int(v) for v in mp.__version__.split('.')] # Check that we have matplotlib version 1.2 or greater if version[0]<1 or (version[0]==1 and version[1]<2): sys.stderr.write("Warning: matplotlib version 1.2 or greater is recommended, but version %s was found, so no figures were rendered for %i.\n"%(mp.__version__,name)) errFlag = True if errFlag==True: return False from numpy import percentile # Add a zeroeth nuc so axis numbering works correctly # There's probably a better way to do this num = [0]+num reactivity = [0]+reactivity stdev = [0]+stdev rxDepth = [0]+rxDepth bgDepth = [0]+bgDepth dcDepth = [0]+dcDepth rxRates = [0]+rxRates bgRates = [0]+bgRates dcRates = [0]+dcRates rxErr = [0]+rxErr bgErr = [0]+bgErr dcErr = [0]+dcErr orangeThresh = 0.4 redThresh = 0.85 grayVals = [] grayNums = [] grayErrs = [] blackVals = [] blackNums = [] blackErrs = [] orangeVals = [] orangeNums = [] orangeErrs = [] redVals = [] redNums = [] redErrs = [] for i in range(len(reactivity)): if reactivity[i] < -900: grayVals.append(-1) grayNums.append(num[i]) grayErrs.append(0) elif reactivity[i] < orangeThresh: blackVals.append(reactivity[i]) blackNums.append(num[i]) blackErrs.append(stdev[i]) elif reactivity[i] < redThresh: orangeVals.append(reactivity[i]) orangeNums.append(num[i]) orangeErrs.append(stdev[i]) else: redVals.append(reactivity[i]) redNums.append(num[i]) redErrs.append(stdev[i]) yMin, yMax = (-0.5, 4) leftInches = 0.9 rightInches = 0.4 spWidth = len(num)*0.032 figWidth = max(7,spWidth+leftInches+rightInches) fig = plt.figure(figsize=(figWidth,8)) leftPercent = leftInches/figWidth rightPercent = 1-rightInches/figWidth ax1 = plt.subplot(311) ax2 = plt.subplot(313) ax3 = plt.subplot(312) plt.subplots_adjust(hspace=0.5, left=leftPercent,right=rightPercent,top=0.94) nearBlack = (0,0,1/255.0) if len(grayNums)>0: ax1.bar(grayNums,grayVals, align="center", width=1.05, color="0.80", edgecolor="0.80",linewidth=0.0) if len(blackNums)>0: ax1.bar(blackNums,blackVals, align="center", width=1.05, color="black", edgecolor="black",linewidth=0.0, yerr=blackErrs,ecolor=nearBlack,capsize=1) if len(orangeNums)>0: ax1.bar(orangeNums,orangeVals, align="center", width=1.05, color="orange",edgecolor="orange",linewidth=0.0, yerr=orangeErrs,ecolor=nearBlack,capsize=1) if len(redNums)>0: ax1.bar(redNums,redVals, align="center", width=1.05,color="red",edgecolor="red",linewidth=0.0, yerr=redErrs,ecolor=nearBlack,capsize=1) ax1title = ax1.set_title(name, horizontalalignment="left", fontsize=16) x,y = ax1title.get_position() ax1title.set_position((0,y)) ax1.set_ylim(yMin,yMax) ax1.set_xlim(1,len(num)) #ax1.set_yticks(fontsize=9) #tickNums = range(num[0]+10,num[-1]+1,10) #tickPos = range(num[0]+9,num[-1],10) #ax1.set_xticks(tickPos,tickNums,fontsize=9,rotation=30) #ax1.set_xticks(fontsize=9) ax1.yaxis.grid(True) ax1.set_axisbelow(True) ax1.spines["right"].set_visible(False) ax1.spines["top"].set_visible(False) for loc, spine in ax1.spines.items(): if loc == 'bottom': spine.set_position(('outward', 6)) # move outward (down) 6 pts spine.set_smart_bounds(True) for loc, spine in ax1.spines.items(): if loc == 'left': spine.set_position(('outward', 6)) # move outward (left) 6 pts spine.set_smart_bounds(True) # need to add labels after moving spines, otherwise they will disappear ax1xlabel = ax1.set_xlabel("Nucleotide", horizontalalignment="left", fontsize=14, labelpad=0) x,y = ax1xlabel.get_position() print str((x,y)) ax1xlabel.set_position((0,y)) ax1ylabel = ax1.set_ylabel("Shape Reactivity", horizontalalignment="left", fontsize=14) x,y = ax1ylabel.get_position() ax1ylabel.set_position((x,0)) # add a SHAPE colorbar to the vertical axis # uses a little transformation magic to place correctly inv = ax1.transData.inverted() for loc, spine in ax1.spines.items(): if loc == 'left': trans = spine.get_transform() pt = trans.transform_point([0,0]) pt2 = inv.transform_point(pt) rectX = pt2[0] ptA = (0,0) ptB = (6,0) ptA2 = inv.transform_point(ptA) ptB2 = inv.transform_point(ptB) rectW = ptB2[0]-ptA2[0] rect = Rectangle((rectX,-0.5), rectW, orangeThresh+0.5, facecolor="black", edgecolor="none") ax1.add_patch(rect) rect.set_clip_on(False) rect = Rectangle((rectX,orangeThresh), rectW, redThresh-orangeThresh, facecolor="orange", edgecolor="none") ax1.add_patch(rect) rect.set_clip_on(False) rect = Rectangle((rectX,redThresh), rectW, 4-redThresh, facecolor="red", edgecolor="none") ax1.add_patch(rect) rect.set_clip_on(False) ax1.get_xaxis().tick_bottom() # remove unneeded ticks ax1.get_yaxis().tick_left() ax1.tick_params(axis='y',which='minor',left='off') #ax1.tick_params(axis='x',which='minor') ax1.minorticks_on() yticks = ax1.get_yticks() #print str(yticks) strippedTicks = ["%d"%val if val==int(val) else "%s"%val for val in yticks] ax1.set_yticklabels(strippedTicks) for line in ax1.get_yticklines(): line.set_markersize(6) line.set_markeredgewidth(1) for line in ax1.get_xticklines(): line.set_markersize(7) line.set_markeredgewidth(2) for line in ax1.xaxis.get_ticklines(minor=True): line.set_markersize(5) line.set_markeredgewidth(1) # put nuc sequence below axis fontProp = mp.font_manager.FontProperties(family = "monospace", style="normal",weight="bold",size="4.5") for i in range(len(seq)): nuc = seq[i] if nuc == "T": nuc = "U" colorDict = {"A":"#f20000", "U":"#f28f00", "G":"#00509d", "C":"#00c200"} if nuc in colorDict.keys(): col = colorDict[nuc] else: col = "black" ax1.annotate(nuc, xy=(i+1, -0.67),fontproperties=fontProp,color=col,annotation_clip=False, horizontalalignment="center") ax2.plot(num,rxDepth, linewidth = 1.5, color=rxColor) ax2.plot(num,bgDepth, linewidth = 1.5, color=bgColor) ax2.plot(num,dcDepth, linewidth = 1.5, color=dcColor) ax2.set_xlim(1,len(num)) #ax2.legend(["+Reagent","Background","Denatured"], bbox_to_anchor=(1.1,1.1)) leg = ax2.legend(["Modified","Untreated","Denatured"], loc=2, borderpad=0.8, handletextpad=0.2, framealpha=0.75) xmin, xmax, ymin, ymax = ax2.axis() ax2.set_ylim(0,ymax) #ax2.set_yscale('symlog')# useful but currently disabled because of a matplotlib/pyparsing bug ax2xlabel = ax2.set_xlabel("Nucleotide", horizontalalignment="left", fontsize=14, labelpad=0) x,y = ax2xlabel.get_position() ax2xlabel.set_position((0,y)) ax2ylabel = ax2.set_ylabel("Read depth", horizontalalignment="left", fontsize=14) x,y = ax2ylabel.get_position() ax2ylabel.set_position((x,0)) #ax2title = ax2.set_title(name, horizontalalignment="left") #x,y = ax2title.get_position() #ax2title.set_position((0,y)) ax2.spines["right"].set_visible(False) ax2.spines["top"].set_visible(False) ax2.get_xaxis().tick_bottom() # remove unneeded ticks ax2.get_yaxis().tick_left() ax2.minorticks_on() ax2.tick_params(axis='y',which='minor',left='off') #ax2.tick_params(axis='x',which='minor') #xlabels = ["%.2f"%v for v in xticks] #ax3.set_xticks(xticks) #ax3.set_xticklabels(xlabels,rotation = -45, horizontalalignment='left') yticks = [int(y) for y in ax2.get_yticks()] formattedTicks = [] for val in yticks: formattedTicks.append(metricAbbreviate(val)) ax2.set_yticklabels(formattedTicks) for line in ax2.get_yticklines(): line.set_markersize(6) line.set_markeredgewidth(1) for line in ax2.get_xticklines(): line.set_markersize(7) line.set_markeredgewidth(2) for line in ax2.xaxis.get_ticklines(minor=True): line.set_markersize(5) line.set_markeredgewidth(1) ax2.yaxis.grid(True) ax2.set_axisbelow(True) # choose a decent range for axis, excluding high-background positions goodIndices = [] for i in xrange(len(bgRates)): if bgRates[i]<=conf.maxBackground: goodIndices.append(i) tempRates = [rxRates[i] for i in goodIndices] nearTopRate = percentile(tempRates,98.0) maxes = [0.32,0.16,0.08,0.04,0.02,0.01] yMax = maxes[0] for i in xrange(len(maxes)): if nearTopRate<maxes[i]: yMax = maxes[i] rxUpper = [rxRates[i]+rxErr[i] for i in xrange(len(rxRates))] rxLower = [rxRates[i]-rxErr[i] for i in xrange(len(rxRates))] bgUpper = [bgRates[i]+bgErr[i] for i in xrange(len(bgRates))] bgLower = [bgRates[i]-bgErr[i] for i in xrange(len(bgRates))] dcUpper = [dcRates[i]+dcErr[i] for i in xrange(len(dcRates))] dcLower = [dcRates[i]-dcErr[i] for i in xrange(len(dcRates))] ax3xlabel = ax3.set_xlabel("Nucleotide", horizontalalignment="left", fontsize=14, labelpad=0) x,y = ax3xlabel.get_position() ax3xlabel.set_position((0,y)) ax3ylabel = ax3.set_ylabel("Mutation rate (%)", horizontalalignment="left", fontsize=14) x,y = ax3ylabel.get_position() ax3ylabel.set_position((x,0)) ax3.plot(rxRates, zorder=3,color=rxColor,linewidth=1.5) ax3.plot(bgRates, zorder=2, color=bgColor, linewidth=1.5) ax3.fill_between(num,rxLower,rxUpper,edgecolor="none",alpha=0.5, facecolor=rxColor) ax3.fill_between(num,bgLower,bgUpper,edgecolor="none",alpha=0.5, facecolor=bgColor) ax3.legend(["Modified","Untreated"], loc=2, borderpad=0.8, handletextpad=0.2, framealpha=0.75) ax3.set_xlim((1,len(rxRates))) ax3.set_ylim((0,yMax)) ax3.spines["right"].set_visible(False) ax3.spines["top"].set_visible(False) ax3.get_xaxis().tick_bottom() # remove unneeded ticks ax3.get_yaxis().tick_left() ax3.minorticks_on() ax3.tick_params(axis='y',which='minor',left='off') ticks = [x*100 for x in ax3.get_yticks()] ax3.set_yticklabels(["%d"%val if val==int(val) else "%s"%val for val in ticks]) for line in ax3.get_yticklines(): line.set_markersize(6) line.set_markeredgewidth(1) for line in ax3.get_xticklines(): line.set_markersize(7) line.set_markeredgewidth(2) for line in ax3.xaxis.get_ticklines(minor=True): line.set_markersize(5) line.set_markeredgewidth(1) ax3.yaxis.grid(True) ax3.set_axisbelow(True) # TODO: add a tick for the first nuc - can't seem to add one without screwing # up all the other ticks outPath = os.path.join(outputDir,"reactivity_profiles") outPath = os.path.join(outPath,name+"_depth_and_reactivity.pdf") plt.savefig(outPath) return True
from matplotlib.patches import Rectangle # build a rectangle in axes coords left, width = .25, .5 bottom, height = .25, .5 right = left + width top = bottom + height ax = gca() p = Rectangle( (left, bottom), width, height, fill=False, ) p.set_transform(ax.transAxes) p.set_clip_on(False) ax.add_patch(p) ax.text(left, bottom, 'left top', horizontalalignment='left', verticalalignment='top', transform=ax.transAxes) ax.text(left, bottom, 'left bottom', horizontalalignment='left', verticalalignment='bottom', transform=ax.transAxes)
def plot_cnn_output(output, path, name, title=None, image=None, video=False, verbose=True, highlight=None): """ This function creates a plot of the cnn output. :param output: response from cnn (28,28,256) :param path: folder where to save plot :param name: name of plot :param title: title of plot :param image: if given, the image is displayed :param video: if true an animation is created, output shape should then be (#frames, 28,28,256) and image either none or (#frames) :param verbose: :param highlight: list of int, highlights the feature map at given indices by a red rectangle :return: """ if verbose: print("start plot_cnn_output of", name) num_ft = output.shape[-1] n_col = math.ceil(np.sqrt(num_ft)) n_rows = math.ceil(num_ft / n_col) vmin, vmax = np.min(output), np.max(output) fig, axs = plt.subplots(n_rows, n_col, figsize=(n_rows + 3, n_col)) # add entry to matrix if there's not enough columns/rows so np.ndenumerate can unpack two values if n_col == 1 and n_rows == 1: axs = [[axs]] elif n_rows == 1: axs = [axs] plt.subplots_adjust(right=0.75, wspace=0.1, hspace=0.1) # add title if title is not None: fig.suptitle(title) ax_colorbar = fig.add_axes([0.83, 0.1, 0.02, 0.65]) # add image input if image is not None: ax_image = fig.add_axes([0.78, 0.78, .12, .12]) if np.max(image) > 1: if verbose: print("transform image data to RGB [0..1] from [0..255]") image = image / 255 if not os.path.exists(path): os.mkdir(path) # add highlight if highlight is not None: for index_highlight in highlight: multi_index_highlight = np.unravel_index(index_highlight, (n_rows, n_col)) if video: size_axis = output.shape[1] else: size_axis = output.shape[0] rec = Rectangle((0, 0), size_axis, size_axis, fill=False, lw=size_axis * 0.15, edgecolor='r') rec = axs[multi_index_highlight].add_patch(rec) rec.set_clip_on(False) update_list = [] def update(n_frame): if verbose and n_frame >= 0: print("frame: {}/{}".format(n_frame, output.shape[0]), end="\r") if not video: data = output else: data = output[n_frame, ...] # loop over all feature maps for (i, j), ax in np.ndenumerate(axs): n = i * n_col + j try: # old way, not sure to understand what Tim tried to do here # ax.get_images()[0].set_data(data[..., n]) im = ax.imshow(data[..., n], vmin=vmin, vmax=vmax) update_list.append(im) except IndexError: # old way, not sure to understand what Tim did here # im = ax.imshow(data[...,n], vmin=vmin, vmax=vmax) # update_list.append(im) pass ax.axis('off') # add input image if image is not None: if video: image_frame = image[n_frame] else: image_frame = image try: ax_image.get_images()[0].set_data(image_frame) except IndexError: im_image = ax_image.imshow(image_frame) update_list.append(im_image) ax_image.axis('off') # display color bar if n_frame <= 0: cbar = fig.colorbar(im, cax=ax_colorbar) return update_list if not video: update(-1) fig.savefig(os.path.join(path, name)) else: def init_func(): return [] anim = FuncAnimation(fig, update, frames=output.shape[0], init_func=init_func, blit=True, interval=33) writergif = animation.PillowWriter(fps=30) anim.save(os.path.join(path, name), writer=writergif) if verbose: print("finished plot_cnn_output of", name)
def create_design_plot(self): """Creates a RNAi design plot.""" # Temp file for storing temp_img_file = tempfile.mkstemp() # Create main figure fig, ax1 = plt.subplots(figsize=(15, 4)) off_target_dict, main_target_dict, efficient_dict, main_hits_histo = general_helpers.get_target_data(self.f_in, self.sirna_size) # If there are no hits, we show only the efficient sirnas for designing a construct if self.main_targets == []: off_target_dict = {} main_target_dict = {} main_hits_histo = [] # Off-target position list off_targets_pos = set() for i in off_target_dict.values(): off_targets_pos = off_targets_pos | i # Main-target position list main_targets_plot = set() for i in main_target_dict.values(): main_targets_plot = main_targets_plot | i # Efficient position list eff_sirna_plot = [] for i in efficient_dict.values(): eff_sirna_plot.extend(i) eff_sirna_plot.sort() # Draw efficiency plot eff_sirna_histo = np.bincount(eff_sirna_plot, minlength=self.query_length) ax1.plot(eff_sirna_histo, 'r-', label='Efficient siRNA hits') # Draw main target histogram main_histo = np.bincount(main_hits_histo, minlength=self.query_length) ax1.plot(main_histo, 'b-', label='Main target siRNA hits') # Draw main targets as green rectangles inside plot figure for region in main_targets_plot: someX, someY = region, 0. currentAxis = fig.gca() tri1 = Rectangle((someX, someY), 1, self.sirna_size + 3, color='g', alpha=0.2)#, label='green') currentAxis.add_patch(tri1) tri1.set_clip_on(False) # Draw off-targets as red rectangles inside plot figure for off_target in off_targets_pos: someX, someY = off_target, 0. currentAxis = fig.gca() tri2 = Rectangle((someX, someY), 1, self.sirna_size + 3, color='r', alpha=0.2)#, label='red') currentAxis.add_patch(tri2) tri2.set_clip_on(False) if max(eff_sirna_histo) > self.sirna_size: max_y = max(eff_sirna_histo) + 3 else: max_y = self.sirna_size + 3 ax1.set_ylim([0, max_y]) x_text = 'mRNA sequence position\n\n' ax1.set_xlabel(x_text, fontsize=12) ax1.xaxis.set_ticks(np.arange(0, self.query_length, 50)) ax1.set_ylabel('Nr of siRNAs', color='b', fontsize=12) ax1.set_xlim([0, self.query_length]) plt.title("RNAi design plot\n\n", fontsize=14) plt.tight_layout() p1 = Rectangle((0, 0), 1, 1, fc="g", alpha=0.2) p2 = Rectangle((0, 0), 1, 1, fc="r", alpha=0.2) p3 = mlines.Line2D([], [], color='r') p4 = mlines.Line2D([], [], color='b') plt.legend([p1,p2, p3, p4], ["Main target", "Off target", 'Efficient siRNAs', 'All siRNAs'], bbox_to_anchor=(0., 1.02, 1., .102), loc=4, ncol=4, mode="", borderaxespad=0.5, frameon=True) plt.savefig(temp_img_file[1] + '.png') #plt.show() plt.close(fig) return temp_img_file[1] + '.png', off_target_dict, main_target_dict
def highlight_artist(self, val, artist=None): from ifigure.matplotlib_mod.art3d_gl import Poly3DCollectionGL from ifigure.matplotlib_mod.art3d_gl import Line3DCollectionGL figure = self.get_figpage()._artists[0] ax = self.get_figaxes() if artist is None: alist = self._artists else: alist = artist if val == True: if self._parent is None: return container = self.get_container() if container is None: return if isinstance(alist[0], Poly3DCollectionGL): hl = alist[0].add_hl_mask() for item in hl: alist[0].figobj_hl.append(item) else: de = self.get_data_extent() x = (de[0], de[1], de[1], de[0], de[0]) y = (de[2], de[2], de[3], de[3], de[2]) facecolor = 'k' if isinstance(alist[0], Poly3DCollectionGL): hl = alist[0].make_hl_artist(container) facecolor = 'none' self._hit_path = None elif isinstance(alist[0], Line3DCollectionGL): hl = alist[0].make_hl_artist(container) facecolor = 'none' self._hit_path = None else: hl = container.plot(x, y, marker='s', color='k', linestyle='None', markerfacecolor='None', markeredgewidth=0.5, scalex=False, scaley=False) for item in hl: alist[0].figobj_hl.append(item) if self._hit_path is not None: v = self._hit_path.vertices hl = container.plot(v[:, 0], v[:, 1], marker='s', color='k', linestyle='None', markerfacecolor='None', markeredgewidth=0.5, scalex=False, scaley=False) for item in hl: alist[0].figobj_hl.append(item) hlp = Rectangle((de[0], de[2]), de[1] - de[0], de[3] - de[2], alpha=0.3, facecolor=facecolor, figure=figure, transform=container.transData) if ax is not None: x0, y0 = ax._artists[0].transAxes.transform((0, 0)) x1, y1 = ax._artists[0].transAxes.transform((1, 1)) bbox = Bbox([[x0, y0], [x1, y1]]) hlp.set_clip_box(bbox) hlp.set_clip_on(True) figure.patches.append(hlp) alist[0].figobj_hl.append(hlp) else: for a in alist: if len(a.figobj_hl) == 0: continue for hl in a.figobj_hl[:-1]: hl.remove() if isinstance(alist[0], Poly3DCollectionGL): a.figobj_hl[-1].remove() else: figure.patches.remove(a.figobj_hl[-1]) a.figobj_hl = []
def generateGraph(self, data=None, outputFilename=None, timeDivisions=6, graphWidth=1920, graphHeight=300, darkMode=False, rainVariance=False, minMaxTemperature=False, fontSize=12, symbolZoom=1.0, symbolDivision=1, showCityName=None, writeMetaData=None): logging.debug("Initializing graph...") if darkMode: colors = self.colorsDarkMode else: colors = self.colorsLightMode fig = plt.figure(0) # Main figure rainAxis = fig.add_subplot(111) # set font sizes plt.rcParams.update({'font.size': fontSize}) # Temperature Y axis and day names rainAxis.tick_params(axis='y', labelsize=fontSize) # Rain Y axis plt.xticks(fontsize=fontSize) # Time axis if not graphWidth: graphWidth = 1280 if not graphHeight: graphHeight = 300 logging.debug("Graph size: %d x %d pixel" % (graphWidth, graphHeight)) fig.set_size_inches( float(graphWidth) / fig.get_dpi(), float(graphHeight) / fig.get_dpi()) # Plot dimension and borders bbox = rainAxis.get_window_extent().transformed( fig.dpi_scale_trans.inverted()) width, height = bbox.width * fig.dpi, bbox.height * fig.dpi # plot size in pixel plt.margins(x=0) rainAxis.margins(x=0) plt.subplots_adjust(left=40 / width, right=1 - 40 / width, top=1 - 35 / height, bottom=40 / height) bbox = rainAxis.get_window_extent().transformed( fig.dpi_scale_trans.inverted()) width, height = bbox.width * fig.dpi, bbox.height * fig.dpi # plot size in pixel xPixelsPerDay = width / data["noOfDays"] # Dimensions of the axis in pixel firstDayX = math.ceil(bbox.x0 * fig.dpi) firstDayY = math.ceil(bbox.y0 * fig.dpi) dayWidth = math.floor((bbox.x1 - bbox.x0) * fig.dpi) / data["noOfDays"] dayHeight = math.floor((bbox.y1 - bbox.y0) * fig.dpi) # Show gray background on every 2nd day for day in range(0, data["noOfDays"], 2): plt.axvspan(data["timestamps"][0 + day * 24], data["timestamps"][23 + day * 24] + 3600, facecolor='gray', alpha=0.2) # Time axis and ticks plt.xticks(data["timestamps"][::timeDivisions], data["formatedTime"][::timeDivisions]) rainAxis.tick_params(axis='x', colors=colors["x-axis"]) # Rain (data gets splitted to stacked bars) logging.debug("Creating rain plot...") rainBars = [0] * len(self.rainColorSteps) for i in range(0, len(self.rainColorSteps)): rainBars[i] = [] for rain in data["rainfall"]: for i in range(0, len(self.rainColorSteps)): if rain > self.rainColorSteps[i]: rainBars[i].append(self.rainColorStepSizes[i]) else: if i > 0: rainBars[i].append( max(rain - self.rainColorSteps[i - 1], 0)) else: rainBars[i].append(rain) continue rainAxis.bar(data["timestamps"], rainBars[0], width=3000, color=self.rainColors[0], align='edge') bottom = [0] * len(rainBars[0]) for i in range(1, len(self.rainColorSteps)): bottom = np.add(bottom, rainBars[i - 1]).tolist() rainAxis.bar(data["timestamps"], rainBars[i], bottom=bottom, width=3000, color=self.rainColors[i], align='edge') rainAxis.tick_params(axis='y', labelcolor=colors["rain-axis"], width=0, length=8) rainYRange = plt.ylim() rainScaleMax = max( data["rainfall"] ) + 1 # Add a bit to make sure we do not bang our head plt.ylim(0, rainScaleMax) rainAxis.locator_params(axis='y', nbins=7) # TODO find a better way than rounding rainAxis.yaxis.set_major_formatter(FormatStrFormatter('%0.1f')) # Rain color bar as y axis plt.xlim( data["timestamps"][0], data["timestamps"][-1] + (data["timestamps"][1] - data["timestamps"][0])) pixelToRainX = 1 / xPixelsPerDay * (data["timestamps"][23] - data["timestamps"][0]) x = data["timestamps"][-1] + ( data["timestamps"][1] - data["timestamps"][0]) # end of x w = 7 * pixelToRainX for i in range(0, len(self.rainColorSteps)): y = self.rainColorSteps[i] - self.rainColorStepSizes[i] if y > rainScaleMax: break h = self.rainColorSteps[i] + self.rainColorStepSizes[i] if y + h >= rainScaleMax: # reached top h = rainScaleMax - y rainScaleBar = Rectangle((x, y), w, h, fc=self.rainColors[i], alpha=1) rainAxis.add_patch(rainScaleBar) rainScaleBar.set_clip_on(False) rainScaleBorder = Rectangle((x, 0), w, rainScaleMax, fc="black", fill=False, alpha=1) rainAxis.add_patch(rainScaleBorder) rainScaleBorder.set_clip_on(False) # Rain variance if rainVariance: rainfallVarianceAxis = rainAxis.twinx( ) # instantiate a second axes that shares the same x-axis rainfallVarianceAxis.axes.yaxis.set_visible(False) timestampsCentered = [i + 1500 for i in data["timestamps"]] rainfallVarianceMin = np.subtract( np.array(data["rainfall"]), np.array(data["rainfallVarianceMin"])) rainfallVarianceMax = np.subtract( np.array(data["rainfallVarianceMax"]), np.array(data["rainfall"])) rainfallVarianceAxis.errorbar( timestampsCentered, data["rainfall"], yerr=[rainfallVarianceMin, rainfallVarianceMax], fmt="none", elinewidth=1, alpha=0.5, ecolor='black', capsize=3) plt.ylim(0, rainScaleMax) # Show when the model was last calculated timestampLocal = data[ "modelCalculationTimestamp"] + self.utcOffset * 3600 l = mlines.Line2D([timestampLocal, timestampLocal], [rainYRange[0], rainScaleMax]) rainAxis.add_line(l) # Temperature logging.debug("Creating temerature plot...") temperatureAxis = rainAxis.twinx( ) # instantiate a second axes that shares the same x-axis temperatureAxis.plot(data["timestamps"], data["temperature"], label="temperature", color=self.temperatureColor, linewidth=4) #temperatureAxis.set_ylabel('Temperature', color=self.temperatureColor) temperatureAxis.tick_params(axis='y', labelcolor=colors["temperature-axis"]) temperatureAxis.grid(True) # Position the Y Scales temperatureAxis.yaxis.tick_left() rainAxis.yaxis.tick_right() # Make sure the temperature scaling has a gap of 45 pixel, so we can fit the labels interimPixelToTemperature = (np.nanmax(data["temperature"]) - np.nanmin(data["temperature"])) / height temperatureScaleMin = np.nanmin( data["temperature"]) - float(45) * interimPixelToTemperature temperatureScaleMax = np.nanmax( data["temperature"]) + float(45) * interimPixelToTemperature plt.ylim(temperatureScaleMin, temperatureScaleMax) temperatureAxis.locator_params(axis='y', nbins=6) temperatureAxis.yaxis.set_major_formatter(FormatStrFormatter('%0.1f')) pixelToTemperature = (temperatureScaleMax - temperatureScaleMin) / height # Temperature variance temperatureVarianceAxis = temperatureAxis.twinx( ) # instantiate a second axes that shares the same x-axis temperatureVarianceAxis.axes.yaxis.set_visible(False) temperatureVarianceAxis.fill_between(data["timestamps"], data["temperatureVarianceMin"], data["temperatureVarianceMax"], facecolor=self.temperatureColor, alpha=0.2) temperatureVarianceAxis.tick_params(axis='y', labelcolor=self.temperatureColor) plt.ylim(temperatureScaleMin, temperatureScaleMax) logging.debug("Adding various additional information to the graph...") # Mark min/max temperature per day if minMaxTemperature: da = DrawingArea(2, 2, 0, 0) da.add_artist( Circle((1, 1), 4, color=self.temperatureColor, fc="white", lw=2)) for day in range(0, data["noOfDays"]): dayXPixelMin = day * xPixelsPerDay dayXPixelMax = (day + 1) * xPixelsPerDay - 1 maxTemperatureOfDay = {"data": -100, "timestamp": 0} minTemperatureOfDay = {"data": +100, "timestamp": 0} for h in range(0, 24): if data["temperature"][day * 24 + h] > maxTemperatureOfDay["data"]: maxTemperatureOfDay["data"] = data["temperature"][day * 24 + h] maxTemperatureOfDay["timestamp"] = data["timestamps"][ day * 24 + h] maxTemperatureOfDay["xpixel"] = ( data["timestamps"][day * 24 + h] - data["timestamps"][0]) / (24 * 3600) * xPixelsPerDay maxTemperatureOfDay["ypixel"] = ( data["temperature"][day * 24 + h] - temperatureScaleMin) / ( temperatureScaleMax - temperatureScaleMin) * height if data["temperature"][day * 24 + h] < minTemperatureOfDay["data"]: minTemperatureOfDay["data"] = data["temperature"][day * 24 + h] minTemperatureOfDay["timestamp"] = data["timestamps"][ day * 24 + h] minTemperatureOfDay["xpixel"] = ( data["timestamps"][day * 24 + h] - data["timestamps"][0]) / (24 * 3600) * xPixelsPerDay minTemperatureOfDay["ypixel"] = ( data["temperature"][day * 24 + h] - temperatureScaleMin) / ( temperatureScaleMax - temperatureScaleMin) * height # Circles temperatureVarianceAxis.add_artist( AnnotationBbox(da, (maxTemperatureOfDay["timestamp"], maxTemperatureOfDay["data"]), xybox=(maxTemperatureOfDay["timestamp"], maxTemperatureOfDay["data"]), xycoords='data', boxcoords=("data", "data"), frameon=False)) temperatureVarianceAxis.add_artist( AnnotationBbox(da, (minTemperatureOfDay["timestamp"], minTemperatureOfDay["data"]), xybox=(minTemperatureOfDay["timestamp"], minTemperatureOfDay["data"]), xycoords='data', boxcoords=("data", "data"), frameon=False)) # Max Temperature Labels text = str(int(round(maxTemperatureOfDay["data"], 0))) + "°C" f = plt.figure( 1 ) # Temporary figure to get the dimensions of the text label t = plt.text(0, 0, text, weight='bold') temporaryLabel = t.get_window_extent( renderer=f.canvas.get_renderer()) plt.figure(0) # Select Main figure again # Check if text is fully within the day (x axis) if maxTemperatureOfDay[ "xpixel"] - temporaryLabel.width / 2 < dayXPixelMin: # To far left maxTemperatureOfDay[ "xpixel"] = dayXPixelMin + temporaryLabel.width / 2 + self.textShadowWidth / 2 if maxTemperatureOfDay[ "xpixel"] + temporaryLabel.width / 2 > dayXPixelMax: # To far right maxTemperatureOfDay[ "xpixel"] = dayXPixelMax - temporaryLabel.width / 2 - self.textShadowWidth / 2 temperatureVarianceAxis.annotate( text, xycoords=('axes pixels'), xy=(maxTemperatureOfDay["xpixel"], maxTemperatureOfDay["ypixel"] + 8), ha="center", va="bottom", color=colors["temperature-label"], weight='bold', path_effects=[ path_effects.withStroke(linewidth=self.textShadowWidth, foreground="w") ]) # Min Temperature Labels text = str(int(round(minTemperatureOfDay["data"], 0))) + "°C" f = plt.figure( 1 ) # Temporary figure to get the dimensions of the text label t = plt.text(0, 0, text, weight='bold') temporaryLabel = t.get_window_extent( renderer=f.canvas.get_renderer()) plt.figure(0) # Select Main figure again # Check if text is fully within the day (x axis) if minTemperatureOfDay[ "xpixel"] - temporaryLabel.width / 2 < dayXPixelMin: # To far left minTemperatureOfDay[ "xpixel"] = dayXPixelMin + temporaryLabel.width / 2 + self.textShadowWidth / 2 if minTemperatureOfDay[ "xpixel"] + temporaryLabel.width / 2 > dayXPixelMax: # To far right minTemperatureOfDay[ "xpixel"] = dayXPixelMax - temporaryLabel.width / 2 - self.textShadowWidth / 2 temperatureVarianceAxis.annotate( text, xycoords=('axes pixels'), xy=(minTemperatureOfDay["xpixel"], minTemperatureOfDay["ypixel"] - 12), ha="center", va="top", color=colors["temperature-label"], weight='bold', path_effects=[ path_effects.withStroke(linewidth=self.textShadowWidth, foreground="w") ]) # Print day names for day in range(0, data["noOfDays"]): rainAxis.annotate(data['dayNames'][day], xy=(day * xPixelsPerDay + xPixelsPerDay / 2, -45), xycoords='axes pixels', ha="center", weight='bold', color=colors["x-axis"]) # Show y-axis units rainAxis.annotate("mm\n/h", linespacing=0.8, xy=(width + 25, height + 12), xycoords='axes pixels', ha="center", color=colors["rain-axis"]) rainAxis.annotate("°C", xy=(-20, height + 10), xycoords='axes pixels', ha="center", color=colors["temperature-axis"]) # Show Symbols above the graph for i in range(0, len(data["symbols"]), symbolDivision): symbolFile = os.path.dirname( os.path.realpath(__file__)) + "/symbols/" + str( data["symbols"][i]) + ".png" if not os.path.isfile(symbolFile): logging.warning( "The symbol file %s seems to be missing. Please check the README.md!" % symbolFile) continue symbolImage = mpimg.imread(symbolFile) imagebox = OffsetImage(symbolImage, zoom=symbolZoom / 1.41 * 0.15) xyPos = ( (data["symbolsTimestamps"][i] - data["symbolsTimestamps"][0]) / (24 * 3600) + len(data["symbols"]) / 24 / 6 / data["noOfDays"]) * xPixelsPerDay, height + 22 ab = AnnotationBbox(imagebox, xy=xyPos, xycoords='axes pixels', frameon=False) rainAxis.add_artist(ab) # Show city name in graph # TODO find a way to show the label in the background if showCityName: logging.debug("Adding city name to plot...") text = fig.text(1 - 7 / width, 1 - 20 / height, self.cityName, color='gray', ha='right', transform=rainAxis.transAxes) text.set_path_effects([ path_effects.Stroke(linewidth=self.textShadowWidth, foreground='white'), path_effects.Normal() ]) # Save the graph in a png image file logging.debug("Saving graph to %s" % outputFilename) plt.savefig(outputFilename, facecolor=colors["background"]) plt.close() # Write Meta Data if writeMetaData: logging.debug("Saving Meta Data to %s" % writeMetaData) metaData = {} metaData['city'] = self.cityName metaData['imageHeight'] = graphHeight metaData['imageWidth'] = graphWidth metaData['firstDayX'] = firstDayX metaData['firstDayY'] = firstDayY metaData['dayWidth'] = dayWidth metaData['dayHeight'] = dayHeight metaData['modelTimestamp'] = self.data[ "modelCalculationTimestamp"] # Seconds in UTC with open(writeMetaData, 'w') as metaFile: json.dump(metaData, metaFile)
def modelMap(grids, shakefile=None, suptitle=None, inventory_shapefile=None, plotorder=None, maskthreshes=None, colormaps=None, boundaries=None, zthresh=0, scaletype='continuous', lims=None, logscale=False, ALPHA=0.7, maproads=True, mapcities=True, isScenario=False, roadfolder=None, topofile=None, cityfile=None, oceanfile=None, roadcolor='#6E6E6E', watercolor='#B8EEFF', countrycolor='#177F10', outputdir=None, savepdf=True, savepng=True, showplots=False, roadref='unknown', cityref='unknown', oceanref='unknown', printparam=False, ds=True, dstype='mean', upsample=False): """ This function creates maps of mapio grid layers (e.g. liquefaction or landslide models with their input layers) All grids must use the same bounds TO DO change so that all input layers do not have to have the same bounds, test plotting multiple probability layers, and add option so that if PDF and PNG aren't output, opens plot on screen using plt.show() :param grids: Dictionary of N layers and metadata formatted like: maplayers['layer name']={ 'grid': mapio grid2D object, 'label': 'label for colorbar and top line of subtitle', 'type': 'output or input to model', 'description': 'detailed description of layer for subtitle'}. Layer names must be unique. :type name: Dictionary or Ordered dictionary - import collections; grids = collections.OrderedDict() :param shakefile: optional ShakeMap file (url or full file path) to extract information for labels and folder names :type shakefile: Shakemap Event Dictionary :param suptitle: This will be displayed at the top of the plots and in the figure names :type suptitle: string :param plotorder: List of keys describing the order to plot the grids, if None and grids is an ordered dictionary, it will use the order of the dictionary, otherwise it will choose order which may be somewhat random but it will always put a probability grid first :type plotorder: list :param maskthreshes: N x 1 array or list of lower thresholds for masking corresponding to order in plotorder or order of OrderedDict if plotorder is None. If grids is not an ordered dict and plotorder is not specified, this will not work right. If None (default), nothing will be masked :param colormaps: List of strings of matplotlib colormaps (e.g. cm.autumn_r) corresponding to plotorder or order of dictionary if plotorder is None. The list can contain both strings and None e.g. colormaps = ['cm.autumn', None, None, 'cm.jet'] and None's will default to default colormap :param boundaries: None to show entire study area, 'zoom' to zoom in on the area of action (only works if there is a probability layer) using zthresh as a threshold, or a dictionary defining lats and lons in the form of boundaries.xmin = minlon, boundaries.xmax = maxlon, boundaries.ymin = min lat, boundaries.ymax = max lat :param zthresh: threshold for computing zooming bounds, only used if boundaries = 'zoom' :type zthresh: float :param scaletype: Type of scale for plotting, 'continuous' or 'binned' - will be reflected in colorbar :type scaletype: string :param lims: None or Nx1 list of tuples or numpy arrays corresponding to plotorder defining the limits for saturating the colorbar (vmin, vmax) if scaletype is continuous or the bins to use (clev) if scaletype if binned. The list can contain tuples, arrays, and Nones, e.g. lims = [(0., 10.), None, (0.1, 1.5), np.linspace(0., 1.5, 15)]. When None is specified, the program will estimate the limits, when an array is specified but the scale type is continuous, vmin will be set to min(array) and vmax will be set to max(array) :param lims: None or Nx1 list of Trues and Falses corresponding to plotorder defining whether to use a linear or log scale (log10) for plotting the layer. This will be reflected in the labels :param ALPHA: Transparency for mapping, if there is a hillshade that will plot below each layer, it is recommended to set this to at least 0.7 :type ALPHA: float :param maproads: Whether to show roads or not, default True, but requires that roadfile is specified and valid to work :type maproads: boolean :param mapcities: Whether to show cities or not, default True, but requires that cityfile is specified and valid to work :type mapcities: boolean :param isScenario: Whether this is a scenario (True) or a real event (False) (default False) :type isScenario: boolean :param roadfolder: Full file path to folder containing road shapefiles :type roadfolder: string :param topofile: Full file path to topography grid (GDAL compatible) - this is only needed to make a hillshade if a premade hillshade is not specified :type topofile: string :param cityfile: Full file path to Pager file containing city & population information :type cityfile: string :param roadcolor: Color to use for roads, if plotted, default #6E6E6E :type roadcolor: Hex color or other matplotlib compatible way of defining color :param watercolor: Color to use for oceans, lakes, and rivers, default #B8EEFF :type watercolor: Hex color or other matplotlib compatible way of defining color :param countrycolor: Color for country borders, default #177F10 :type countrycolor: Hex color or other matplotlib compatible way of defining color :param outputdir: File path for outputting figures, if edict is defined, a subfolder based on the event id will be created in this folder. If None, will use current directory :param savepdf: True to save pdf figure, False to not :param savepng: True to save png figure, False to not :param ds: True to allow downsampling for display (necessary when arrays are quite large, False to not allow) :param dstype: What function to use in downsampling, options are 'min', 'max', 'median', or 'mean' :param upsample: True to upsample the layer to the DEM resolution for better looking hillshades :returns: * PDF and/or PNG of map * Downsampled and trimmed version of input grids. If no modification was needed for plotting, this will be identical to grids but without the metadata """ if suptitle is None: suptitle = ' ' plt.ioff() defaultcolormap = cm.jet if shakefile is not None: edict = ShakeGrid.load(shakefile, adjust='res').getEventDict() temp = ShakeGrid.load(shakefile, adjust='res').getShakeDict() edict['eventid'] = temp['shakemap_id'] edict['version'] = temp['shakemap_version'] else: edict = None # Get output file location if outputdir is None: print('No output location given, using current directory for outputs\n') outputdir = os.getcwd() if edict is not None: outfolder = os.path.join(outputdir, edict['event_id']) else: outfolder = outputdir if not os.path.isdir(outfolder): os.makedirs(outfolder) # Get plotting order, if not specified if plotorder is None: plotorder = list(grids.keys()) # Get boundaries to use for all plots cut = True if boundaries is None: cut = False keytemp = list(grids.keys()) boundaries = grids[keytemp[0]]['grid'].getGeoDict() elif boundaries == 'zoom': # Find probability layer (will just take the maximum bounds if there is # more than one) keytemp = list(grids.keys()) key1 = [key for key in keytemp if 'model' in key.lower()] if len(key1) == 0: print('Could not find model layer to use for zoom, using default boundaries') keytemp = list(grids.keys()) boundaries = grids[keytemp[0]]['grid'].getGeoDict() else: lonmax = -1.e10 lonmin = 1.e10 latmax = -1.e10 latmin = 1.e10 for key in key1: # get lat lons of areas affected and add, if no areas affected, # switch to shakemap boundaries temp = grids[key]['grid'] xmin, xmax, ymin, ymax = temp.getBounds() lons = np.linspace(xmin, xmax, temp.getGeoDict().nx) lats = np.linspace(ymax, ymin, temp.getGeoDict().ny) # backwards so it plots right row, col = np.where(temp.getData() > float(zthresh)) lonmin = lons[col].min() lonmax = lons[col].max() latmin = lats[row].min() latmax = lats[row].max() # llons, llats = np.meshgrid(lons, lats) # make meshgrid # llons1 = llons[temp.getData() > float(zthresh)] # llats1 = llats[temp.getData() > float(zthresh)] # if llons1.min() < lonmin: # lonmin = llons1.min() # if llons1.max() > lonmax: # lonmax = llons1.max() # if llats1.min() < latmin: # latmin = llats1.min() # if llats1.max() > latmax: # latmax = llats1.max() boundaries1 = {'dx': 100, 'dy': 100., 'nx': 100., 'ny': 100} # dummy fillers, only really care about bounds if xmin < lonmin-0.15*(lonmax-lonmin): boundaries1['xmin'] = lonmin-0.1*(lonmax-lonmin) else: boundaries1['xmin'] = xmin if xmax > lonmax+0.15*(lonmax-lonmin): boundaries1['xmax'] = lonmax+0.1*(lonmax-lonmin) else: boundaries1['xmax'] = xmax if ymin < latmin-0.15*(latmax-latmin): boundaries1['ymin'] = latmin-0.1*(latmax-latmin) else: boundaries1['ymin'] = ymin if ymax > latmax+0.15*(latmax-latmin): boundaries1['ymax'] = latmax+0.1*(latmax-latmin) else: boundaries1['ymax'] = ymax boundaries = GeoDict(boundaries1, adjust='res') else: # SEE IF BOUNDARIES ARE SAME AS BOUNDARIES OF LAYERS keytemp = list(grids.keys()) tempgdict = grids[keytemp[0]]['grid'].getGeoDict() if np.abs(tempgdict.xmin-boundaries['xmin']) < 0.05 and \ np.abs(tempgdict.ymin-boundaries['ymin']) < 0.05 and \ np.abs(tempgdict.xmax-boundaries['xmax']) < 0.05 and \ np.abs(tempgdict.ymax - boundaries['ymax']) < 0.05: print('Input boundaries are almost the same as specified boundaries, no cutting needed') boundaries = tempgdict cut = False else: try: if boundaries['xmin'] > boundaries['xmax'] or \ boundaries['ymin'] > boundaries['ymax']: print('Input boundaries are not usable, using default boundaries') keytemp = list(grids.keys()) boundaries = grids[keytemp[0]]['grid'].getGeoDict() cut = False else: # Build dummy GeoDict boundaries = GeoDict({'xmin': boundaries['xmin'], 'xmax': boundaries['xmax'], 'ymin': boundaries['ymin'], 'ymax': boundaries['ymax'], 'dx': 100., 'dy': 100., 'ny': 100., 'nx': 100.}, adjust='res') except: print('Input boundaries are not usable, using default boundaries') keytemp = list(grids.keys()) boundaries = grids[keytemp[0]]['grid'].getGeoDict() cut = False # Pull out bounds for various uses bxmin, bxmax, bymin, bymax = boundaries.xmin, boundaries.xmax, boundaries.ymin, boundaries.ymax # Determine if need a single panel or multi-panel plot and if multi-panel, # how many and how it will be arranged fig = plt.figure() numpanels = len(grids) if numpanels == 1: rowpan = 1 colpan = 1 # create the figure and axes instances. fig.set_figwidth(5) elif numpanels == 2 or numpanels == 4: rowpan = np.ceil(numpanels/2.) colpan = 2 fig.set_figwidth(13) else: rowpan = np.ceil(numpanels/3.) colpan = 3 fig.set_figwidth(15) if rowpan == 1: fig.set_figheight(rowpan*6.0) else: fig.set_figheight(rowpan*5.3) # Need to update naming to reflect the shakemap version once can get # getHeaderData to work, add edict['version'] back into title, maybe # shakemap id also? fontsizemain = 14. fontsizesub = 12. fontsizesmallest = 10. if rowpan == 1.: fontsizemain = 12. fontsizesub = 10. fontsizesmallest = 8. if edict is not None: if isScenario: title = edict['event_description'] else: timestr = edict['event_timestamp'].strftime('%b %d %Y') title = 'M%.1f %s v%i - %s' % (edict['magnitude'], timestr, edict['version'], edict['event_description']) plt.suptitle(title+'\n'+suptitle, fontsize=fontsizemain) else: plt.suptitle(suptitle, fontsize=fontsizemain) clear_color = [0, 0, 0, 0.0] # Cut all of them and release extra memory xbuff = (bxmax-bxmin)/10. ybuff = (bymax-bymin)/10. cutxmin = bxmin-xbuff cutymin = bymin-ybuff cutxmax = bxmax+xbuff cutymax = bymax+ybuff if cut is True: newgrids = collections.OrderedDict() for k, layer in enumerate(plotorder): templayer = grids[layer]['grid'] try: newgrids[layer] = {'grid': templayer.cut(cutxmin, cutxmax, cutymin, cutymax, align=True)} except Exception as e: print(('Cutting failed, %s, continuing with full layers' % e)) newgrids = grids continue del templayer gc.collect() else: newgrids = grids tempgdict = newgrids[list(grids.keys())[0]]['grid'].getGeoDict() # Upsample layers to same as topofile if desired for better looking hillshades if upsample is True and topofile is not None: try: topodict = GDALGrid.getFileGeoDict(topofile) if topodict.dx >= tempgdict.dx or topodict.dy >= tempgdict.dy: print('Upsampling not possible, resolution of results already smaller than DEM') pass else: tempgdict1 = GeoDict({'xmin': tempgdict.xmin-xbuff, 'ymin': tempgdict.ymin-ybuff, 'xmax': tempgdict.xmax+xbuff, 'ymax': tempgdict.ymax+ybuff, 'dx': topodict.dx, 'dy': topodict.dy, 'nx': topodict.nx, 'ny': topodict.ny}, adjust='res') tempgdict2 = tempgdict1.getBoundsWithin(tempgdict) for k, layer in enumerate(plotorder): newgrids[layer]['grid'] = newgrids[layer]['grid'].subdivide(tempgdict2) except: print('Upsampling failed, continuing') # Downsample all of them for plotting, if needed, and replace them in # grids (to save memory) tempgrid = newgrids[list(grids.keys())[0]]['grid'] xsize = tempgrid.getGeoDict().nx ysize = tempgrid.getGeoDict().ny inchesx, inchesy = fig.get_size_inches() divx = int(np.round(xsize/(500.*inchesx))) divy = int(np.round(ysize/(500.*inchesy))) xmin, xmax, ymin, ymax = tempgrid.getBounds() gdict = tempgrid.getGeoDict() # Will be replaced if downsampled del tempgrid gc.collect() if divx <= 1: divx = 1 if divy <= 1: divy = 1 if (divx > 1. or divy > 1.) and ds: if dstype == 'max': func = np.nanmax elif dstype == 'min': func = np.nanmin elif dstype == 'med': func = np.nanmedian else: func = np.nanmean for k, layer in enumerate(plotorder): layergrid = newgrids[layer]['grid'] dat = block_reduce(layergrid.getData().copy(), block_size=(divy, divx), cval=float('nan'), func=func) if k == 0: lons = block_reduce(np.linspace(xmin, xmax, layergrid.getGeoDict().nx), block_size=(divx,), func=np.mean, cval=float('nan')) if math.isnan(lons[-1]): lons[-1] = lons[-2] + (lons[1]-lons[0]) lats = block_reduce(np.linspace(ymax, ymin, layergrid.getGeoDict().ny), block_size=(divy,), func=np.mean, cval=float('nan')) if math.isnan(lats[-1]): lats[-1] = lats[-2] + (lats[1]-lats[0]) gdict = GeoDict({'xmin': lons.min(), 'xmax': lons.max(), 'ymin': lats.min(), 'ymax': lats.max(), 'dx': np.abs(lons[1]-lons[0]), 'dy': np.abs(lats[1]-lats[0]), 'nx': len(lons), 'ny': len(lats)}, adjust='res') newgrids[layer]['grid'] = Grid2D(dat, gdict) del layergrid, dat else: lons = np.linspace(xmin, xmax, xsize) lats = np.linspace(ymax, ymin, ysize) # backwards so it plots right side up #make meshgrid llons1, llats1 = np.meshgrid(lons, lats) # See if there is an oceanfile for masking bbox = PolygonSH(((cutxmin, cutymin), (cutxmin, cutymax), (cutxmax, cutymax), (cutxmax, cutymin))) if oceanfile is not None: try: f = fiona.open(oceanfile) oc = next(f) f.close shapes = shape(oc['geometry']) # make boundaries into a shape ocean = shapes.intersection(bbox) except: print('Not able to read specified ocean file, will use default ocean masking') oceanfile = None if inventory_shapefile is not None: try: f = fiona.open(inventory_shapefile) invshp = list(f.items(bbox=(bxmin, bymin, bxmax, bymax))) f.close() inventory = [shape(inv[1]['geometry']) for inv in invshp] except: print('unable to read inventory shapefile specified, will not plot inventory') inventory_shapefile = None # # Find cities that will be plotted if mapcities is True and cityfile is not None: try: mycity = BasemapCities.loadFromGeoNames(cityfile=cityfile) bcities = mycity.limitByBounds((bxmin, bxmax, bymin, bymax)) #bcities = bcities.limitByPopulation(40000) bcities = bcities.limitByGrid(nx=4, ny=4, cities_per_grid=2) except: print('Could not read in cityfile, not plotting cities') mapcities = False cityfile = None # Load in topofile if topofile is not None: try: topomap = GDALGrid.load(topofile, resample=True, method='linear', samplegeodict=gdict) except: topomap = GMTGrid.load(topofile, resample=True, method='linear', samplegeodict=gdict) topodata = topomap.getData().copy() # mask oceans if don't have ocean shapefile if oceanfile is None: topodata = maskoceans(llons1, llats1, topodata, resolution='h', grid=1.25, inlands=True) else: print('no hillshade is possible\n') topomap = None topodata = None # Load in roads, if needed if maproads is True and roadfolder is not None: try: roadslist = [] for folder in os.listdir(roadfolder): road1 = os.path.join(roadfolder, folder) shpfiles = glob.glob(os.path.join(road1, '*.shp')) if len(shpfiles): shpfile = shpfiles[0] f = fiona.open(shpfile) shapes = list(f.items(bbox=(bxmin, bymin, bxmax, bymax))) for shapeid, shapedict in shapes: roadslist.append(shapedict) f.close() except: print('Not able to plot roads') roadslist = None val = 1 for k, layer in enumerate(plotorder): layergrid = newgrids[layer]['grid'] if 'label' in list(grids[layer].keys()): label1 = grids[layer]['label'] else: label1 = layer try: sref = grids[layer]['description']['name'] except: sref = None ax = fig.add_subplot(rowpan, colpan, val) val += 1 clat = bymin + (bymax-bymin)/2.0 clon = bxmin + (bxmax-bxmin)/2.0 # setup of basemap ('lcc' = lambert conformal conic). # use major and minor sphere radii from WGS84 ellipsoid. m = Basemap(llcrnrlon=bxmin, llcrnrlat=bymin, urcrnrlon=bxmax, urcrnrlat=bymax, rsphere=(6378137.00, 6356752.3142), resolution='l', area_thresh=1000., projection='lcc', lat_1=clat, lon_0=clon, ax=ax) x1, y1 = m(llons1, llats1) # get projection coordinates axsize = ax.get_window_extent().transformed(fig.dpi_scale_trans.inverted()) if k == 0: wid, ht = axsize.width, axsize.height if colormaps is not None and \ len(colormaps) == len(newgrids) and \ colormaps[k] is not None: palette = colormaps[k] else: # Find preferred default color map for each type of layer if 'prob' in layer.lower() or 'pga' in layer.lower() or \ 'pgv' in layer.lower() or 'cohesion' in layer.lower() or \ 'friction' in layer.lower() or 'fs' in layer.lower(): palette = cm.jet elif 'slope' in layer.lower(): palette = cm.gnuplot2 elif 'precip' in layer.lower(): palette = cm2.s3pcpn else: palette = defaultcolormap if topodata is not None: if k == 0: ptopo = m.transform_scalar( np.flipud(topodata), lons+0.5*gdict.dx, lats[::-1]-0.5*gdict.dy, np.round(300.*wid), np.round(300.*ht), returnxy=False, checkbounds=False, order=1, masked=False) #use lightsource class to make our shaded topography ls = LightSource(azdeg=135, altdeg=45) ls1 = LightSource(azdeg=120, altdeg=45) ls2 = LightSource(azdeg=225, altdeg=45) intensity1 = ls1.hillshade(ptopo, fraction=0.25, vert_exag=1.) intensity2 = ls2.hillshade(ptopo, fraction=0.25, vert_exag=1.) intensity = intensity1*0.5 + intensity2*0.5 #hillshm_im = m.transform_scalar(np.flipud(hillshm), lons, lats[::-1], np.round(300.*wid), np.round(300.*ht), returnxy=False, checkbounds=False, order=0, masked=False) #m.imshow(hillshm_im, cmap='Greys', vmin=0., vmax=3., zorder=1, interpolation='none') # vmax = 3 to soften colors to light gray #m.pcolormesh(x1, y1, hillshm, cmap='Greys', linewidth=0., rasterized=True, vmin=0., vmax=3., edgecolors='none', zorder=1); # plt.draw() # Get the data dat = layergrid.getData().copy() # mask out anything below any specified thresholds # Might need to move this up to before downsampling...might give illusion of no hazard in places where there is some that just got averaged out if maskthreshes is not None and len(maskthreshes) == len(newgrids): if maskthreshes[k] is not None: dat[dat <= maskthreshes[k]] = float('NaN') dat = np.ma.array(dat, mask=np.isnan(dat)) if logscale is not False and len(logscale) == len(newgrids): if logscale[k] is True: dat = np.log10(dat) label1 = r'$log_{10}$(' + label1 + ')' if scaletype.lower() == 'binned': # Find order of range to know how to scale order = np.round(np.log(np.nanmax(dat) - np.nanmin(dat))) if order < 1.: scal = 10**-order else: scal = 1. if lims is None or len(lims) != len(newgrids): clev = (np.linspace(np.floor(scal*np.nanmin(dat)), np.ceil(scal*np.nanmax(dat)), 10))/scal else: if lims[k] is None: clev = (np.linspace(np.floor(scal*np.nanmin(dat)), np.ceil(scal*np.nanmax(dat)), 10))/scal else: clev = lims[k] # Adjust to colorbar levels dat[dat < clev[0]] = clev[0] for j, level in enumerate(clev[:-1]): dat[(dat >= clev[j]) & (dat < clev[j+1])] = clev[j] # So colorbar saturates at top dat[dat > clev[-1]] = clev[-1] #panelhandle = m.contourf(x1, y1, datm, clev, cmap=palette, linewidth=0., alpha=ALPHA, rasterized=True) vmin = clev[0] vmax = clev[-1] else: if lims is not None and len(lims) == len(newgrids): if lims[k] is None: vmin = np.nanmin(dat) vmax = np.nanmax(dat) else: vmin = lims[k][0] vmax = lims[k][-1] else: vmin = np.nanmin(dat) vmax = np.nanmax(dat) # Mask out cells overlying oceans or block with a shapefile if available if oceanfile is None: dat = maskoceans(llons1, llats1, dat, resolution='h', grid=1.25, inlands=True) else: #patches = [] if type(ocean) is PolygonSH: ocean = [ocean] for oc in ocean: patch = getProjectedPatch(oc, m, edgecolor="#006280", facecolor=watercolor, lw=0.5, zorder=4.) #x, y = m(oc.exterior.xy[0], oc.exterior.xy[1]) #xy = zip(x, y) #patch = Polygon(xy, facecolor=watercolor, edgecolor="#006280", lw=0.5, zorder=4.) ##patches.append(Polygon(xy, facecolor=watercolor, edgecolor=watercolor, zorder=500.)) ax.add_patch(patch) ##ax.add_collection(PatchCollection(patches)) if inventory_shapefile is not None: for in1 in inventory: if 'point' in str(type(in1)): x, y = in1.xy x = x[0] y = y[0] m.scatter(x, y, c='m', s=50, latlon=True, marker='^', zorder=100001) else: x, y = m(in1.exterior.xy[0], in1.exterior.xy[1]) xy = list(zip(x, y)) patch = Polygon(xy, facecolor='none', edgecolor='k', lw=0.5, zorder=10.) #patches.append(Polygon(xy, facecolor=watercolor, edgecolor=watercolor, zorder=500.)) ax.add_patch(patch) palette.set_bad(clear_color, alpha=0.0) # Plot it up dat_im = m.transform_scalar( np.flipud(dat), lons+0.5*gdict.dx, lats[::-1]-0.5*gdict.dy, np.round(300.*wid), np.round(300.*ht), returnxy=False, checkbounds=False, order=0, masked=True) if topodata is not None: # Drape over hillshade #turn data into an RGBA image cmap = palette #adjust data so scaled between vmin and vmax and between 0 and 1 dat1 = dat_im.copy() dat1[dat1 < vmin] = vmin dat1[dat1 > vmax] = vmax dat1 = (dat1 - vmin)/(vmax-vmin) rgba_img = cmap(dat1) maskvals = np.dstack((dat1.mask, dat1.mask, dat1.mask)) rgb = np.squeeze(rgba_img[:, :, 0:3]) rgb[maskvals] = 1. draped_hsv = ls.blend_hsv(rgb, np.expand_dims(intensity, 2)) m.imshow(draped_hsv, zorder=3., interpolation='none') # This is just a dummy layer that will be deleted to make the # colorbar look right panelhandle = m.imshow(dat_im, cmap=palette, zorder=0., vmin=vmin, vmax=vmax) else: panelhandle = m.imshow(dat_im, cmap=palette, zorder=3., vmin=vmin, vmax=vmax, interpolation='none') #panelhandle = m.pcolormesh(x1, y1, dat, linewidth=0., cmap=palette, vmin=vmin, vmax=vmax, alpha=ALPHA, rasterized=True, zorder=2.); #panelhandle.set_edgecolors('face') # add colorbar cbfmt = '%1.1f' if vmax is not None and vmin is not None: if (vmax - vmin) < 1.: cbfmt = '%1.2f' elif vmax > 5.: # (vmax - vmin) > len(clev): cbfmt = '%1.0f' #norm = mpl.colors.Normalize(vmin=vmin, vmax=vmax) if scaletype.lower() == 'binned': cbar = fig.colorbar(panelhandle, spacing='proportional', ticks=clev, boundaries=clev, fraction=0.036, pad=0.04, format=cbfmt, extend='both') #cbar1 = ColorbarBase(cbar.ax, cmap=palette, norm=norm, spacing='proportional', ticks=clev, boundaries=clev, fraction=0.036, pad=0.04, format=cbfmt, extend='both', extendfrac='auto') else: cbar = fig.colorbar(panelhandle, fraction=0.036, pad=0.04, extend='both', format=cbfmt) #cbar1 = ColorbarBase(cbar.ax, cmap=palette, norm=norm, fraction=0.036, pad=0.04, extend='both', extendfrac='auto', format=cbfmt) if topodata is not None: panelhandle.remove() cbar.set_label(label1, fontsize=10) cbar.ax.tick_params(labelsize=8) parallels = m.drawparallels(getMapLines(bymin, bymax, 3), labels=[1, 0, 0, 0], linewidth=0.5, labelstyle='+/-', fontsize=9, xoffset=-0.8, color='gray', zorder=100.) m.drawmeridians(getMapLines(bxmin, bxmax, 3), labels=[0, 0, 0, 1], linewidth=0.5, labelstyle='+/-', fontsize=9, color='gray', zorder=100.) for par in parallels: try: parallels[par][1][0].set_rotation(90) except: pass #draw roads on the map, if they were provided to us if maproads is True and roadslist is not None: try: for road in roadslist: try: xy = list(road['geometry']['coordinates']) roadx, roady = list(zip(*xy)) mapx, mapy = m(roadx, roady) m.plot(mapx, mapy, roadcolor, lw=0.5, zorder=9) except: continue except Exception as e: print(('Failed to plot roads, %s' % e)) #add city names to map if mapcities is True and cityfile is not None: try: fontname = 'Arial' fontsize = 8 if k == 0: # Only need to choose cities first time and then apply to rest fcities = bcities.limitByMapCollision( m, fontname=fontname, fontsize=fontsize) ctlats, ctlons, names = fcities.getCities() cxis, cyis = m(ctlons, ctlats) for ctlat, ctlon, cxi, cyi, name in zip(ctlats, ctlons, cxis, cyis, names): m.scatter(ctlon, ctlat, c='k', latlon=True, marker='.', zorder=100000) ax.text(cxi, cyi, name, fontname=fontname, fontsize=fontsize, zorder=100000) except Exception as e: print('Failed to plot cities, %s' % e) #draw star at epicenter plt.sca(ax) if edict is not None: elat, elon = edict['lat'], edict['lon'] ex, ey = m(elon, elat) plt.plot(ex, ey, '*', markeredgecolor='k', mfc='None', mew=1.0, ms=15, zorder=10000.) m.drawmapboundary(fill_color=watercolor) m.fillcontinents(color=clear_color, lake_color=watercolor) m.drawrivers(color=watercolor) ##m.drawcoastlines() #draw country boundaries m.drawcountries(color=countrycolor, linewidth=1.0) #add map scale m.drawmapscale((bxmax+bxmin)/2., (bymin+(bymax-bymin)/9.), clon, clat, np.round((((bxmax-bxmin)*111)/5)/10.)*10, barstyle='fancy', zorder=10) # Add border autoAxis = ax.axis() rec = Rectangle((autoAxis[0]-0.7, autoAxis[2]-0.2), (autoAxis[1]-autoAxis[0])+1, (autoAxis[3]-autoAxis[2])+0.4, fill=False, lw=1, zorder=1e8) rec = ax.add_patch(rec) rec.set_clip_on(False) plt.draw() if sref is not None: label2 = '%s\nsource: %s' % (label1, sref) # '%s\n' % label1 + r'{\fontsize{10pt}{3em}\selectfont{}%s}' % sref # else: label2 = label1 plt.title(label2, axes=ax, fontsize=fontsizesub) #draw scenario watermark, if scenario if isScenario: plt.sca(ax) cx, cy = m(clon, clat) plt.text(cx, cy, 'SCENARIO', rotation=45, alpha=0.10, size=72, ha='center', va='center', color='red') #if ds: # Could add this to print "downsampled" on map # plt.text() if k == 1 and rowpan == 1: # adjust single level plot axsize = ax.get_window_extent().transformed(fig.dpi_scale_trans.inverted()) ht2 = axsize.height fig.set_figheight(ht2*1.6) else: plt.tight_layout() # Make room for suptitle - tight layout doesn't account for it plt.subplots_adjust(top=0.92) if printparam is True: try: fig = plt.gcf() dictionary = grids['model']['description']['parameters'] paramstring = 'Model parameters: ' halfway = np.ceil(len(dictionary)/2.) for i, key in enumerate(dictionary): if i == halfway and colpan == 1: paramstring += '\n' paramstring += ('%s = %s; ' % (key, dictionary[key])) print(paramstring) fig.text(0.01, 0.015, paramstring, fontsize=fontsizesmallest) plt.draw() except: print('Could not display model parameters') if edict is not None: eventid = edict['eventid'] else: eventid = '' time1 = datetime.datetime.utcnow().strftime('%d%b%Y_%H%M') outfile = os.path.join(outfolder, '%s_%s_%s.pdf' % (eventid, suptitle, time1)) pngfile = os.path.join(outfolder, '%s_%s_%s.png' % (eventid, suptitle, time1)) if savepdf is True: print('Saving map output to %s' % outfile) plt.savefig(outfile, dpi=300) if savepng is True: print('Saving map output to %s' % pngfile) plt.savefig(pngfile) if showplots is True: plt.show() else: plt.close(fig) return newgrids
def highlight_artist(self, val, artist=None): from ifigure.matplotlib_mod.art3d_gl import Poly3DCollectionGL from ifigure.matplotlib_mod.art3d_gl import Line3DCollectionGL figure=self.get_figpage()._artists[0] ax = self.get_figaxes() if artist is None: alist=self._artists else: alist=artist if val == True: if self._parent is None: return container = self.get_container() if container is None: return if isinstance(alist[0], Poly3DCollectionGL): hl = alist[0].add_hl_mask() for item in hl: alist[0].figobj_hl.append(item) else: de = self.get_data_extent() x=(de[0], de[1],de[1],de[0],de[0]) y=(de[2], de[2],de[3],de[3],de[2]) facecolor='k' if isinstance(alist[0], Poly3DCollectionGL): hl = alist[0].make_hl_artist(container) facecolor = 'none' self._hit_path = None elif isinstance(alist[0], Line3DCollectionGL): hl = alist[0].make_hl_artist(container) facecolor = 'none' self._hit_path = None else: hl= container.plot(x, y, marker='s', color='k', linestyle='None', markerfacecolor='None', markeredgewidth = 0.5, scalex=False, scaley=False) for item in hl: alist[0].figobj_hl.append(item) if self._hit_path is not None: v = self._hit_path.vertices hl= container.plot(v[:,0], v[:,1], marker='s', color='k', linestyle='None', markerfacecolor='None', markeredgewidth = 0.5, scalex=False, scaley=False) for item in hl: alist[0].figobj_hl.append(item) hlp = Rectangle((de[0],de[2]), de[1]-de[0], de[3]-de[2], alpha=0.3, facecolor=facecolor, figure = figure, transform= container.transData) if ax is not None: x0, y0 = ax._artists[0].transAxes.transform((0,0)) x1, y1 = ax._artists[0].transAxes.transform((1,1)) bbox = Bbox([[x0,y0],[x1,y1]]) hlp.set_clip_box(bbox) hlp.set_clip_on(True) figure.patches.append(hlp) alist[0].figobj_hl.append(hlp) else: for a in alist: if len(a.figobj_hl) == 0: continue for hl in a.figobj_hl[:-1]: hl.remove() if isinstance(alist[0], Poly3DCollectionGL): a.figobj_hl[-1].remove() else: figure.patches.remove(a.figobj_hl[-1]) a.figobj_hl=[]
def plot_beast_ifit(filters, waves, stats, pdf1d_hdu): # setup the plot grid gs = gridspec.GridSpec(4, 4, height_ratios=[1.0, 1.0, 1.0, 1.0], width_ratios=[1.0, 1.0, 1.0, 1.0]) ax = [] # plots for the 1D PDFs for j in range(2): for i in range(4): ax.append(plt.subplot(gs[j + 2, i])) # now for the big SED plot ax.append(plt.subplot(gs[0:2, 0:3])) # plot the SED #print(np.sort(stats.colnames)) n_filters = len(filters) # get the observations waves *= 1e-4 obs_flux = np.empty((n_filters), dtype=np.float) mod_flux = np.empty((n_filters, 3), dtype=np.float) mod_flux_nd = np.empty((n_filters, 3), dtype=np.float) mod_flux_wbias = np.empty((n_filters, 3), dtype=np.float) k = starnum c = ap_SkyCoord(ra=stats['RA'][k] * ap_units.degree, dec=stats['DEC'][k] * ap_units.degree, frame='icrs') corname = ('PHAT J' + c.ra.to_string(unit=ap_units.hourangle, sep="", precision=2, alwayssign=False, pad=True) + c.dec.to_string(sep="", precision=2, alwayssign=True, pad=True)) for i, cfilter in enumerate(filters): obs_flux[i] = stats[cfilter][k] mod_flux[i, 0] = np.power(10.0, stats['log' + cfilter + '_wd_p50'][k]) mod_flux[i, 1] = np.power(10.0, stats['log' + cfilter + '_wd_p16'][k]) mod_flux[i, 2] = np.power(10.0, stats['log' + cfilter + '_wd_p84'][k]) mod_flux_nd[i, 0] = np.power(10.0, stats['log' + cfilter + '_nd_p50'][k]) mod_flux_nd[i, 1] = np.power(10.0, stats['log' + cfilter + '_nd_p16'][k]) mod_flux_nd[i, 2] = np.power(10.0, stats['log' + cfilter + '_nd_p84'][k]) if 'log' + cfilter + '_wd_bias_p50' in stats.colnames: mod_flux_wbias[i, 0] = np.power( 10.0, stats['log' + cfilter + '_wd_bias_p50'][k]) mod_flux_wbias[i, 1] = np.power( 10.0, stats['log' + cfilter + '_wd_bias_p16'][k]) mod_flux_wbias[i, 2] = np.power( 10.0, stats['log' + cfilter + '_wd_bias_p84'][k]) ax[8].plot(waves, obs_flux, 'ko', label='observed') if 'log' + filters[0] + '_wd_bias_p50' in stats.colnames: ax[8].plot(waves, mod_flux_wbias[:, 0], 'b-', label='stellar+dust+bias') ax[8].fill_between(waves, mod_flux_wbias[:, 1], mod_flux_wbias[:, 2], color='b', alpha=0.3) ax[8].plot(waves, mod_flux[:, 0], 'r-', label='stellar+dust') ax[8].fill_between(waves, mod_flux[:, 1], mod_flux[:, 2], color='r', alpha=0.2) ax[8].plot(waves, mod_flux_nd[:, 0], 'y-', label='stellar only') ax[8].fill_between(waves, mod_flux_nd[:, 1], mod_flux_nd[:, 2], color='y', alpha=0.1) ax[8].legend(loc='upper right', bbox_to_anchor=(1.25, 1.025)) ax[8].set_ylabel(r'Flux [ergs s$^{-1}$ cm$^{-2}$ $\AA^{-1}$]') ax[8].set_yscale('log') ax[8].set_xscale('log') ax[8].text(0.5, -0.01, r'$\lambda$ [$\AA$]', transform=ax[8].transAxes, va='top') ax[8].set_xlim(0.2, 2.0) ax[8].set_xticks([0.2, 0.3, 0.4, 0.5, 0.8, 0.9, 1.0, 2.0]) ax[8].get_xaxis().set_major_formatter(matplotlib.ticker.ScalarFormatter()) ax[8].text(0.05, 0.95, corname, transform=ax[8].transAxes, va='top', ha='left') # add the text results keys = ['Av', 'M_ini', 'logA', 'Rv', 'f_A', 'Z', 'logT', 'logg', 'logL'] dispnames = [ 'A(V)', 'log(M)', 'log(t)', 'R(V)', r'f$_\mathcal{A}$', 'Z', r'log(T$_\mathrm{eff})$', 'log(g)', 'log(L)' ] laby = 0.72 ty = np.linspace(laby - 0.07, 0.1, num=len(keys)) ty[3:] -= 0.025 ty[6:] -= 0.025 tx = [1.12, 1.2, 1.3] for i in range(len(keys)): ax[8].text(tx[0], ty[i], dispnames[i], ha='right', transform=ax[8].transAxes) ax[8].text(tx[1], ty[i], disp_str(stats, starnum, keys[i]), ha='center', color='m', transform=ax[8].transAxes) best_val = stats[keys[i] + '_Best'][k] if keys[i] == 'M_ini': best_val = np.log10(best_val) ax[8].text(tx[2], ty[i], '$' + "{0:.2f}".format(best_val) + '$', ha='center', color='c', transform=ax[8].transAxes) ax[8].text(tx[0], laby, 'Param', ha='right', transform=ax[8].transAxes) ax[8].text(tx[1], laby, '50%$\pm$33%', ha='center', color='k', transform=ax[8].transAxes) ax[8].text(tx[2], laby, 'Best', color='k', ha='center', transform=ax[8].transAxes) # now draw boxes around the different kinds of parameters tax = ax[8] # primary rec = Rectangle((tx[0] - 0.1, ty[2] - 0.02), tx[2] - tx[0] + 0.15, (ty[0] - ty[2]) * 1.5, fill=False, lw=2, transform=tax.transAxes, ls='dashed') rec = tax.add_patch(rec) rec.set_clip_on(False) # secondary rec = Rectangle((tx[0] - 0.1, ty[5] - 0.02), tx[2] - tx[0] + 0.15, (ty[3] - ty[5]) * 1.5, fill=False, lw=2, transform=tax.transAxes, ls='dotted') rec = tax.add_patch(rec) rec.set_clip_on(False) # derived rec = Rectangle((tx[0] - 0.1, ty[8] - 0.02), tx[2] - tx[0] + 0.15, (ty[6] - ty[8]) * 1.5, fill=False, lw=2, transform=tax.transAxes, ls='dashdot') rec = tax.add_patch(rec) rec.set_clip_on(False) # padding for rectangles of 1D PDFs pad = 0.1 # plot the primary parameter 1D PDFs plot_1dpdf(ax[0], pdf1d_hdu, 'Av', 'A(V)', starnum, stats=stats) plot_1dpdf(ax[1], pdf1d_hdu, 'M_ini', 'log(M)', starnum, logx=True, stats=stats) plot_1dpdf(ax[2], pdf1d_hdu, 'logA', 'log(t)', starnum, stats=stats) # draw a box around them and label tax = ax[0] rec = Rectangle((-1.75 * pad, -pad), 3 * (1.0 + pad) + 1.5 * pad, 1.0 + 1.5 * pad, fill=False, lw=2, transform=tax.transAxes, ls='dashed') rec = tax.add_patch(rec) rec.set_clip_on(False) tax.text(-2. * pad, 0.5, 'Primary', transform=tax.transAxes, rotation='vertical', fontstyle='oblique', va='center', ha='right') tax.text(0.0, 0.5, 'Probability', transform=tax.transAxes, rotation='vertical', va='center', ha='right') # plot the secondary parameter 1D PDFs plot_1dpdf(ax[4], pdf1d_hdu, 'Rv', 'R(V)', starnum, stats=stats) plot_1dpdf(ax[5], pdf1d_hdu, 'f_A', r'f$_\mathcal{A}$', starnum, stats=stats) plot_1dpdf(ax[6], pdf1d_hdu, 'Z', 'Z', starnum, stats=stats) # draw a box around them tax = ax[4] rec = Rectangle((-1.75 * pad, -pad), 3 * (1.0 + pad) + 1.5 * pad, 1.0 + 1.5 * pad, fill=False, lw=2, transform=tax.transAxes, ls='dotted') rec = tax.add_patch(rec) rec.set_clip_on(False) tax.text(-2 * pad, 0.5, 'Secondary', transform=tax.transAxes, rotation='vertical', fontstyle='oblique', va='center', ha='right') tax.text(0.0, 0.5, 'Probability', transform=tax.transAxes, rotation='vertical', va='center', ha='right') # plot the derived parameter 1D PDFs plot_1dpdf(ax[3], pdf1d_hdu, 'logT', r'log(T$_\mathrm{eff})$', starnum, stats=stats) plot_1dpdf(ax[7], pdf1d_hdu, 'logg', 'log(g)', starnum, stats=stats) # draw a box around them tax = ax[7] rec = Rectangle((-0.25 * pad, -pad), 1.0 + 0.5 * pad, 2 * (1.0 + 2. * pad) - 0.125 * pad, fill=False, lw=2, transform=tax.transAxes, ls='dashdot') rec = tax.add_patch(rec) rec.set_clip_on(False) tax.text(0.5, 2 * (1.0 + 2 * pad) - 1.0 * pad, 'Derived', transform=tax.transAxes, rotation='horizontal', fontstyle='oblique', va='bottom', ha='center') # optimize the figure layout plt.tight_layout(h_pad=2.0, w_pad=1.0)