簡體   English   中英

如何將 pandas DataFrame 表保存為 png

[英]How to save a pandas DataFrame table as a png

我構建了一個 pandas dataframe 的結果。 該數據框充當表格。 有 MultiIndexed 列,每行代表一個名稱,即創建 DataFrame 時index=['name1','name2',...] 。我想顯示此表並將其保存為 png(或任何圖形格式真的)。 目前,我能得到的最接近的是將它轉換為 html,但我想要一個 png。 看起來有人問過類似的問題,例如How to save the Pandas dataframe/series data as a figure?

但是,標記的解決方案將 dataframe 轉換為一行 plot(不是表格),而另一個解決方案依賴於 PySide,我想遠離它只是因為我不能 pip 在 linux 上安裝它。我希望這段代碼易於移植. 我真的很期待使用 python 輕松創建 png 表格。感謝所有幫助。

Pandas 允許您使用 matplotlib 繪制表格(詳情請點擊此處)。 通常這會將表格直接繪制到一個繪圖(帶有軸和所有內容)上,這不是您想要的。 但是,可以先刪除這些:

import matplotlib.pyplot as plt
import pandas as pd
from pandas.table.plotting import table # EDIT: see deprecation warnings below

ax = plt.subplot(111, frame_on=False) # no visible frame
ax.xaxis.set_visible(False)  # hide the x axis
ax.yaxis.set_visible(False)  # hide the y axis

table(ax, df)  # where df is your data frame

plt.savefig('mytable.png')

輸出可能不是最漂亮的,但您可以在此處找到 table() 函數的其他參數。 還要感謝這篇文章提供了有關如何在 matplotlib 中刪除軸的信息。


編輯:

這是使用上述方法進行繪圖時模擬多索引的一種(誠然非常hacky)的方法。 如果您有一個名為 df 的多索引數據框,如下所示:

first  second
bar    one       1.991802
       two       0.403415
baz    one      -1.024986
       two      -0.522366
foo    one       0.350297
       two      -0.444106
qux    one      -0.472536
       two       0.999393
dtype: float64

首先重置索引,使它們成為普通列

df = df.reset_index() 
df
    first second       0
0   bar    one  1.991802
1   bar    two  0.403415
2   baz    one -1.024986
3   baz    two -0.522366
4   foo    one  0.350297
5   foo    two -0.444106
6   qux    one -0.472536
7   qux    two  0.999393

通過將它們設置為空字符串來刪除高階多索引列中的所有重復項(在我的示例中,我只有在“first”中有重復索引):

df.ix[df.duplicated('first') , 'first'] = '' # see deprecation warnings below
df
  first second         0
0   bar    one  1.991802
1          two  0.403415
2   baz    one -1.024986
3          two -0.522366
4   foo    one  0.350297
5          two -0.444106
6   qux    one -0.472536
7          two  0.999393

將“索引”上的列名稱更改為空字符串

new_cols = df.columns.values
new_cols[:2] = '',''  # since my index columns are the two left-most on the table
df.columns = new_cols 

現在調用 table 函數,但將表中的所有行標簽設置為空字符串(這確保不顯示繪圖的實際索引):

table(ax, df, rowLabels=['']*df.shape[0], loc='center')

等等:

在此處輸入圖片說明

您不太漂亮但功能齊全的多索引表。

編輯:棄用警告

正如評論中所指出的, table的導入語句:

from pandas.tools.plotting import table

現在在較新版本的熊貓中已棄用,以支持:

from pandas.plotting import table 

編輯:棄用警告 2

ix索引器現已完全棄用,因此我們應該改用loc索引器。 代替:

df.ix[df.duplicated('first') , 'first'] = ''

df.loc[df.duplicated('first') , 'first'] = ''

實際上有一個叫做dataframe_image的python庫就做一個

pip install dataframe_image

做進口

import pandas as pd
import numpy as np
import dataframe_image as dfi
df = pd.DataFrame(np.random.randn(6, 6), columns=list('ABCDEF'))

如果需要,可以通過以下方式設置表格樣式:

