У меня есть два фрейма данных pandas, и я хотел бы отобразить их в блокноте Jupyter.
Сделать что-то вроде:
display(df1)
display(df2)
Показывает их одно под другим:
Я хотел бы иметь второй фрейм данных справа от первого. Есть аналогичный вопрос , но похоже, что там человека устраивает либо объединение их в один фрейм данных, либо отображение разницы между ними.
У меня это не сработает. В моем случае фреймы данных могут представлять совершенно разные (несопоставимые элементы), и их размер может быть разным. Таким образом, моя главная цель - сэкономить место.
pandas
ipython-notebook
jupyter-notebook
Сальвадор Дали
источник
источник
Ответы:
Вы можете переопределить CSS выходного кода. Используется
flex-direction: column
по умолчанию.row
Вместо этого попробуйте изменить его на . Вот пример:import pandas as pd import numpy as np from IPython.display import display, HTML CSS = """ .output { flex-direction: row; } """ HTML('<style>{}</style>'.format(CSS))
Конечно, вы можете настроить CSS дальше по своему желанию.
Если вы хотите настроить таргетинг только на одну ячейку, попробуйте использовать
:nth-child()
селектор. Например, этот код изменит CSS вывода только 5-й ячейки записной книжки:CSS = """ div.cell:nth-child(5) .output { flex-direction: row; } """
источник
HTML('<style>{}</style>'.format(CSS))
является последней строкой в ячейке (и не забудьте использовать селектор nth-child). Однако это может вызвать проблемы с форматированием, поэтому ваше решение лучше. (+1)HTML('<style>.output {flex-direction: row;}</style>')
для простотыВ итоге я написал функцию, которая может это сделать:
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)
Пример использования:
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)
источник
*args
вместо простоdf
? Это потому, что у вас может быть несколько входов*args
? 2) Какая часть вашей функции заставляет второй и последующие df добавлять справа от первого, а не под ним? Это'table style="display:inline"'
часть? Еще раз спасибоStyler
s, а неDataFrame
s. В этом случае используйтеhtml_str+=df.render()
вместоhtml_str+=df.to_html()
.Начиная с
pandas 0.17.1
визуализации DataFrames, можно напрямую изменять методы стилизации pandas.Чтобы отобразить два DataFrames рядом, вы должны использовать
set_table_attributes
аргумент,"style='display:inline'"
как предложено в ответе ntg . Это вернет дваStyler
объекта. Чтобы отобразить выровненные фреймы данных, просто передайте их объединенное HTML-представление черезdisplay_html
метод из IPython.С помощью этого метода также проще добавить другие варианты укладки. Вот как добавить подпись, как просили здесь :
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)
источник
Комбинируя подходы gibbone (для установки стилей и подписей) и stevi (для добавления пространства), я создал свою версию функции, которая выводит фреймы данных pandas в виде таблиц рядом:
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))
Применение:
display_side_by_side([df1, df2, df3], ['caption1', 'caption2', 'caption3'])
Выход:
источник
Вот решение Джейка Вандерпласа, с которым я столкнулся буквально на днях:
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)
Кредит: https://github.com/jakevdp/PythonDataScienceHandbook/blob/master/notebooks/03.08-Aggregation-and-Grouping.ipynb
источник
Мое решение просто создает таблицу в HTML без каких-либо взломов CSS и выводит ее:
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)
источник
Это добавляет заголовки к ответу @ 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)
источник
mydisplay((df1,df2))
только даетdf.to_html(index=False) df.to_html(index=False)
вместо содержимого фрейма данных. Кроме того, в строке f'string есть дополнительный знак '}'.В итоге я использовал 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)))
источник
Ответ Гиббона сработал для меня! Если вам нужно дополнительное пространство между таблицами, перейдите к предложенному им коду и добавьте
"\xa0\xa0\xa0"
его в следующую строку кода.display_html(df1_styler._repr_html_()+"\xa0\xa0\xa0"+df2_styler._repr_html_(), raw=True)
источник
Я решил добавить некоторые дополнительные функции к элегантному ответу Ясина, где можно выбрать как количество столбцов, так и количество строк; любые дополнительные файлы dfs затем добавляются внизу. Кроме того, можно выбрать, в каком порядке заполнять сетку (просто измените ключевое слово fill на 'cols' или 'rows' по мере необходимости)
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)
тестовый вывод
источник
Код @zarak довольно мал, но влияет на макет всей записной книжки. Другие варианты для меня немного запутаны.
Я добавил к этому ответу чистый CSS, влияющий только на текущий вывод ячейки. Также вы можете добавить что-нибудь ниже или выше фреймов данных.
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
источник
Расширение ответа Антония. Если вы хотите ограничить де-визуализацию таблиц некоторым количеством блоков по строкам, используйте переменную 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)
источник