Máy tính xách tay Jupyter hiển thị hai bảng gấu trúc cạnh nhau


94

Tôi có hai khung dữ liệu gấu trúc và tôi muốn hiển thị chúng trong sổ ghi chép Jupyter.

Làm điều gì đó như:

display(df1)
display(df2)

Hiển thị chúng bên dưới cái khác:

nhập mô tả hình ảnh ở đây

Tôi muốn có khung dữ liệu thứ hai ở bên phải khung đầu tiên. Có một câu hỏi tương tự , nhưng có vẻ như có một người hài lòng với việc hợp nhất chúng trong một khung dữ liệu để hiển thị sự khác biệt giữa chúng.

Điều này sẽ không làm việc cho tôi. Trong trường hợp của tôi, các khung dữ liệu có thể đại diện hoàn toàn khác nhau (các phần tử không thể so sánh) và kích thước của chúng có thể khác nhau. Vì vậy, mục tiêu chính của tôi là tiết kiệm không gian.


Tôi đã đăng giải pháp của Jake Vanderplas. Sạch đẹp mã.
Riêng tư

Câu trả lời:


85

Bạn có thể ghi đè CSS của mã đầu ra. Nó sử dụng flex-direction: columntheo mặc định. Hãy thử thay đổi nó thành rowthay thế. Đây là một ví dụ:

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

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

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

Hình ảnh Jupyter

Tất nhiên, bạn có thể tùy chỉnh CSS hơn nữa nếu bạn muốn.

Nếu bạn chỉ muốn nhắm mục tiêu đầu ra của một ô, hãy thử sử dụng :nth-child()bộ chọn. Ví dụ: mã này sẽ sửa đổi CSS của đầu ra chỉ ô thứ 5 trong sổ ghi chép:

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

5
Giải pháp này ảnh hưởng đến tất cả các ô, Làm cách nào tôi có thể thực hiện việc này chỉ cho một ô?
jrovegno

2
@jrovegno Tôi đã cập nhật câu trả lời của mình để bao gồm thông tin bạn yêu cầu.
zarak

1
@ntg Bạn cần đảm bảo rằng dòng HTML('<style>{}</style>'.format(CSS)) là cuối cùng trong ô (và đừng quên sử dụng bộ chọn con thứ n). Tuy nhiên, điều này có thể gây ra sự cố với định dạng, vì vậy giải pháp của bạn tốt hơn. (+1)
zarak

1
@zarak Thanx cho những lời tử tế :) Trong giải pháp của bạn, bạn có thể có hiển thị (HTML ('<style> {} </style>' .format (CSS))) thay vì HTML ('<style> {} </ style> '. format (CSS)). Sau đó, nó có thể ở bất kỳ nơi nào. Tôi vẫn gặp sự cố với ô thứ n (nghĩa là, nếu tôi sao chép dán, n có thể thay đổi)
NTG

4
HTML('<style>.output {flex-direction: row;}</style>')vì lợi ích đơn giản
Thomas Matthew

114

Tôi đã viết một hàm có thể thực hiện việc này:

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)

Ví dụ sử dụng:

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)

nhập mô tả hình ảnh ở đây


Điều này thực sự tuyệt vời, cảm ơn. Bạn có nghĩ rằng việc thêm tên khung dữ liệu phía trên mỗi đầu ra sẽ dễ dàng hay cách khác sẽ dễ dàng như thế nào?
Ricky McMaster

1
Sẽ có hai vấn đề: 1. biết tên của các khung dữ liệu nằm ngoài phạm vi imho stackoverflow.com/questions/2749796/… nhưng có thể thực hiện stackoverflow.com/questions/218616/… hoặc chuyển chúng dưới dạng tham số) 2. Bạn sẽ cần thêm html và nó kết thúc mở / tùy thuộc vào bạn phải làm gì ... đây là một ví dụ cơ bản của phần này có thể nhìn như thế nào: i.stack.imgur.com/mIVsD.png
NTG

Cảm ơn câu trả lời của bạn, tôi đã thêm tiêu đề vào nó theo cách tương tự như những gì bạn đã mô tả trong nhận xét cuối cùng của mình.
Antony Hatchkins

Câu trả lời tuyệt vời. Đây cũng là những gì tôi đang tìm kiếm. Tôi vẫn đang học theo cách của mình, vì vậy tôi muốn biết: 1) Tại sao bạn sử dụng *argsthay vì chỉ df? Có phải vì bạn có thể có nhiều đầu vào với *args? 2) Phần nào trong hàm của bạn làm cho df thứ 2 và tiếp theo thêm vào bên phải của cái đầu tiên thay vì bên dưới nó? Nó là 'table style="display:inline"'một phần? Cảm ơn một lần nữa
Bowen Liu