df_styled = df.style.background_gradient() #adding a gradient based on values in cell

最后:

dfi.export(df_styled,"mytable.png")

解決您的問題的最佳解決方案可能是首先將您的數據框導出為 HTML,然后使用 HTML 到圖像工具將其轉換。 最終的外觀可以通過 CSS 進行調整。

HTML 到圖像渲染的流行選項包括:


讓我們假設我們有一個名為df的數據df 我們可以使用以下代碼生成一個:

import string
import numpy as np
import pandas as pd


np.random.seed(0)  # just to get reproducible results from `np.random`
rows, cols = 5, 10
labels = list(string.ascii_uppercase[:cols])
df = pd.DataFrame(np.random.randint(0, 100, size=(5, 10)), columns=labels)
print(df)
#     A   B   C   D   E   F   G   H   I   J
# 0  44  47  64  67  67   9  83  21  36  87
# 1  70  88  88  12  58  65  39  87  46  88
# 2  81  37  25  77  72   9  20  80  69  79
# 3  47  64  82  99  88  49  29  19  19  14
# 4  39  32  65   9  57  32  31  74  23  35

使用 Wea​​syPrint

這種方法使用pip -installable 包,它允許您使用 Python 生態系統完成所有操作。 weasyprint一個缺點是它似乎沒有提供一種使圖像大小適應其內容的方法 無論如何,從圖像中去除一些背景在 Python/PIL 中相對容易,它是在下面的trim()函數中實現的(改編自這里)。 還需要確保圖像足夠大,這可以通過 CSS 的@page size屬性來完成。

代碼如下:

import weasyprint as wsp
import PIL as pil


def trim(source_filepath, target_filepath=None, background=None):
    if not target_filepath:
        target_filepath = source_filepath
    img = pil.Image.open(source_filepath)
    if background is None:
        background = img.getpixel((0, 0))
    border = pil.Image.new(img.mode, img.size, background)
    diff = pil.ImageChops.difference(img, border)
    bbox = diff.getbbox()
    img = img.crop(bbox) if bbox else img
    img.save(target_filepath)


img_filepath = 'table1.png'
css = wsp.CSS(string='''
@page { size: 2048px 2048px; padding: 0px; margin: 0px; }
table, td, tr, th { border: 1px solid black; }
td, th { padding: 4px 8px; }
''')
html = wsp.HTML(string=df.to_html())
html.write_png(img_filepath, stylesheets=[css])
trim(img_filepath)

table_weasyprint


使用wkhtmltopdf / wkhtmltoimage

這種方法使用外部開源工具,需要在生成圖像之前安裝。 還有一個 Python 包pdfkit可以作為它的前端(它並不免除您自己安裝核心軟件的責任),但我不會使用它。

wkhtmltoimage可以使用subprocess wkhtmltoimage (或在 Python 中運行外部程序的任何其他類似方法)簡單地調用。 還需要將 HTML 文件輸出到磁盤。

代碼如下:

import subprocess


df.to_html('table2.html')
subprocess.call(
    'wkhtmltoimage -f png --width 0 table2.html table2.png', shell=True)

table_wkhtmltoimage

和其他方法類似,它的方面可以用 CSS 進一步調整。


雖然我不確定這是否是您期望的結果,但您可以通過使用帶有注釋的 Seaborn Heatmap 繪制 DataFrame 以 png 格式保存您的 DataFrame,如下所示:

http://stanford.edu/~mwaskom/software/seaborn/generated/seaborn.heatmap.html#seaborn.heatmap

帶有注釋的 Seaborn 熱圖示例

它可以立即與 Pandas Dataframe 配合使用。 你可以看看這個例子: Efficiently plotting a table in csv format using Python

您可能想要更改顏色圖,使其僅顯示白色背景。

希望這可以幫助。

@bunji 的解決方案對我有用,但默認選項並不總是能給出好的結果。 我添加了一些有用的參數來調整表格的外觀。

import pandas as pd
import matplotlib.pyplot as plt
from pandas.plotting import table
import numpy as np

