115 votes

Jupyter notebook affiche deux tableaux pandas côte à côte

J'ai deux dataframes pandas et je voudrais les afficher dans le notebook Jupyter.

Faire quelque chose comme :

display(df1)
display(df2)

Les montre l'un en dessous de l'autre :

enter image description here

Je voudrais avoir un deuxième cadre de données à droite du premier. Il y a une question similaire mais il semble qu'une personne se contente soit de les fusionner dans un seul cadre de données, soit de montrer la différence entre eux.

Cela ne fonctionnera pas pour moi. Dans mon cas, les dataframes peuvent représenter des éléments complètement différents (non comparables) et leur taille peut être différente. Mon objectif principal est donc de gagner de l'espace.

0 votes

J'ai posté la solution de Jake Vanderplas. Un code propre et agréable.

156voto

ntg Points 498

J'ai fini par écrire une fonction qui peut faire cela : [mise à jour : ajout de titres basés sur des suggestions (merci @Antony_Hatchkins et al.)]

from IPython.display import display_html
from itertools import chain,cycle
def display_side_by_side(*args,titles=cycle([''])):
    html_str=''
    for df,title in zip(args, chain(titles,cycle(['</br>'])) ):
        html_str+='<th style="text-align:center"><td style="vertical-align:top">'
        html_str+=f'<h2>{title}</h2>'
        html_str+=df.to_html().replace('table','table style="display:inline"')
        html_str+='</td></th>'
    display_html(html_str,raw=True)

Exemple d'utilisation :

df1 = pd.DataFrame(np.arange(12).reshape((3,4)),columns=['A','B','C','D',])
df2 = pd.DataFrame(np.arange(16).reshape((4,4)),columns=['A','B','C','D',])
display_side_by_side(df1,df2,df1, titles=['Foo','Foo Bar']) #we left 3rd empty...

enter image description here

0 votes

C'est vraiment génial, merci. Pensez-vous qu'il serait facile ou non d'ajouter le nom du cadre de données au-dessus de chaque sortie ?

0 votes

Merci pour votre réponse, j'ai ajout d'en-têtes d'une manière similaire à celle que vous avez décrite dans votre dernier commentaire.

0 votes

Réponse étonnante. C'est également ce que je recherche. Je suis encore en train d'apprendre à m'y retrouver, alors je veux savoir : 1) Pourquoi avez-vous utilisé *args au lieu de simplement df ? Est-ce parce que vous pouvez avoir plusieurs entrées avec *args ? 2) Quelle partie de votre fonction fait en sorte que le deuxième df et les suivants s'ajoutent à la droite du premier au lieu d'être en dessous ? Est-ce le 'table style="display:inline"' partie ? Merci encore

100voto

zarak Points 1821

Vous pouvez remplacer le CSS du code de sortie. Il utilise flex-direction: column par défaut. Essayez de le changer en row à la place. Voici un exemple :

import pandas as pd
import numpy as np
from IPython.display import display, HTML

CSS = """
.output {
    flex-direction: row;
}
"""

HTML('<style>{}</style>'.format(CSS))

Jupyter image

Vous pouvez, bien sûr, personnaliser davantage le CSS comme vous le souhaitez.

Si vous souhaitez cibler la sortie d'une seule cellule, essayez d'utiliser la fonction :nth-child() sélecteur. Par exemple, ce code modifiera le CSS de la sortie de la 5e cellule seulement du cahier :

CSS = """
div.cell:nth-child(5) .output {
    flex-direction: row;
}
"""

0 votes

Que se passe-t-il si je veux donner un titre distinct à chacun d'eux ? J'ai essayé de le faire, mais je n'y suis pas arrivé.

6 votes

Cette solution affecte toutes les cellules, comment puis-je le faire pour une seule cellule ?

0 votes

@NeerajKomuravalli Il serait probablement préférable de poser cette question dans un nouvel article. Je ne suis pas sûr d'un moyen facile de le faire.

