Jupyter dizüstü bilgisayar iki panda masasını yan yana görüntüler


96

İki panda veri çerçevem ​​var ve bunları Jupyter not defterinde görüntülemek istiyorum.

Şunun gibi bir şey yapmak:

display(df1)
display(df2)

Bunları birbirinin altında gösterir:

görüntü açıklamasını buraya girin

İlkinin sağında ikinci bir veri çerçevesine sahip olmak istiyorum. Orada da benzer bir soru , ama bir kişinin aralarındaki farkı gösteren bir dataframe bunları birleştirme ile ya memnun olduğunu orada gibi görünüyor.

Bu benim için işe yaramayacak. Benim durumumda, veri çerçeveleri tamamen farklı (karşılaştırılamayan öğeleri) temsil edebilir ve bunların boyutları farklı olabilir. Bu yüzden asıl amacım yerden tasarruf etmek.


Jake Vanderplas'ın çözümünü gönderdim. Güzel temiz kod.
Özel

Yanıtlar:


90

Çıktı kodunun CSS'sini geçersiz kılabilirsiniz. flex-direction: columnVarsayılan olarak kullanır . rowBunun yerine olarak değiştirmeyi deneyin . İşte bir örnek:

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 görüntüsü

Elbette CSS'yi dilediğiniz gibi özelleştirebilirsiniz.

Yalnızca bir hücrenin çıktısını hedeflemek istiyorsanız, :nth-child()seçiciyi kullanmayı deneyin . Örneğin, bu kod not defterinde yalnızca 5. hücrenin çıktısının CSS'sini değiştirir:

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

5
Bu çözüm tüm hücreleri etkiliyor, bunu sadece bir hücre için nasıl yapabilirim?
jrovegno

2
@jrovegno İstediğiniz bilgileri içerecek şekilde cevabımı güncelledim.
zarak

1
@ntg Satırın hücredeki HTML('<style>{}</style>'.format(CSS))son satır olduğundan emin olmanız gerekir (ve nth-çocuk seçiciyi kullanmayı unutmayın). Ancak bu, biçimlendirmeyle ilgili sorunlara neden olabilir, bu nedenle çözümünüz daha iyidir. (+1)
zarak

1
@zarak Thanx tür kelimeler için :) Çözümünüzde HTML ('<style> {} </) yerine display (HTML (' <style> {} </style> '.format (CSS))) olabilir stil> '. format (CSS)). O zaman herhangi bir yerde olabilir. Yine de n'inci hücrede sorun yaşadım (yani, yapıştırırsam n değişebilir)
ntg

4
HTML('<style>.output {flex-direction: row;}</style>')basitlik uğruna
Thomas Matthew

123

Bunu yapabilen bir işlev yazdım:

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)

Örnek kullanım:

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)

görüntü açıklamasını buraya girin


Bu gerçekten harika, teşekkürler. Veri çerçevesi adını her çıktının üzerine eklemek ne kadar kolay olur ya da başka türlü olur mu?
Ricky McMaster

1
Orada iki sorun olacaktır: dataframes isimlerini bilmeden 1. kapsamı imho dışında stackoverflow.com/questions/2749796/... ama yapabileceği stackoverflow.com/questions/218616/... veya 2.) params olarak geçmek fazladan html'ye ihtiyaç duyacak
ntg

Cevabınız için teşekkürler , son yorumunuzda anlattığınıza benzer bir şekilde ona başlıklar ekledim .
Antony Hatchkins

Harika cevap. Benim de aradığım şey bu. Hala kendi yolumu öğreniyorum, bu yüzden bilmek istiyorum: 1) Neden *argssadece yerine kullandın df? Birden fazla girişiniz olabileceği için *argsmi? 2) Fonksiyonunuzun hangi bölümü 2. ve sonraki df'nin altına değil de ilkinin sağına eklemesini sağlıyor? Bu 'table style="display:inline"'kısım mı? Tekrar teşekkürler
Bowen Liu

1
Harika çözümünüz için teşekkürler! Veri çerçevelerinizi görüntülemeden önce biçimlendirmek istiyorsanız, girdi Stylers olacaktır , DataFrames olacaktır. Bu durumda html_str+=df.render()yerine kullanın html_str+=df.to_html().
Martin Becker

37