dates = pd.date_range('20130101',periods=6)
df = pd.DataFrame(np.random.randn(6,4),index=dates,columns=list('ABCD'))

df.index = [item.strftime('%Y-%m-%d') for item in df.index] # Format date

fig, ax = plt.subplots(figsize=(12, 2)) # set size frame
ax.xaxis.set_visible(False)  # hide the x axis
ax.yaxis.set_visible(False)  # hide the y axis
ax.set_frame_on(False)  # no visible frame, uncomment if size is ok
tabla = table(ax, df, loc='upper right', colWidths=[0.17]*len(df.columns))  # where df is your data frame
tabla.auto_set_font_size(False) # Activate set fontsize manually
tabla.set_fontsize(12) # if ++fontsize is necessary ++colWidths
tabla.scale(1.2, 1.2) # change size table
plt.savefig('table.png', transparent=True)

結果: 桌子

我對我正在做的項目有同樣的要求。 但是沒有一個答案符合我的要求。 這是最終幫助我的東西,可能對這種情況有用:

from bokeh.io import export_png, export_svgs
from bokeh.models import ColumnDataSource, DataTable, TableColumn

def save_df_as_image(df, path):
    source = ColumnDataSource(df)
    df_columns = [df.index.name]
    df_columns.extend(df.columns.values)
    columns_for_table=[]
    for column in df_columns:
        columns_for_table.append(TableColumn(field=column, title=column))

    data_table = DataTable(source=source, columns=columns_for_table,height_policy="auto",width_policy="auto",index_position=None)
    export_png(data_table, filename = path)

在此處輸入圖片說明

如果您對在編碼環境中調用 DataFrame 時出現的格式感到滿意,那么絕對最簡單的方法是僅使用打印屏幕並使用基本圖像編輯軟件裁剪圖像。

是我使用 Jupyter Notebook 和 Pinta Image Editor(Ubuntu 免費軟件)的結果。

正如jcdoming 所建議的,使用 Seaborn heatmap heatmap()

import seaborn as sns
import matplotlib.pyplot as plt

fig = plt.figure(facecolor='w', edgecolor='k')
sns.heatmap(df.head(), annot=True, cmap='viridis', cbar=False)
plt.savefig('DataFrame.png')

DataFrame 作為熱圖

以下內容需要大量自定義才能正確設置表格格式,但它的主要內容是:

import numpy as np
from PIL import Image, ImageDraw, ImageFont
import pandas as pd

df = pd.DataFrame({ 'A' : 1.,
                     'B' : pd.Series(1,index=list(range(4)),dtype='float32'),
                     'C' : np.array([3] * 4,dtype='int32'),
                     'D' : pd.Categorical(["test","train","test","train"]),
                     'E' : 'foo' })