51voto

gibbone Points 179

À partir de pandas 0.17.1 la visualisation des DataFrames peut être directement modifiée avec méthodes de style pandas

Pour afficher deux DataFrames côte à côte, vous devez utiliser set_table_attributes avec l'argument "style='display:inline'" comme suggéré dans réponse de la ntg . Cela renverra deux Styler objets. Pour afficher les dataframes alignés, il suffit de passer leur représentation HTML jointe par la fonction display_html d'IPython.

Avec cette méthode, il est également plus facile d'ajouter d'autres options de style. Voici comment ajouter une légende, comme demandé aquí :

import numpy as np
import pandas as pd   
from IPython.display import display_html 

df1 = pd.DataFrame(np.arange(12).reshape((3,4)),columns=['A','B','C','D',])
df2 = pd.DataFrame(np.arange(16).reshape((4,4)),columns=['A','B','C','D',])

df1_styler = df1.style.set_table_attributes("style='display:inline'").set_caption('Caption table 1')
df2_styler = df2.style.set_table_attributes("style='display:inline'").set_caption('Caption table 2')

display_html(df1_styler._repr_html_()+df2_styler._repr_html_(), raw=True)

aligned dataframes pandas styler with caption

1 votes

Je n'avais pas remarqué, cela semble très bien et peut probablement être utile dans plus de situations pour ajouter, par exemple, la couleur, etc. (+1)

0 votes

@gibbone existe-t-il un moyen de spécifier l'espacement entre les tableaux ?

13voto

Yasin Zähringer Points 141

Ma solution se contente de construire un tableau en HTML sans aucune manipulation CSS et de le sortir :

import pandas as pd
from IPython.display import display,HTML

def multi_column_df_display(list_dfs, cols=3):
    html_table = "<table style='width:100%; border:0px'>{content}</table>"
    html_row = "<tr style='border:0px'>{content}</tr>"
    html_cell = "<td style='width:{width}%;vertical-align:top;border:0px'>{{content}}</td>"
    html_cell = html_cell.format(width=100/cols)

    cells = [ html_cell.format(content=df.to_html()) for df in list_dfs ]
    cells += (cols - (len(list_dfs)%cols)) * [html_cell.format(content="")] # pad
    rows = [ html_row.format(content="".join(cells[i:i+cols])) for i in range(0,len(cells),cols)]
    display(HTML(html_table.format(content="".join(rows))))

list_dfs = []
list_dfs.append( pd.DataFrame(2*[{"x":"hello"}]) )
list_dfs.append( pd.DataFrame(2*[{"x":"world"}]) )
multi_column_df_display(2*list_dfs)

Output

11voto

Private Points 1289

Voici la solution de Jake Vanderplas sur laquelle je suis tombé l'autre jour :

import numpy as np
import pandas as pd

class display(object):
    """Display HTML representation of multiple objects"""
    template = """<div style="float: left; padding: 10px;">
    <p style='font-family:"Courier New", Courier, monospace'>{0}</p>{1}
    </div>"""

    def __init__(self, *args):
        self.args = args

    def _repr_html_(self):
        return '\n'.join(self.template.format(a, eval(a)._repr_html_())
                     for a in self.args)

    def __repr__(self):
       return '\n\n'.join(a + '\n' + repr(eval(a))
                       for a in self.args)

Crédit : https://github.com/jakevdp/PythonDataScienceHandbook/blob/master/notebooks/03.08-Aggregation-and-Grouping.ipynb

1 votes

Pourriez-vous expliquer cette réponse ? Jake VanderPlas ne l'a pas expliqué sur son site web. C'est la seule solution qui imprime le nom du jeu de données en haut.

0 votes

Que voulez-vous savoir ?

0 votes

Peut-être une description de toutes les fonctions/comment elles fonctionnent, comment elles sont appelées, etc... pour que les programmeurs python débutants puissent les comprendre correctement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X