Mam dwie pandy dataframe i chciałbym je wyświetlić w notatniku Jupyter.
Robię coś takiego:
display(df1)
display(df2)
Pokazuje je jeden pod drugim:
Chciałbym mieć drugą ramkę danych po prawej stronie pierwszej. Jest podobne pytanie , ale wygląda na to, że ktoś jest zadowolony z połączenia ich w jedną ramkę danych, aby pokazać różnicę między nimi.
To nie zadziała dla mnie. W moim przypadku ramki danych mogą reprezentować zupełnie inne (nieporównywalne elementy), a ich rozmiar może być inny. Dlatego moim głównym celem jest oszczędność miejsca.
pandas
ipython-notebook
jupyter-notebook
Salvador Dali
źródło
źródło
Odpowiedzi:
Możesz zastąpić CSS kodu wyjściowego. Używa
flex-direction: column
domyślnie. Spróbuj zmienić to narow
. Oto przykład:import pandas as pd import numpy as np from IPython.display import display, HTML CSS = """ .output { flex-direction: row; } """ HTML('<style>{}</style>'.format(CSS))
Możesz oczywiście dalej dostosować CSS, jak chcesz.
Jeśli chcesz kierować tylko dane wyjściowe jednej komórki, spróbuj użyć
:nth-child()
selektora. Na przykład ten kod zmodyfikuje CSS danych wyjściowych tylko piątej komórki w notatniku:CSS = """ div.cell:nth-child(5) .output { flex-direction: row; } """
źródło
HTML('<style>{}</style>'.format(CSS))
jest ostatnią linią w komórce (i nie zapomnij użyć selektora nth-child). Może to jednak powodować problemy z formatowaniem, więc rozwiązanie jest lepsze. (+1)HTML('<style>.output {flex-direction: row;}</style>')
dla uproszczeniaSkończyło się na napisaniu funkcji, która może to zrobić:
from IPython.display import display_html def display_side_by_side(*args): html_str='' for df in args: html_str+=df.to_html() display_html(html_str.replace('table','table style="display:inline"'),raw=True)
Przykładowe użycie:
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)
źródło
*args
zamiast po prostudf
? Czy to dlatego, że możesz mieć wiele danych wejściowych*args
? 2) Która część twojej funkcji powoduje, że druga i kolejne df są dodawane po prawej stronie pierwszej zamiast poniżej niej? Czy to ta'table style="display:inline"'
część? Jeszcze raz dziękujęStyler
s,DataFrame
a nie s. W takim przypadku użyjhtml_str+=df.render()
zamiasthtml_str+=df.to_html()
.Począwszy od
pandas 0.17.1
wizualizacji DataFrames można bezpośrednio modyfikować metodami stylizacji pandAby wyświetlić dwie ramki DataFrame obok siebie, należy użyć
set_table_attributes
argumentu"style='display:inline'"
zgodnie z sugestią zawartą w odpowiedzi ntg . To zwróci dwaStyler
obiekty. Aby wyświetlić wyrównane ramki danych, po prostu przekaż ich połączoną reprezentację HTML za pomocądisplay_html
metody z IPython.Dzięki tej metodzie łatwiej jest też dodać inne opcje stylizacji. Oto jak dodać podpis, zgodnie z wnioskiem o :
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)
źródło
Łącząc podejście gibbone (do ustawiania stylów i podpisów) i stevi (dodawania spacji) stworzyłem moją wersję funkcji, która generuje ramki danych pandy jako tabele obok siebie:
from IPython.core.display import display, HTML def display_side_by_side(dfs:list, captions:list): """Display tables side by side to save vertical space Input: dfs: list of pandas.DataFrame captions: list of table captions """ output = "" combined = dict(zip(captions, dfs)) for caption, df in combined.items(): output += df.style.set_table_attributes("style='display:inline'").set_caption(caption)._repr_html_() output += "\xa0\xa0\xa0" display(HTML(output))
Stosowanie:
display_side_by_side([df1, df2, df3], ['caption1', 'caption2', 'caption3'])
Wynik:
źródło
Oto rozwiązanie Jake'a Vanderplasa, na które natknąłem się niedawno:
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)
Kredyt: https://github.com/jakevdp/PythonDataScienceHandbook/blob/master/notebooks/03.08-Aggregation-and-Grouping.ipynb
źródło
Moje rozwiązanie po prostu buduje tabelę w HTML bez żadnych hacków CSS i wyświetla ją:
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)
źródło
To dodaje nagłówki do odpowiedzi @ nts:
from IPython.display import display_html def mydisplay(dfs, names=[]): html_str = '' if names: html_str += ('<tr>' + ''.join(f'<td style="text-align:center">{name}</td>' for name in names) + '</tr>') html_str += ('<tr>' + ''.join(f'<td style="vertical-align:top"> {df.to_html(index=False)}</td>' for df in dfs) + '</tr>') html_str = f'<table>{html_str}</table>' html_str = html_str.replace('table','table style="display:inline"') display_html(html_str, raw=True)
źródło
mydisplay((df1,df2))
tylko podajedf.to_html(index=False) df.to_html(index=False)
zamiast zawartości ramki danych. Ponadto na f'string znajduje się dodatkowy znak '}'.Skończyło się na HBOX
import ipywidgets as ipyw def get_html_table(target_df, title): df_style = target_df.style.set_table_attributes("style='border:2px solid;font-size:10px;margin:10px'").set_caption(title) return df_style._repr_html_() df_2_html_table = get_html_table(df_2, 'Data from Google Sheet') df_4_html_table = get_html_table(df_4, 'Data from Jira') ipyw.HBox((ipyw.HTML(df_2_html_table),ipyw.HTML(df_4_html_table)))
źródło
Odpowiedź Gibbone'a zadziałała dla mnie! Jeśli chcesz uzyskać dodatkową przestrzeń między tabelami, przejdź do zaproponowanego przez niego kodu i dodaj go
"\xa0\xa0\xa0"
do poniższej linii kodu.display_html(df1_styler._repr_html_()+"\xa0\xa0\xa0"+df2_styler._repr_html_(), raw=True)
źródło
Postanowiłem dodać dodatkową funkcjonalność do eleganckiej odpowiedzi Yasin, w której można wybrać zarówno liczbę kolumn, jak i wierszy; wszelkie dodatkowe pliki df są następnie dodawane na dole. Dodatkowo można wybrać kolejność wypełniania siatki (po prostu zmień słowo kluczowe fill na „cols” lub „rowery” w zależności od potrzeb)
import pandas as pd from IPython.display import display,HTML def grid_df_display(list_dfs, rows = 2, cols=3, fill = 'cols'): 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[:rows*cols] ] cells += cols * [html_cell.format(content="")] # pad if fill == 'rows': #fill in rows first (first row: 0,1,2,... col-1) grid = [ html_row.format(content="".join(cells[i:i+cols])) for i in range(0,rows*cols,cols)] if fill == 'cols': #fill columns first (first column: 0,1,2,..., rows-1) grid = [ html_row.format(content="".join(cells[i:rows*cols:rows])) for i in range(0,rows)] display(HTML(html_table.format(content="".join(grid)))) #add extra dfs to bottom [display(list_dfs[i]) for i in range(rows*cols,len(list_dfs))] list_dfs = [] list_dfs.extend((pd.DataFrame(2*[{"x":"hello"}]), pd.DataFrame(2*[{"x":"world"}]), pd.DataFrame(2*[{"x":"gdbye"}]))) grid_df_display(3*list_dfs)
wyjście testowe
źródło
Kod @zarak jest dość mały, ale wpływa na układ całego notatnika. Inne opcje są dla mnie nieco kłopotliwe.
Dodałem do tej odpowiedzi kilka wyraźnych CSS wpływających tylko na bieżące wyjście komórki. Możesz także dodać cokolwiek poniżej lub powyżej ramek danych.
from ipywidgets import widgets, Layout from IPython import display import pandas as pd import numpy as np # sample data df1 = pd.DataFrame(np.random.randn(8, 3)) df2 = pd.DataFrame(np.random.randn(8, 3)) # create output widgets widget1 = widgets.Output() widget2 = widgets.Output() # render in output widgets with widget1: display.display(df1.style.set_caption('First dataframe')) df1.info() with widget2: display.display(df2.style.set_caption('Second dataframe')) df1.info() # add some CSS styles to distribute free space box_layout = Layout(display='flex', flex_flow='row', justify_content='space-around', width='auto' ) # create Horisontal Box container hbox = widgets.HBox([widget1, widget2], layout=box_layout) # render hbox hbox
źródło
Rozszerzenie odpowiedzi Antoniego Jeśli chcesz ograniczyć de wizualizację tabel do pewnej liczby bloków w wierszu, użyj zmiennej maxTables.
def mydisplay(dfs, names=[]): count = 0 maxTables = 6 if not names: names = [x for x in range(len(dfs))] html_str = '' html_th = '' html_td = '' for df, name in zip(dfs, names): if count <= (maxTables): html_th += (''.join(f'<th style="text-align:center">{name}</th>')) html_td += (''.join(f'<td style="vertical-align:top"> {df.to_html(index=False)}</td>')) count += 1 else: html_str += f'<tr>{html_th}</tr><tr>{html_td}</tr>' html_th = f'<th style="text-align:center">{name}</th>' html_td = f'<td style="vertical-align:top"> {df.to_html(index=False)}</td>' count = 0 if count != 0: html_str += f'<tr>{html_th}</tr><tr>{html_td}</tr>' html_str += f'<table>{html_str}</table>' html_str = html_str.replace('table','table style="display:inline"') display_html(html_str, raw=True)
źródło