class DrawTable():
    def __init__(self,_df):
        self.rows,self.cols = _df.shape
        img_size = (300,200)
        self.border = 50
        self.bg_col = (255,255,255)
        self.div_w = 1
        self.div_col = (128,128,128)
        self.head_w = 2
        self.head_col = (0,0,0)
        self.image = Image.new("RGBA", img_size,self.bg_col)
        self.draw = ImageDraw.Draw(self.image)
        self.draw_grid()
        self.populate(_df)
        self.image.show()
    def draw_grid(self):
        width,height = self.image.size
        row_step = (height-self.border*2)/(self.rows)
        col_step = (width-self.border*2)/(self.cols)
        for row in range(1,self.rows+1):
            self.draw.line((self.border-row_step//2,self.border+row_step*row,width-self.border,self.border+row_step*row),fill=self.div_col,width=self.div_w)
            for col in range(1,self.cols+1):
                self.draw.line((self.border+col_step*col,self.border-col_step//2,self.border+col_step*col,height-self.border),fill=self.div_col,width=self.div_w)
        self.draw.line((self.border-row_step//2,self.border,width-self.border,self.border),fill=self.head_col,width=self.head_w)
        self.draw.line((self.border,self.border-col_step//2,self.border,height-self.border),fill=self.head_col,width=self.head_w)
        self.row_step = row_step
        self.col_step = col_step
    def populate(self,_df2):
        font = ImageFont.load_default().font
        for row in range(self.rows):
            print(_df2.iloc[row,0])
            self.draw.text((self.border-self.row_step//2,self.border+self.row_step*row),str(_df2.index[row]),font=font,fill=(0,0,128))
            for col in range(self.cols):
                text = str(_df2.iloc[row,col])
                text_w, text_h = font.getsize(text)
                x_pos = self.border+self.col_step*(col+1)-text_w
                y_pos = self.border+self.row_step*row
                self.draw.text((x_pos,y_pos),text,font=font,fill=(0,0,128))
        for col in range(self.cols):
            text = str(_df2.columns[col])
            text_w, text_h = font.getsize(text)
            x_pos = self.border+self.col_step*(col+1)-text_w
            y_pos = self.border - self.row_step//2
            self.draw.text((x_pos,y_pos),text,font=font,fill=(0,0,128))
    def save(self,filename):
        try:
            self.image.save(filename,mode='RGBA')
            print(filename," Saved.")
        except:
            print("Error saving:",filename)




table1 = DrawTable(df)
table1.save('C:/Users/user/Pictures/table1.png')

輸出如下所示:

在此處輸入圖片說明

https://pypi.org/project/df2img/ 上有一個名為df2img的 Python 庫(免責聲明:我是作者)。 這是一個使用plotly作為后端的包裝器/便利功能。

import pandas as pd

import df2img

df = pd.DataFrame(
    data=dict(
        float_col=[1.4, float("NaN"), 250, 24.65],
        str_col=("string1", "string2", float("NaN"), "string4"),
    ),
    index=["row1", "row2", "row3", "row4"],
)

pd.DataFrame保存為 .png 文件可以很快完成。 您可以應用格式,例如背景顏色或交替行顏色以提高可讀性。

fig = df2img.plot_dataframe(
    df,
    title=dict(
        font_color="darkred",
        font_family="Times New Roman",
        font_size=16,
        text="This is a title",
    ),
    tbl_header=dict(
        align="right",
        fill_color="blue",
        font_color="white",
        font_size=10,
        line_color="darkslategray",
    ),
    tbl_cells=dict(
        align="right",
        line_color="darkslategray",
    ),
    row_fill_color=("#ffffff", "#d7d8d6"),
    fig_size=(300, 160),
)

df2img.save_dataframe(fig=fig, filename="plot.png")

pd.DataFrame png 文件

使用 Anaconda Spyder IDE 將 Pandas 數據框轉換為 png 圖像的最簡單、最快捷的方法 - 只需在變量資源管理器中雙擊數據框,IDE 表就會出現,並帶有自動格式化和配色方案。 只需使用截圖工具捕獲表格以供您的報告使用,並保存為 png:

2020年藍籌比率

這為我節省了大量時間,並且仍然優雅和專業。

Plotly做數據可視化的人:

  • 您可以輕松地將 dataframe 轉換為go.Table

  • 您可以使用列名保存 dataframe。

  • 您可以格式化 dataframe 到go.Table

  • 您可以將 dataframe 保存為具有不同比例和高分辨率的 pdf、jpg 或 png。

     import plotly.express as px df = px.data.medals_long() fig = go.Figure(data=[ go.Table( header=dict(values=list(df.columns),align='center'), cells=dict(values=df.values.transpose(), fill_color = [["white","lightgrey"]*df.shape[0]], align='center' ) ) ]) fig.write_image('image.png',scale=6)

注意:圖像下載在當前 python 文件運行的同一目錄中。

Output:

在此處輸入圖像描述

我真的很喜歡 Jupyter 筆記本格式化 DataFrame 的方式,這個庫以相同的格式導出它:

import dataframe_image as dfi
dfi.export(df, "df.png")

如果您想提高圖像質量,還有一個 dpi 參數。 我建議 300 表示質量還行,600 表示出色,1200 表示完美,超過這個值可能太多了。

import dataframe_image as dfi
dfi.export(df, "df.png", dpi = 600)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM