Блокнот Юпітера відображає дві таблиці панд поряд


94

У мене є дві фрейми даних панд, і я хотів би відобразити їх у блокноті Юпітера.

Робимо щось на зразок:

display(df1)
display(df2)

Показує їх один під одним:

введіть тут опис зображення

Я хотів би мати другий фрейм даних праворуч від першого. Є подібне запитання , але схоже, що людина задоволена або злиттям їх в одному кадрі даних, щоб показати різницю між ними.

Це для мене не спрацює. У моєму випадку фрейми даних можуть представляти абсолютно різні (непорівнянні елементи), і їх розмір може бути різним. Таким чином, моя головна мета - заощадити простір.


Я опублікував рішення Джейка Вандерпласа. Хороший чистий код.
Рядовий

Відповіді:


85

Ви можете замінити 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;
}
"""

5
Це рішення впливає на всі клітини. Як я можу зробити це лише для однієї клітини?
jrovegno

2
@jrovegno Я оновив свою відповідь, включивши інформацію, яку ви вимагали.
zarak

1
@ntg Вам потрібно переконатися, що рядок HTML('<style>{}</style>'.format(CSS))є останнім рядком у комірці (і не забудьте скористатися селектором n-потомка). Однак це може спричинити проблеми з форматуванням, тому ваше рішення буде кращим. (+1)
zarak

1
@zarak Подяка за добрі слова :) У своєму рішенні ви можете мати display (HTML ('<style> {} </style>' .format (CSS))) замість HTML ('<style> {} </ style> '. format (CSS)). Тоді це може бути в будь-якому місці. У мене все ще була проблема з n-ю клітинкою (мається на увазі, якщо я скопіюю вставку, n може змінитися)
ntg

4
HTML('<style>.output {flex-direction: row;}</style>')для простоти
Томас Метью

114

У підсумку я написав функцію, яка може це зробити:

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)

введіть тут опис зображення


Це справді чудово, дякую. Як ви думаєте, наскільки легко чи інакше було б додати назву кадру даних над кожним результатом?
Рікі Макмастер,

1
Було б дві проблеми: 1. знання імен фреймів даних виходить за рамки imho stackoverflow.com/questions/2749796/…, але може зробити stackoverflow.com/questions/218616/… , або передавати їх як параметри) 2. Ви потрібен додатковий html та його відкритий кінець / до вас, що робити ... ось базовий приклад того, як може виглядати ця частина: i.stack.imgur.com/mIVsD.png
ntg

Дякую за вашу відповідь, я додав до неї заголовки таким чином, як ви описали у вашому останньому коментарі.
Antony Hatchkins

Дивовижна відповідь. Це те, що я теж шукаю. Я все ще вивчаю свій шлях, тому хочу знати: 1) Чому ти використовував *argsзамість просто df? Це тому, що ви можете мати кілька входів *args? 2) Яку частину вашої функції робить 2-ю та наступні df доданими праворуч від першої замість неї? Це 'table style="display:inline"'частина? Ще раз спасибі
Боуен Лю

1
Дякуємо за ваше чудове рішення! Якщо ви хочете стилізувати свої кадри даних перед їх відображенням, введенням буде Stylers, а не DataFrames. У цьому випадку використовуйте html_str+=df.render()замість html_str+=df.to_html().
Мартін Беккер,

35

Починаючи з pandas 0.17.1візуалізації DataFrames можна безпосередньо модифікувати за допомогою методів стилювання панд

Щоб відобразити два 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)

вирівняні фрейми даних стилів панд із написом


15

Поєднуючи підходи gibone (для встановлення стилів та підписів) та 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'])

Вихід:

введіть тут опис зображення


11

Ось рішення Джейка Вандерпласа, з яким я зіткнувся днями:

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


1
не могли б ви пояснити цю відповідь. Джейк ВандерПлас не пояснив це на своєму веб-сайті. Це єдине рішення, яке друкує ім’я набору даних зверху.
Gaurav Singhal

Що ти хочеш знати? Що ви хочете знати?
рядовий

Це може бути опис усіх функцій / як вони працюють, як їх називають тощо ..., щоб програмісти-початківці пітони могли це зрозуміти належним чином.
Gaurav Singhal

10

Моє рішення просто створює таблицю в 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)

Вихідні дані


9

Це додає заголовки до відповіді @ 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 '.

Дещо не пов’язане, але чи можна змінити свою функцію так, щоб код для виводу комірки був прихований?
alpenmilch411

1
@ alpenmilch411 див. розширення "Приховати вхід"
Antony Hatchkins

Будь-яка ідея, як додати "max_rows" до цього?
Тіккон

2

Я закінчив використовувати 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)))

2

Відповідь Гіббоуна мені спрацювала! Якщо вам потрібен додатковий простір між таблицями, перейдіть до запропонованого ним коду та додайте його "\xa0\xa0\xa0"до наступного рядка коду.

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

2

Я вирішив додати деяку додаткову функціональність до елегантної відповіді Ясіна, де можна вибрати як кількість колів, так і рядків; будь-які зайві dfs потім додаються внизу. Крім того, можна вибрати, в якому порядку заповнювати сітку (просто змініть ключове слово fill на 'cols' або 'рядки', якщо потрібно)

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)

тестовий результат


0

Розширення відповіді antony Якщо ви хочете обмежити візуалізацію таблиць деяким числом блоків за рядком, використовуйте змінну 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)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.