def perfect_visualizer(p_subplot_list,gridspec_params,**kwargs): #p_subplot_list: list of perfect_subplot #gridspec_params = [rows,cols] of the subplot grid. Should be compatible with the coordinates of the perfect_subplots #kwargs: contains instructions to visualize everything dimensions=kwarg_default("dimensions",1,**kwargs) height=kwarg_default("height",0.15,**kwargs) textcols=kwarg_default("textcols",1,**kwargs) rows=kwarg_default("rows",gridspec_params[0],**kwargs) cols=kwarg_default("cols",gridspec_params[1],**kwargs) #set the height differently depending on if most plots are colormaps (2D), and thus need colorbars if dimensions == 1: adjust_bottom=kwarg_default("adjust_bottom",0.15,**kwargs) adjust_left=kwarg_default("adjust_left",0.17,**kwargs) adjust_top=kwarg_default("adjust_top",0.97,**kwargs) adjust_right=kwarg_default("adjust_right",0.95,**kwargs) base_rows=3.0 elif dimensions == 2: adjust_bottom=kwarg_default("adjust_bottom",0.15,**kwargs) adjust_left=kwarg_default("adjust_left",0.12,**kwargs) adjust_top=kwarg_default("adjust_top",0.85,**kwargs) adjust_right=kwarg_default("adjust_right",0.99,**kwargs) base_rows=2.0 base_topbot_adjust=adjust_bottom+(1-adjust_top) def row_to_height(rows): return (rows/base_rows)*3.39*(1-base_topbot_adjust)*(numpy.sqrt(5)-1.0)/2.0 +3.39*base_topbot_adjust*(numpy.sqrt(5)-1.0)/2.0 height=row_to_height(rows) base_height=row_to_height(base_rows) adjust_bottom=adjust_bottom*base_height/height adjust_top=1-(1-adjust_top)*base_height/height latexify(fig_height=height,columns=textcols) fig=plt.figure() fig.subplots_adjust(bottom=adjust_bottom) fig.subplots_adjust(left=adjust_left) fig.subplots_adjust(top=adjust_top) fig.subplots_adjust(right=adjust_right) adjust_hspace=kwarg_default("adjust_hspace",0.01,**kwargs) adjust_wspace=kwarg_default("adjust_wspace",0.01,**kwargs) fig.subplots_adjust(hspace=adjust_hspace) fig.subplots_adjust(wspace=adjust_wspace) global_xlabel=kwarg_default("global_xlabel",None,**kwargs) if global_xlabel is not None: if dimensions == 1: fig.text(0.5+adjust_left/4, 0.01, global_xlabel, ha='center') elif dimensions == 2: fig.text(0.5+adjust_left/4, 0.01*base_height/height, global_xlabel, ha='center') global_ylabel=kwarg_default("global_ylabel",None,**kwargs) if global_ylabel is not None: if dimensions == 1: fig.text(0.01, 0.5+adjust_bottom/4, global_ylabel, va='center', rotation='vertical') elif dimensions == 2: fig.text(0.01, 0.5+adjust_bottom/4.0, global_ylabel, va='center', rotation='vertical') gs=gridspec.GridSpec(gridspec_params[0],gridspec_params[1]) ax_list=[] for p_subplot in p_subplot_list: ax_list.append(plt.subplot(gs[p_subplot.subplot_coordinates])) for ax,p_subplot in zip(ax_list,p_subplot_list): monkey_patch(ax.xaxis,'x') monkey_patch(ax.yaxis,'y') #keywords in the p_subplot to control looks: ax.spines['bottom'].set_color(p_subplot.border_color) ax.spines['top'].set_color(p_subplot.border_color) ax.spines['left'].set_color(p_subplot.border_color) ax.spines['right'].set_color(p_subplot.border_color) ax.spines['bottom'].set_linestyle(p_subplot.border_linestyle) ax.spines['top'].set_linestyle(p_subplot.border_linestyle) ax.spines['left'].set_linestyle(p_subplot.border_linestyle) ax.spines['right'].set_linestyle(p_subplot.border_linestyle) if p_subplot.vlines is not None: for p in p_subplot.vlines: ax.axvline(x=p,color='k',linestyle=':') if p_subplot.hlines is not None: for p in p_subplot.hlines: ax.axhline(y=p,color='silver',linestyle=':') if p_subplot.show_xaxis_ticklabel == False: plt.setp(ax.get_xticklabels(), visible=False) ax.xaxis.get_major_formatter().set_powerlimits((float("-inf"), float("inf"))) else: plt.setp(ax.get_xticklabels(), visible=True) if p_subplot.show_yaxis_ticklabel == False: plt.setp(ax.get_yticklabels(), visible=False) ax.yaxis.get_major_formatter().set_powerlimits((float("-inf"), float("inf"))) if p_subplot.show_xaxis == False: plt.setp(ax.xaxis, visible=False) if p_subplot.show_yaxis == False: plt.setp(ax.yaxis, visible=False) if p_subplot.xscale == 'linear': x_locator=ticker.MaxNLocator(p_subplot.xticks) if p_subplot.xscale == 'log': x_locator=ticker.LogLocator(p_subplot.xticks) ax.xaxis.set_major_locator(x_locator) if p_subplot.yscale == 'linear': y_locator=ticker.MaxNLocator(p_subplot.yticks) if p_subplot.yscale == 'log': y_locator=ticker.LogLocator(p_subplot.yticks) ax.yaxis.set_major_locator(y_locator) ############## 1D ######### if p_subplot.dimensions == 1: x=p_subplot.x y=p_subplot.data ax.yaxis.offset_text_position="there" if type(p_subplot.linestyles) is not list: p_subplot.linestyles=[p_subplot.linestyles]*len(y) p_subplot.linewidths=[p_subplot.linewidths]*len(y) for i in range(len(y)): try: ax.plot(x[i],y[i],linestyle=p_subplot.linestyles[i],color=p_subplot.colors[i],linewidth=p_subplot.linewidths[i],marker=p_subplot.markers[i],fillstyle=p_subplot.fillstyles[i]) except IndexError: print "Index error in ax.plot(). Most likely, linestyles, linewidths and colors have the wrong lengths." print "len(colors): " + str(len(p_subplot.colors)) print "len(linestyles): " + str(len(p_subplot.linestyles)) print "len(linewidths): " + str(len(p_subplot.linewidths)) print "len(markers): " + str(len(p_subplot.markers)) print "len(fillstyles): " + str(len(p_subplot.fillstyles)) print "len(x): " + str(len(x)) print "len(y): " + str(len(y)) ax.yaxis.set_label_coords(-0.15, 0.5) ############# 2D ########### if p_subplot.dimensions == 2: X,Y=numpy.meshgrid(p_subplot.x,p_subplot.y) z=numpy.transpose(p_subplot.data) ax.pcolor(X, Y, z,rasterized=True,linewidth=0) if p_subplot.show_zaxis == True: divider = make_axes_locatable(ax) cax = divider.append_axes("top", "-10%", pad="10%") cb=fig.colorbar(ax.collections[0],cax=cax,orientation="horizontal") #cb.solids.set_edgecolor("face") monkey_patch(cb.ax.xaxis, 'x') if p_subplot.yscale == 'linear': tick_locator = ticker.MaxNLocator(nbins=p_subplot.zticks) if p_subplot.yscale == 'log': tick_locator = ticker.LogLocator(nbins=p_subplot.zticks) cb.locator=tick_locator cb.ax.xaxis.set_ticks_position('top') cb.ax.xaxis.set_label_position('top') cb.ax.set_xscale(p_subplot.zscale) cb.ax.tick_params(direction='out', pad=1) cb.formatter.set_powerlimits((0, 0)) cb.update_ticks() if p_subplot.show_zaxis_ticklabel == False: plt.setp(cb.ax.get_xticklabels(), visible=False) #makes it impossible to have an offset without a ticklabel cb.formatter.set_powerlimits((float("-inf"), float("inf"))) cb.update_ticks() cb.ax.xaxis.offset_text_position="there2" if p_subplot.zaxis_label is not None: cb.ax.set_xlabel(p_subplot.zaxis_label) if p_subplot.zlims is not None: zmin=p_subplot.zlims[0] zmax=p_subplot.zlims[1] ax.collections[0].set_clim(zmin,zmax) cm=p_subplot.cm if p_subplot.symmetrize_cm: cm=symmetrize_colormap(cm,zmin,zmax) ax.collections[0].set_cmap(cm) for i in p_subplot.hidden_zticklabels: plt.setp(cb.ax.get_xticklabels()[i],visible=False) cb.solids.set_edgecolor("face") #we need to sort out ticks after plotting, since they are generated #during the plot operation if p_subplot.xaxis_label is not None: ax.set_xlabel(p_subplot.xaxis_label) if p_subplot.yaxis_label is not None: #print str(p_subplot.yaxis_label)+": " +"("+str(p_subplot.yaxis_label_x)+","+str(p_subplot.yaxis_label_y)+")" ax.set_ylabel(p_subplot.yaxis_label) ax.yaxis.set_label_coords(p_subplot.yaxis_label_x,p_subplot.yaxis_label_y) if p_subplot.xlims is not None: ax.set_xlim(p_subplot.xlims) if p_subplot.xlims is not None: ax.set_ylim(p_subplot.ylims) if p_subplot.xaxis_powerlimits is not None: print "Warning: xlabel power limits not fully implemented: offset position unknown, offset not shown." ax.ticklabel_format(axis='x', style='sci', scilimits=p_subplot.xaxis_powerlimits) #ax.xaxis.get_major_formatter().set_powerlimits(p_subplot.xaxis_powerlimits) if p_subplot.yscale == 'log': ax.set_yscale(p_subplot.yscale, nonposy='clip',subsy=[10]) for ticklabel in ax.get_yticklabels()[0:2:-1]: ticklabel.set_visible(False) ax.get_yticklabels()[0].set_visible(False) ax.get_yticklabels()[-1].set_visible(False) ax.get_yticklabels()[1].set_visible(False) ax.get_yticklabels()[-2].set_visible(False) elif p_subplot.yscale=='linear': if p_subplot.yaxis_powerlimits is None: ax.ticklabel_format(axis='y', style='sci', scilimits=(-0,1)) else: ax.ticklabel_format(axis='y', style='sci', scilimits=p_subplot.yaxis_powerlimits) ax.get_yticklabels()[0].set_visible(False) ax.get_yticklabels()[-1].set_visible(False) elif p_subplot.yscale=='symlog': ax.set_yscale(p_subplot.yscale) for i in p_subplot.hidden_xticklabels: plt.setp(ax.get_xticklabels()[i],visible=False) for i in p_subplot.hidden_yticklabels: plt.setp(ax.get_yticklabels()[i],visible=False) #print str(p_subplot.title)+": " +"("+str(p_subplot.title_x)+","+str(p_subplot.title_y)+")" ax.set_title(p_subplot.title,x=p_subplot.title_x,y=p_subplot.title_y,fontsize=8)
def __init__(self,data,x,subplot_coordinates,dimensions=None,y=None,**kwargs): #this object contains instructions for what to plot in a numpy subplot with gridspec #dimensions: whether to visualize data as a 2D colormap, or several 1D plots in the same subplot # this can be partially infered from the dimensions of the data #data: the data to go into this plot. Should be a 1D, list of 1D, or 2D numpy array #x,y: x/y grid points corresponding to the indices in the data array. y value needed for 2D arrays #subplot_coordinates: where to put this plot on the gridspec #**kwargs: extra visualization options that will be different depending on "dimensions". #data_<X>axis: how to intepret the axes of the data array. <X>=x,(line),(y) #x_<X>axis: how to intepret the axes of the x array. <X>=x,(line),(y) #show_<X>axis: whether to show axis when plotting. <X>=x,y,(z) #show_<X>axis_label: whether to show axis label when plotting. <X>=x,y,(z) #kwargs that may change how we intepret the data data_xaxis=kwarg_default("data_xaxis",0,**kwargs) data_otheraxis=(data_xaxis+1)%2 #use rank of input data to try to determine dimensions #and reshape appropriately rank=arraylist_rank(data) if rank == 1: #put it in a list for consistency with multi-array code data=[data] if dimensions==None: dimensions=1 elif rank == 2: #can be a 2D function or several 1D. #please manually specify to avoid ambiguity #default assumes second index reperesents species/simulation #if it is under or equal to 4.# if dimensions==None: print "perfect_subplot: warning: ambigious array rank." if y == None: dimensions=1 else: dimensions=2 elif type(rank) is list: if all(x == 1 for x in rank): if dimensions==None: dimensions=1 else: print rank print "perfect_subplot: error: input list has array(s) of rank above 1." exit(1) #kwargs related to tagging this subplot self.groups=kwarg_default("groups",[],**kwargs) #kwargs related to flagging how the subplot should be visualized self.border_color=kwarg_default("border_color",'k',**kwargs) self.border_linestyle=kwarg_default("border_linestyle",'solid',**kwargs) self.title=kwarg_default("title","",**kwargs) #axis propert kwargs self.show_xaxis=kwarg_default("show_xaxis",True,**kwargs) self.show_yaxis=kwarg_default("show_yaxis",True,**kwargs) #powerlimit should be a tuple: (-a,b) self.xaxis_powerlimits=kwarg_default("xaxis_powerlimits",None,**kwargs) self.yaxis_powerlimits=kwarg_default("yaxis_powerlimits",None,**kwargs) self.xaxis_label=kwarg_default("xaxis_label",None,**kwargs) self.yaxis_label=kwarg_default("yaxis_label",None,**kwargs) self.show_xaxis_ticklabel=kwarg_default("show_xaxis_ticklabel",False,**kwargs) self.show_yaxis_ticklabel=kwarg_default("show_yaxis_ticklabel",False,**kwargs) self.xscale=kwarg_default("xscale",'linear',**kwargs) self.yscale=kwarg_default("yscale",'linear',**kwargs) self.xlims=kwarg_default("xlims",None,**kwargs) self.ylims=kwarg_default("ylims",None,**kwargs) self.vlines=kwarg_default("vlines",None,**kwargs) self.hlines=kwarg_default("hlines",None,**kwargs) self.yaxis_label_x=kwarg_default("yaxis_label_x",-0.15,**kwargs) self.yaxis_label_y=kwarg_default("yaxis_label_y",0.5,**kwargs) ############################################################################# # # 1D # ############################################################################# if dimensions==1: #going to visualize 1D data self.dimensions=1 #split 2D array into list of 1D arrays self.data=array2D_to_array_list(data,data_otheraxis) #print self.data #terminology suitable for 1D case data_lineaxis=data_otheraxis #kwarg needed to intepret x, which can be a list of arrays here x_xaxis=kwarg_default("x_xaxis",0,**kwargs) x_lineaxis=(x_xaxis+1)%2 if type(arraylist_rank(x)) is not list: if arraylist_rank(x) == 1: if all(len(x) != len(self.data[i]) for i in range(len(self.data))): print "perfect_subplot: 1D: error: data and x have different dimensions" exit(1) else: #make the x list the same size as the data list self.x=[x]*len(self.data) elif arraylist_rank(x) == 2: self.x=array2D_to_array_list(x,x_lineaxis) else: print "perfect_subplot: 1D: error: x has too high rank to be plotted" exit(1) else: if all(len(x[i]) != len(self.data[i]) for i in range(len(self.data))): print "perfect_subplot: 1D: error: data and x have different dimensions" exit(1) else: self.x=x #x is now a list of 1D arrays. Check compatiblity with data if len(self.x) != len(self.data): print "perfect_subplot: 1D: error: data and x list have different lengths" exit(1) elif not all(len(self.x[i]) == len(self.data[i]) for i in range(len(self.data))): print "perfect_subplot: 1D: error: some data and x have different lengths" exit(1) self.subplot_coordinates=subplot_coordinates #aesthetic kwargs self.xticks=kwarg_default("xticks",6,**kwargs) if self.yscale=='linear': self.yticks=kwarg_default("yticks",5,**kwargs) if self.yscale=='log': self.yticks=kwarg_default("yticks",4,**kwargs) self.hidden_xticklabels=kwarg_default("hidden_xticklabels",[],**kwargs) self.hidden_yticklabels=kwarg_default("hidden_yticklabels",[0,-1],**kwargs) self.linestyles=kwarg_default("linestyles",["solid"]*len(x),**kwargs) self.markers=kwarg_default("markers",[""]*len(x),**kwargs) self.fillstyles=kwarg_default("fillstyles",["full"]*len(x),**kwargs) self.linewidths=kwarg_default("linewidths",[1]*len(x),**kwargs) self.colors=kwarg_default("colors",["k"]*len(x),**kwargs) #title position self.title_y=kwarg_default("title_y",0.4,**kwargs) self.title_x=kwarg_default("title_x",1.04,**kwargs) ############################################################################# # # 2D # ############################################################################# if dimensions==2: #going to visualize 2D data self.dimensions=2 if y is None: print "perfect_subplot: 2D: error: need y for 2D plot." exit(1) #terminology suitable for 2D case data_yaxis=data_otheraxis if (data_xaxis == 0) and (data_yaxis == 1): self.data=data elif (data_xaxis == 1) and (data_yaxis == 0): #we always want our x data along the first axis self.data=numpy.transpose(data) else: print "perfect_subplot: 2D: error: data has too high rank to be plotted" exit(1) if (arraylist_rank(x) !=1) or (arraylist_rank(y) != 1): print "perfect_subplot: 2D: error: x and y should have rank 1" self.x=x self.y=y self.subplot_coordinates=subplot_coordinates #kwargs related to flagging how the subplot should be visualized #z-axis refers to the colorbar for the colormap self.show_zaxis=kwarg_default("show_zaxis",True,**kwargs) self.zaxis_label=kwarg_default("zaxis_label",None,**kwargs) self.show_zaxis_ticklabel=kwarg_default("show_zaxis_ticklabel",False,**kwargs) self.zscale=kwarg_default("zscale",'linear',**kwargs) self.xticks=kwarg_default("xticks",4,**kwargs) self.yticks=kwarg_default("yticks",4,**kwargs) self.zticks=kwarg_default("zticks",4,**kwargs) self.zlims=kwarg_default("zlims",None,**kwargs) self.cm=kwarg_default("cm",invert_cm(cm_remove_middle(cm.RdBu,cut_radius=0.1)),**kwargs) #self.cm=kwarg_default("cm",invert_cm(cm.RdBu),**kwargs) #self.cm=kwarg_default("cm",diverging_rb_cm(),**kwargs) self.symmetrize_cm=kwarg_default("symmetrize_cm",True,**kwargs) self.hidden_xticklabels=kwarg_default("hidden_xticklabels",[0,-1],**kwargs) self.hidden_yticklabels=kwarg_default("hidden_yticklabels",[],**kwargs) self.hidden_zticklabels=kwarg_default("hidden_zticklabels",[],**kwargs) #title position self.title_y=kwarg_default("title_y",1.19,**kwargs) self.title_x=kwarg_default("title_x",0.5,**kwargs)