1
Cảm ơn cho giải pháp tuyệt vời của bạn! Nếu bạn muốn tạo kiểu cho các khung dữ liệu của mình trước khi hiển thị chúng, đầu vào sẽ là Stylers chứ không phải DataFrames. Trong trường hợp này, hãy sử dụng html_str+=df.render()thay vì html_str+=df.to_html().
Martin Becker

35

Bắt đầu từ pandas 0.17.1việc trực quan hóa DataFrames có thể được sửa đổi trực tiếp bằng các phương pháp tạo kiểu gấu trúc

Để hiển thị hai DataFrames cạnh nhau, bạn phải sử dụng set_table_attributesđối số "style='display:inline'"như được đề xuất trong câu trả lời ntg . Điều này sẽ trả về hai Stylerđối tượng. Để hiển thị các khung dữ liệu được căn chỉnh, chỉ cần chuyển biểu diễn HTML đã kết hợp của chúng thông quadisplay_html phương thức từ IPython.

Với phương pháp này cũng dễ dàng hơn để thêm các tùy chọn tạo kiểu khác. Đây là cách thêm chú thích, theo yêu cầu ở đây :

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)

căn chỉnh dữ liệu khung hình gấu trúc với chú thích


15

Kết hợp các phương pháp tiếp cận gibbone (để đặt kiểu và chú thích) và stevi (thêm không gian), tôi đã tạo phiên bản hàm của mình, xuất ra khung dữ liệu gấu trúc dưới dạng bảng cạnh nhau:

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

Sử dụng:

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

Đầu ra:

nhập mô tả hình ảnh ở đây


11

Đây là giải pháp của Jake Vanderplas mà tôi đã xem hôm trước:

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)

Tín dụng: https://github.com/jakevdp/PythonDataScienceHandbook/blob/master/notebooks/03.08-Aggregation-and-Grouping.ipynb


1
bạn có thể vui lòng giải thích câu trả lời này. Jake VanderPlas đã không giải thích nó trên trang web của mình. Đây là giải pháp duy nhất in tên tập dữ liệu ở trên cùng.
Gaurav Singhal

Bạn muốn biết gì?
Riêng tư

Có thể là mô tả về tất cả các chức năng / cách chúng hoạt động, cách chúng được gọi là ... để những người mới lập trình python có thể hiểu đúng về nó.
Gaurav Singhal

10

Giải pháp của tôi chỉ tạo một bảng bằng HTML mà không cần bất kỳ cuộc tấn công CSS nào và xuất ra nó:

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)

Đầu ra


9

Điều này thêm tiêu đề vào câu trả lời của @ 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)

nhập mô tả hình ảnh ở đây


Điều này có vẻ rất hữu ích, nhưng mang lại cho tôi một vấn đề. For mydisplay((df1,df2))only đưa ra df.to_html(index=False) df.to_html(index=False)thay vì nội dung khung dữ liệu. Ngoài ra, có thêm dấu '}' ở f'string '.

Hơi không liên quan nhưng có thể sửa đổi chức năng của bạn để mã cho đầu ra ô bị ẩn không?
alpenmilch411

1
@ alpenmilch411 xem phần mở rộng "Ẩn đầu vào"
Antony Hatchkins

Bất kỳ ý tưởng nào về cách thêm 'max_rows' vào điều này?
Tickon

2

Tôi đã kết thúc sử dụng 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

Câu trả lời của Gibbone phù hợp với tôi! Nếu bạn muốn có thêm khoảng trống giữa các bảng, hãy chuyển đến mã anh ta đề xuất và thêm mã này "\xa0\xa0\xa0"vào dòng mã sau.

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

2

Tôi quyết định thêm một số chức năng bổ sung vào câu trả lời thanh lịch của Yasin, nơi người ta có thể chọn cả số col và số hàng; bất kỳ dfs bổ sung nào sau đó được thêm vào dưới cùng. Ngoài ra, người ta có thể chọn thứ tự điền vào lưới (chỉ cần thay đổi từ khóa điền thành 'cols' hoặc 'row' nếu cần)

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)

kiểm tra đầu ra


0

Mở rộng câu trả lời của antony Nếu bạn muốn giới hạn việc hiển thị bảng ở một số số khối theo hàng, hãy sử dụng biến maxTables.nhập mô tả hình ảnh ở đây

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)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.