Notebook Jupyter menampilkan dua meja panda berdampingan

96

Saya memiliki dua kerangka data panda dan saya ingin menampilkannya di notebook Jupyter.

Melakukan sesuatu seperti:

display(df1)
display(df2)

Tunjukkan satu sama lain di bawah ini:

masukkan deskripsi gambar di sini

Saya ingin memiliki kerangka data kedua di sebelah kanan yang pertama. Ada pertanyaan serupa , tetapi sepertinya ada orang yang puas dengan menggabungkan mereka dalam satu kerangka data untuk menunjukkan perbedaan di antara mereka.

Ini tidak akan berhasil untuk saya. Dalam kasus saya, kerangka data dapat mewakili sama sekali berbeda (elemen yang tidak dapat dibandingkan) dan ukurannya bisa berbeda. Jadi tujuan utama saya adalah menghemat ruang.

Salvador Dali
sumber
Saya memposting solusi Jake Vanderplas. Kode bersih yang bagus.
Prajurit

Jawaban:

90

Anda dapat mengganti CSS dari kode keluaran. Ini digunakan flex-direction: columnsecara default. Coba ubah menjadi rowsebagai gantinya. Berikut contohnya:

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

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

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

Gambar jupyter

Anda dapat, tentu saja, menyesuaikan CSS sesuai keinginan Anda.

Jika Anda ingin menargetkan hanya satu keluaran sel, coba gunakan :nth-child()selektor. Misalnya, kode ini akan mengubah CSS dari output hanya sel ke-5 di notebook:

CSS = """
div.cell:nth-child(5) .output {
    flex-direction: row;
}
"""
zarak
sumber
5
Solusi ini mempengaruhi semua sel, Bagaimana saya dapat melakukan ini hanya untuk satu sel?
jrovegno
2
@jrovegno Saya memperbarui jawaban saya dengan menyertakan informasi yang Anda minta.
zarak
1
@ntg Anda perlu memastikan bahwa baris tersebut HTML('<style>{}</style>'.format(CSS))adalah baris terakhir dalam sel (dan jangan lupa untuk menggunakan pemilih anak ke-n). Namun, ini dapat menyebabkan masalah dengan pemformatan, jadi solusi Anda lebih baik. (+1)
zarak
1
@zarak Thanx untuk kata-kata baik :) Dalam solusi Anda, Anda dapat memiliki tampilan (HTML ('<style> {} </style>' .format (CSS))) daripada HTML ('<style> {} </ style> '. format (CSS)). Lalu bisa di mana saja. Saya masih memiliki masalah dengan sel ke-n (artinya, jika saya menyalin tempel, n mungkin berubah)
ntg
4
HTML('<style>.output {flex-direction: row;}</style>')demi kesederhanaan
Thomas Matthew
123

Saya akhirnya menulis fungsi yang dapat melakukan ini:

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)

Contoh penggunaan:

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)

masukkan deskripsi gambar di sini

ntg
sumber
Ini sangat bagus, terima kasih. Seberapa mudah atau sebaliknya menambahkan nama bingkai data di atas setiap keluaran, menurut Anda?
Ricky McMaster
1
Akan ada dua masalah: 1. mengetahui nama dataframe berada di luar cakupan imho stackoverflow.com/questions/2749796/… tetapi dapat melakukan stackoverflow.com/questions/218616/… , atau meneruskannya sebagai params) 2. Anda akan membutuhkan html tambahan dan terbuka / terserah Anda apa yang harus dilakukan ... berikut adalah contoh dasar bagaimana bagian ini dapat terlihat: i.stack.imgur.com/mIVsD.png
ntg
Terima kasih atas jawaban Anda, saya telah menambahkan tajuk ke dalamnya dengan cara yang mirip dengan apa yang Anda jelaskan dalam komentar terakhir Anda.
Antony Hatchkins
Jawaban yang luar biasa. Inilah yang saya cari juga. Saya masih mempelajarinya, jadi saya ingin tahu: 1) Mengapa Anda menggunakan *argsalih-alih hanya df? Apakah karena Anda dapat memiliki banyak masukan *args? 2) Bagian mana dari fungsi Anda yang membuat df ke-2 dan selanjutnya ditambahkan ke kanan yang pertama, bukan di bawahnya? Apakah itu 'table style="display:inline"'bagiannya? Terima kasih lagi
Bowen Liu
1
Terima kasih atas solusi hebat Anda! Jika Anda ingin menata dataframe Anda sebelum menampilkannya, masukannya adalah Stylers, bukan DataFrames. Dalam hal ini, menggunakan html_str+=df.render()bukan html_str+=df.to_html().
Martin Becker
37

