如何将Pandas数据框/系列数据保存为图形?

51

听起来有些奇怪,但我需要将Pandas控制台输出的字符串保存为PNG图片。例如:

>>> df
                   sales  net_pft     ROE    ROIC
STK_ID RPT_Date                                  
600809 20120331  22.1401   4.9253  0.1651  0.6656
       20120630  38.1565   7.8684  0.2567  1.0385
       20120930  52.5098  12.4338  0.3587  1.2867
       20121231  64.7876  13.2731  0.3736  1.2205
       20130331  27.9517   7.5182  0.1745  0.3723
       20130630  40.6460   9.8572  0.2560  0.4290
       20130930  53.0501  11.8605  0.2927  0.4369 

有没有类似 df.output_as_png(filename='df_data.png') 这样的方法可以生成一张图片文件,将上面的内容显示在图片里面?


请参见此答案的第二部分:https://dev59.com/xmkw5IYBdhLWcg3wBV7j#10195347目前还没有像“df.plot(how ='table')”这样简单的方法。 - Rutger Kassies
1
@bigbug,你能发布答案并标记为已解决吗? - gabra
这可能是相同的问题,但我有点不清楚。https://dev59.com/Y2Af5IYBdhLWcg3wgy4Y - Keith
1
请查看此问题 https://dev59.com/xFsV5IYBdhLWcg3w6yYh,但不要看接受的答案,而是看其他一些答案,特别是 https://dev59.com/xFsV5IYBdhLWcg3w6yYh#63387275 - Joseph
7个回答

67

选项1:使用matplotlib表格功能,加上一些额外的样式:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

df = pd.DataFrame()
df['date'] = ['2016-04-01', '2016-04-02', '2016-04-03']
df['calories'] = [2200, 2100, 1500]
df['sleep hours'] = [8, 7.5, 8.2]
df['gym'] = [True, False, False]

def render_mpl_table(data, col_width=3.0, row_height=0.625, font_size=14,
                     header_color='#40466e', row_colors=['#f1f1f2', 'w'], edge_color='w',
                     bbox=[0, 0, 1, 1], header_columns=0,
                     ax=None, **kwargs):
    if ax is None:
        size = (np.array(data.shape[::-1]) + np.array([0, 1])) * np.array([col_width, row_height])
        fig, ax = plt.subplots(figsize=size)
        ax.axis('off')
    mpl_table = ax.table(cellText=data.values, bbox=bbox, colLabels=data.columns, **kwargs)
    mpl_table.auto_set_font_size(False)
    mpl_table.set_fontsize(font_size)

    for k, cell in mpl_table._cells.items():
        cell.set_edgecolor(edge_color)
        if k[0] == 0 or k[1] < header_columns:
            cell.set_text_props(weight='bold', color='w')
            cell.set_facecolor(header_color)
        else:
            cell.set_facecolor(row_colors[k[0]%len(row_colors) ])
    return ax.get_figure(), ax

fig,ax = render_mpl_table(df, header_columns=0, col_width=2.0)
fig.savefig("table_mpl.png")

enter image description here

选项2 使用Plotly + kaleido

import plotly.figure_factory as ff
import pandas as pd

df = pd.DataFrame()
df['date'] = ['2016-04-01', '2016-04-02', '2016-04-03']
df['calories'] = [2200, 2100, 1500]
df['sleep hours'] = [8, 7.5, 8.2]
df['gym'] = [True, False, False]

fig =  ff.create_table(df)
fig.update_layout(
    autosize=False,
    width=500,
    height=200,
)
fig.write_image("table_plotly.png", scale=2)
fig.show()

在此输入图片描述

对于上述内容,可以使用font属性更改字体大小

fig.update_layout(
    autosize=False,
    width=500,
    height=200,
    font={'size':8}
)

2
你的代码对我非常有效,谢谢。你能否添加一些方法来更改一列的宽度 - 例如,我在最左边的列中有很长的“标签”字符串,希望它比其他列更宽。 - Robert
你需要做的就是改变代码中 size 数组的方式。 - volodymyr
嗨@volodymyr,感谢您的卓越建议。请问如何将标题文本旋转40度或90度? - mpx

39

您必须使用由 DataFrame.plot() 命令返回的图形:

ax = df.plot()
fig = ax.get_figure()
fig.savefig('asdf.png')

27
OP似乎对保留表格描述更感兴趣,而不是绘图。 - ivotron
1
使用Python 3.x,这会返回“'numpy.ndarray'对象没有属性'get_figure'”。 - Pat
在我看来,这个答案应该被接受。@Pat: 因为这个问题是关于 Pandas 而不是 NumPy,所以它可以在 Python 3.X 中使用 Pandas - strpeter
@strpeter:它只适用于单个图。如果您有子图,Pandas绘图将返回一个数字数组。要获取包含所有子图的单个图的句柄,请执行以下操作:import matplotlib.pyplot as plt; fig=plt.gcf() - germ

8

我想把我的数据框保存为一张表格,作为报告附录的一部分。我发现这是最简单的解决方案:

import pandas as pd
from matplotlib.backends.backend_pdf import PdfPages
import matplotlib.pyplot as plt

# Assuming that you have a dataframe, df
pp = PdfPages('Appendix_A.pdf')
total_rows, total_cols = df.shape; #There were 3 columns in my df

rows_per_page = 40; # Assign a page cut off length
rows_printed = 0
page_number = 1;

while (total_rows >0): 
    #put the table on a correctly sized figure    
    fig=plt.figure(figsize=(8.5, 11))
    plt.gca().axis('off')
    matplotlib_tab = pd.tools.plotting.table(plt.gca(),df.iloc[rows_printed:rows_printed+rows_per_page], 
        loc='upper center', colWidths=[0.2, 0.2, 0.2])    

    # Give you cells some styling 
    table_props=matplotlib_tab.properties()
    table_cells=table_props['child_artists'] # I have no clue why child_artists works
    for cell in table_cells:
        cell.set_height(0.024)
        cell.set_fontsize(12)

    # Add a header and footer with page number 
    fig.text(4.25/8.5, 10.5/11., "Appendix A", ha='center', fontsize=12)
    fig.text(4.25/8.5, 0.5/11., 'A'+str(page_number), ha='center', fontsize=12)

    pp.savefig()
    plt.close()

    #Update variables
    rows_printed += rows_per_page;
    total_rows -= rows_per_page;
    page_number+=1;

pp.close()

6

我在做一个项目时也有同样的要求,但是没有一个答案符合我的需求。这是最终帮助到我的东西,可能对这种情况有用,使用 Bokeh:

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)

示例输出:

输入图像描述


3
这里提供一种有点投机取巧的解决方案,但它可以完成任务。
import numpy as np
import pandas as pd
from matplotlib.backends.backend_pdf import PdfPages
import matplotlib.pyplot as plt

from PySide.QtGui import QImage
from PySide.QtGui import QPainter
from PySide.QtCore import QSize
from PySide.QtWebKit import QWebPage

arrays = [np.hstack([ ['one']*3, ['two']*3]), ['Dog', 'Bird', 'Cat']*2]
columns = pd.MultiIndex.from_arrays(arrays, names=['foo', 'bar'])
df =pd.DataFrame(np.zeros((3,6)),columns=columns,index=pd.date_range('20000103',periods=3))

h = "<!DOCTYPE html> <html> <body> <p> " + df.to_html() + " </p> </body> </html>";
page = QWebPage()
page.setViewportSize(QSize(5000,5000))

frame = page.mainFrame()
frame.setHtml(h, "text/html")

img = QImage(1000,700, QImage.Format(5))
painter = QPainter(img)
frame.render(painter)
painter.end()
a = img.save("html.png")

0
你可以尝试将这个df保存为pdf格式,这种情况下可以使用reportlab Table来完成任务。

0

你也可以使用Dask从RAM中卸载工作负载,它可以与Pandas数据框架、Numpy、Sklearn和ML一起使用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接