Python implementation of the CellPlot from the CellPlot package for R.
    -inf or inf enrichments will come out as min found float or max found float, respectively.

    :param df: pandas dataframe with the following columns - 'Enrichment', 'Term', and 'log2fc'.
               For log2fc each cell must contain a comma separated string with the log2fc for the genes enriched in the respective term.
               eg. '-inf,-1,2,3.4,3.66,inf'
    :param output_file: prefix for an output file. If given it will create output_file.CellPlot.svg and output_file.CellPlot.png
    :param gene_expression: label for the color gradiant bar.
    :param figure_title: Figure title.
    :param pvalCol: name of the column containing the p values to determine if the terms should be marked as NS - not significant, use None for no marking
    :param lowerLimit: lower limit for the heatmap bar (default is the 0.1 percentile)
    :param upperLimit: upper limit for the heatmap bar (default is the 0.9 percentile)
    :param colorBarType: type of heatmap, 'Spectral' is dafault, alternative eg. 'seismic'
    :returns: a matplotlib figure

def CellPlot(df, output_file=None, gene_expression="log2FC", figure_title="CellPlot", pvalCol="elimFisher", lowerLimit=None, upperLimit=None, colorBarType='Spectral'):
    """
    Python implementation of the CellPlot from the CellPlot package for R.
    -inf or inf enrichments will come out as min found float or max found float, respectively.

    :param df: pandas dataframe with the following columns - 'Enrichment', 'Term', and 'log2fc'.
               For log2fc each cell must contain a comma separated string with the log2fc for the genes enriched in the respective term.
               eg. '-inf,-1,2,3.4,3.66,inf'
    :param output_file: prefix for an output file. If given it will create output_file.CellPlot.svg and output_file.CellPlot.png
    :param gene_expression: label for the color gradiant bar.
    :param figure_title: Figure title.
    :param pvalCol: name of the column containing the p values to determine if the terms should be marked as NS - not significant, use None for no marking
    :param lowerLimit: lower limit for the heatmap bar (default is the 0.1 percentile)
    :param upperLimit: upper limit for the heatmap bar (default is the 0.9 percentile)
    :param colorBarType: type of heatmap, 'Spectral' is dafault, alternative eg. 'seismic'
    :returns: a matplotlib figure
    """
    limits=pd.DataFrame(df['log2fc'].str.split(",").tolist())
    limits=limits.as_matrix().flatten()
    limits=pd.DataFrame(limits)
    limits[0]=limits[0].astype(str)
    limits=limits[limits[0]!="None"][limits[0]!=""]

    try:
        limits=[float(x) for x in limits[0].tolist()]

    except (ValueError,e):
        print("error",e,"on line")

    if upperLimit:
        maxFC=upperLimit
    else:
        maxFC=np.percentile(limits,90)

    if lowerLimit:
        minFC=lowerLimit
    else:
        minFC=np.percentile(limits,10)

    #maxFC=np.percentile(limits,90)
    #minFC=np.percentile(limits,10)

    cmap = matplotlib.cm.get_cmap(colorBarType)
    norm = matplotlib.colors.Normalize(vmin=minFC, vmax=maxFC)

    if len(df)>10:
        siz=len(df)*3/10
    elif len(df)==1:
        siz=1
    elif len(df)==2:
        siz=2
    else:
        siz=3


    fig = plt.figure(figsize=(8, siz))
    #fig.suptitle(figure_title, fontsize=24, fontweight='bold')

    ax1 = fig.add_axes([0.05, 3.5/( float(siz)*float(10)/float(3) ), 0.9, 2])
    ax2 = fig.add_axes([0.05, 1.5/( float(siz)*float(10)/float(3) ), 0.9, 1.5/( float(siz)*float(10)/float(3) )])
    arrangment=np.arange(len(df))+.5
    df['Enrichment']=df['Enrichment'].astype(float)
    enr=df['Enrichment'].tolist()
    enr=[x for x in enr if str(x) != str(float("inf"))]
    enr=[x for x in enr if str(x) != str(float("-inf"))]

    m=max(enr)

    maxE=max(enr)
    minE=min(enr)

    def getINFs(x,maxFC=maxFC,minFC=minFC):
        if x == str(float("inf")):
            return maxFC
        elif x == str(float("-inf")):
            return minFC
        else:
            return x

    def fix_enrichment(x,minE=minE,maxE=maxE):
        if str(x) == str(float("inf")):
            return maxE
        elif str(x) == str(float("-inf")):
            return minE
        else:
            return x

    df['Enrichment']=df['Enrichment'].apply(lambda x: fix_enrichment(x))


    ax1.barh(arrangment, df['Enrichment'].tolist(), color='white', edgecolor='black')#range(0,len(test))
    for i,pos in zip(df.index.tolist(),arrangment):
        fcs=df.ix[i,'log2fc'].split(",")
        fcs=pd.DataFrame(fcs)
        fcs[0]=fcs[0].astype(str)
        fcs[0]=fcs[0].apply(lambda x: getINFs(x))

        #fcs=fcs[fcs[0]!=""].astype(float)[0].tolist()
        fcs=fcs.astype(float)[0].tolist()

        try:
            w=float(df.ix[i,'Enrichment'])/float(len(fcs))
        except:
            print(df.ix[i,])
        p=0
        fcs.sort(key=float)
        for f in fcs:
            #if float(f) > maxFC:
            #    f=maxFC
            #if float(f) < minFC:
            #    f=minFC
            #ax1.barh(pos, w, left=p, color=cmap(norm(float(f))), edgecolor='black')
            ax1.barh(pos, w, left=p, color=cmap(norm(float(f))), edgecolor=cmap(norm(float(f))))
            p=p+w
        if pvalCol:
            df[pvalCol] = df[pvalCol].astype(float)
            if df.ix[i,pvalCol] < 0.05:
                barAn=len(fcs)
            else:
                barAn=str(len(fcs))+" (NS)"
        else:
            barAn=len(fcs)
        ax1.text(df.ix[i,'Enrichment']+m*0.02, pos, barAn, ha='left', va='bottom')
    ax1.set_yticks(arrangment) # +0.4
    ax1.set_yticklabels(df['Term'].tolist())

    ax1.tick_params(
        axis='y',
        which='both',
        left='off',
        right='off',
        labelleft='on')

    ax1.tick_params(
        axis='x',
        which='both',
        bottom='off',
        top='on',
        labelbottom='off',
        labeltop='on')

    ax1.set_ylim(ymax = max(arrangment) + 1.5 ) #1.5
    ax1.set_xlabel("GO Term Enrichment")
    ax1.xaxis.set_label_position('top')

    ax1.spines['right'].set_visible(False)
    ax1.spines['bottom'].set_visible(False)

    cb1 = matplotlib.colorbar.ColorbarBase(ax2, cmap=cmap,norm=norm, orientation='horizontal')
    if not lowerLimit:
        if not upperLimit:
            cb1.set_label(gene_expression+'\n(0.1-0.9 percentiles)\n\n\n'+figure_title)
        else:
            cb1.set_label(gene_expression+'\n\n\n'+figure_title)
    else:
        cb1.set_label(gene_expression+'\n\n\n'+figure_title)

    #plt.subplots_adjust(top=8.5)

    #ax1.annotate('a fractional title', xy=(.025, .975), xycoords='figure fraction', horizontalalignment='center', verticalalignment='top', fontsize=20)
    #plt.subplots_adjust(top=500)
    #ax1.text(2, 2, 'right bottom',
    #    horizontalalignment='center',
    #    verticalalignment='center',
    #    transform=ax1.transAxes)

    if output_file:
        plt.savefig(output_file+".CellPlot.png",dpi=300,bbox_inches='tight', pad_inches=0.1,format='png')
        plt.savefig(output_file+".CellPlot.svg",dpi=300,bbox_inches='tight', pad_inches=0.1,format='svg')

    return fig