2015-10-08 15 views
7

Ho il seguente panda dataframe ("A" è intestazione dell'ultima colonna, il resto delle colonne sono un indice gerarchico combinato):tabella gerarchica a torta/ciambella da Pandas dataframe utilizzando bokeh o matplotlib

A 
kingdom  phylum   class    order    family      genus    species    
No blast hit                               2496 
k__Archaea p__Euryarchaeota c__Thermoplasmata o__E2    f__[Methanomassiliicoccaceae] g__vadinCA11  s__    6 
k__Bacteria p__    c__    o__     f__       g__    s__    5 
      p__Actinobacteria c__Acidimicrobiia o__Acidimicrobiales f__       g__    s__    0 
           c__Actinobacteria o__Actinomycetales f__Corynebacteriaceae   g__Corynebacterium s__stationis  2 
                     f__Micrococcaceae    g__Arthrobacter s__    8 
               o__Bifidobacteriales f__Bifidobacteriaceae   g__Bifidobacterium s__    506 
                                 s__animalis  48 
           c__Coriobacteriia o__Coriobacteriales f__Coriobacteriaceae   g__    s__    734 
                            g__Collinsella  s__aerofaciens  3 

(un CSV con i dati è disponibile here)

Voglio tracciare un grafico a torta/ciambella, dove ogni cerchio concentrico è un livello (regno, phylum, ecc.) ed è diviso in base alla somma della colonna A per quel livello, quindi termino con qualcosa di simile a questo, ma con i miei dati:

disk usage chart

Ho guardato in matplotlib e bokeh, ma la cosa più simile che ho trovato finora è l'esempio bokeh grafico ciambella, utilizzando un grafico deprecato, che io non so come estrapolare per più di 2 livelli.

+0

Ciao, non un risposta pitonica, ma potresti essere interessato a un programma perl molto carino per farlo, dove il diagramma è interattivo (puoi ingrandire le sottocategorie), si chiama _Krona Tools_: [https://github.com/marbl/Krona /wiki](https://github.com/marbl/Krona/wiki). Inoltre, come vedo che sei MetaPhlAn e lavori sull'abbondanza di taxon, potresti apprezzare la mia pipeline _metaBIT_ che automatizza l'esecuzione di MetaPhlAn e le analisi down-stream (compresi i grafici di Krona): [https://bitbucket.org/Glouvel/metabit] (https://bitbucket.org/Glouvel/metabit) – PlasmaBinturong

risposta

7

Non so se c'è qualcosa di predefinito che lo faccia, ma è possibile costruirlo utilizzando i grafici a torta groupby e sovrapposti. Ho costruito il seguente script per prendere i tuoi dati e ottenere qualcosa di simile a quello che hai specificato.

Si noti che le chiamate di gruppo (utilizzate per calcolare i totali a ciascun livello) devono essere disattivate per consentire l'allineamento delle cose correttamente. Anche il set di dati è molto poco uniforme, quindi ho appena creato dati casuali per distribuire un po 'il grafico risultante a scopo illustrativo.

Probabilmente dovrai modificare i colori e le posizioni delle etichette, ma potrebbe essere un inizio.

import pandas as pd 
import matplotlib.pyplot as plt 
import numpy as np 

df = pd.read_csv('species.csv') 
df = df.dropna() # Drop the "no hits" line 
df['A'] = np.random.rand(len(df)) * 100 + 1 

# Do the summing to get the values for each layer 
def nested_pie(df): 

    cols = df.columns.tolist() 
    outd = {} 
    gb = df.groupby(cols[0], sort=False).sum() 
    outd[0] = {'names':gb.index.values, 'values':gb.values} 
    for lev in range(1,7): 
     gb = df.groupby(cols[:(lev+1)], sort=False).sum() 
     outd[lev] = {'names':gb.index.levels[lev][gb.index.labels[lev]].tolist(), 
        'values':gb.values} 
    return outd 

outd = nested_pie(df) 
diff = 1/7.0 

# This first pie chart fill the plot, it's the lowest level 
plt.pie(outd[6]['values'], labels=outd[6]['names'], labeldistance=0.9, 
     colors=plt.style.library['bmh']['axes.color_cycle']) 
ax = plt.gca() 
# For each successive plot, change the max radius so that they overlay 
for i in np.arange(5,-1,-1): 
    ax.pie(outd[i]['values'], labels=outd[i]['names'], 
      radius=np.float(i+1)/7.0, labeldistance=((2*(i+1)-1)/14.0)/((i+1)/7.0), 
      colors=plt.style.library['bmh']['axes.color_cycle']) 
ax.set_aspect('equal') 

Modulo lievi modifiche dalla chiamata a random(), questo produce una trama simile a questo: layered pie chart random data

sui dati reali, che appare così:

layered pie chart user data