Mulai dari pandas 0.17.1visualisasi DataFrames bisa langsung dimodifikasi dengan metode pandas styling

Untuk menampilkan dua DataFrames secara berdampingan, Anda harus menggunakan set_table_attributesargumen "style='display:inline'"seperti yang disarankan dalam jawaban ntg . Ini akan mengembalikan dua Stylerobjek. Untuk menampilkan dataframe selaras, cukup kirimkan representasi HTML mereka yang digabungkan melaluidisplay_html metode dari IPython.

Dengan metode ini juga lebih mudah untuk menambahkan opsi styling lainnya. Berikut cara menambahkan keterangan, seperti yang diminta di sini :

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)

dataframes pandas styler selaras dengan teks

tulang siam
sumber
18

Menggabungkan pendekatan gibbone (untuk mengatur gaya dan teks) dan stevi (menambahkan spasi) Saya membuat versi fungsi saya, yang mengeluarkan pandas dataframes sebagai tabel berdampingan:

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))

Pemakaian:

display_side_by_side([df1, df2, df3], ['caption1', 'caption2', 'caption3'])

Keluaran:

masukkan deskripsi gambar di sini

Anton Golubev
sumber
11

Inilah solusi Jake Vanderplas yang saya temui beberapa hari yang lalu:

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)

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

Pribadi
sumber
1
bisakah Anda menjelaskan jawaban ini. Jake VanderPlas belum menjelaskannya di situsnya. Ini adalah satu-satunya solusi yang mencetak nama kumpulan data di atas.
Gaurav Singhal
Apa yang ingin kamu ketahui?
Prajurit
Semoga bisa menjadi gambaran semua fungsi / bagaimana cara kerjanya, bagaimana mereka disebut dan sebagainya ... agar programmer newbie python dapat memahaminya dengan baik.
Gaurav Singhal
10

Solusi saya hanya membuat tabel dalam HTML tanpa peretasan CSS dan mengeluarkannya:

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)

Keluaran

Yasin Zähringer
sumber
9

Ini menambahkan header ke jawaban @ 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)

masukkan deskripsi gambar di sini

Antony Hatchkins
sumber
Ini sepertinya sangat berguna, tetapi memberi saya masalah. Untuk mydisplay((df1,df2))hanya memberi, df.to_html(index=False) df.to_html(index=False)bukan konten dataframe. Juga, ada tanda '}' ekstra di f'string '.
Agak tidak terkait tetapi apakah mungkin untuk mengubah fungsi Anda sehingga kode untuk keluaran sel disembunyikan?
alpenmilch411
1
@ alpenmilch411 lihat ekstensi "Sembunyikan Input"
Antony Hatchkins
Ada ide bagaimana menambahkan 'max_rows' ke ini?
Tickon
Ini juga kehilangan multi indeks, ketika frame data multi indeks digunakan.
Parthiban Rajendran
2

Saya akhirnya menggunakan 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)))
Dinis Cruz
sumber
2

Jawaban Gibbone berhasil untuk saya! Jika Anda ingin spasi ekstra di antara tabel, buka kode yang dia usulkan dan tambahkan ini "\xa0\xa0\xa0"ke baris kode berikut.

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

Saya memutuskan untuk menambahkan beberapa fungsionalitas ekstra pada jawaban Yasin yang elegan, di mana seseorang dapat memilih jumlah kolom dan baris; setiap df tambahan kemudian ditambahkan ke bawah. Selain itu, seseorang dapat memilih di mana urutan untuk mengisi kisi (cukup ubah kata kunci isian menjadi 'kolom' atau 'baris' sesuai kebutuhan)

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)

hasil tes

Martino Schröder
sumber
1

Kode @zarak cukup kecil tetapi memengaruhi tata letak seluruh buku catatan. Pilihan lain agak berantakan bagi saya.

Saya telah menambahkan beberapa CSS yang jelas ke jawaban ini yang hanya mempengaruhi keluaran sel saat ini. Anda juga dapat menambahkan apa pun di bawah atau di atas kerangka data.

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

masukkan deskripsi gambar di sini

MSorro
sumber
0

Perpanjangan jawaban antony Jika Anda ingin membatasi de visualisasi tabel menjadi beberapa angka blok demi baris, gunakan variabel maxTables.masukkan deskripsi gambar di sini

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)
Arzanico
sumber
Ini kehilangan multi indeks saat diterapkan pada kerangka data multi indeks
Parthiban Rajendran