Example #1
0
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)
Example #2
0
    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)