pandas 0.17.1DataFrame'lerin görselleştirilmesinden başlayarak, pandaların stil verme yöntemleriyle doğrudan değiştirilebilir

İki DataFrame'i yan yana görüntülemek set_table_attributesiçin argümanla "style='display:inline'"birlikte ntg answer'da önerildiği gibi kullanmanız gerekir . Bu iki Stylernesne döndürecektir . Hizalanmış veri çerçevelerini görüntülemek için, birleştirilmiş HTML temsillerini IPython'daki display_htmlyöntem aracılığıyla iletmeniz yeterlidir .

Bu yöntemle diğer stil seçeneklerini eklemek de daha kolaydır. İşte istendiği gibi, başlık eklemek için aşağıdaki adımları burada :

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)

hizalanmış veri çerçeveleri pandalar şekillendirici ve başlık


18

Gibbone (stilleri ve başlıkları ayarlamak için) ve stevi (boşluk eklemek için) yaklaşımlarını birleştirerek, pandaların veri çerçevelerini yan yana tablolar olarak çıkaran işlev sürümümü yaptım:

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

Kullanım:

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

Çıktı:

görüntü açıklamasını buraya girin


11

İşte Jake Vanderplas'ın geçen gün karşılaştığım çözümü:

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)

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


1
lütfen bu cevabı açıklar mısın? Jake VanderPlas bunu web sitesinde açıklamadı. Bu, veri kümesi adını en üste yazdıran tek çözümdür.
Gaurav Singhal

Ne bilmek istiyorsun?
Özel

Tüm işlevlerin / nasıl çalıştıkları, nasıl böyle adlandırıldıklarının bir açıklaması olabilir, böylece acemi python programcıları bunu doğru bir şekilde anlayabilir.
Gaurav Singhal

10

Çözümüm, herhangi bir CSS hacklemesi olmadan HTML'de bir tablo oluşturuyor ve çıktılarını veriyor:

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)

Çıktı


9

Bu, @ nts yanıtına başlıklar ekler:

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)

görüntü açıklamasını buraya girin


Bu çok yararlı görünüyor, ancak bana bir sorun veriyor. İçin mydisplay((df1,df2))sadece verir df.to_html(index=False) df.to_html(index=False)yerine dataframe içeriğinin. Ayrıca, f'string'de fazladan '}' işareti vardır.

Biraz ilgisiz, ancak işlevinizi hücre çıktısının kodu gizlenecek şekilde değiştirmek mümkün müdür?
alpenmilch411

1
@ alpenmilch411 "Girişi Gizle" uzantısına bakın
Antony Hatchkins

Buna 'max_rows' nasıl ekleneceği hakkında bir fikriniz var mı?
Tickon

Bu da çoklu indeksli veri çerçeveleri kullanıldığında çoklu indisleri kaybeder.
Parthiban Rajendran

2

HBOX kullanmaya son verdim

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

Gibbone'un cevabı benim için çalıştı! Tablolar arasında fazladan boşluk istiyorsanız, önerdiği koda gidin ve bunu "\xa0\xa0\xa0"aşağıdaki kod satırına ekleyin .

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

2

Bir cols sayısını hem seçebilir Yasin'in şık cevap, bazı ekstra işlevsellik eklemeye karar ve satırlar; herhangi bir ekstra dfs daha sonra en alta eklenir. Ek olarak, ızgarayı hangi sırayla dolduracağınızı seçebilirsiniz (sadece doldurma anahtar kelimesini 'sütunlar' veya 'satırlar' olarak değiştirin)

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)

test çıktısı


1

@zarak kodu oldukça küçüktür ancak tüm dizüstü bilgisayarın düzenini etkiler. Diğer seçenekler benim için biraz karışık.

Bu yanıta yalnızca mevcut hücre çıktısını etkileyen bazı açık CSS ekledim . Ayrıca veri çerçevelerinin altına veya üstüne herhangi bir şey ekleyebilirsiniz.

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

görüntü açıklamasını buraya girin


0

Antony cevabının uzantısı Tabloların görselleştirilmesini satır bazında birkaç blokla sınırlamak istiyorsanız maxTables değişkenini kullanın.görüntü açıklamasını buraya girin

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)

Bu, çok dizine alınmış bir veri çerçevesine uygulandığında çoklu endeksleri kaybeder
Parthiban Rajendran
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.