Подтвердить что ты не робот

Как сохранить таблицу pandas DataFrame в виде png

Я построил datachrame pandas результатов. Этот фрейм данных действует как таблица. Существуют столбцы MultiIndexed, и каждая строка представляет собой имя, то есть index=['name1','name2',...] при создании DataFrame. Я бы хотел отобразить эту таблицу и сохранить ее как png (или любой графический формат). На данный момент самое близкое, что я могу получить, это преобразовать его в html, но я бы хотел png. Похоже, что были заданы аналогичные вопросы, например Как сохранить данные

Тем не менее, отмеченное решение преобразует dataframe в линейный график (а не таблицу), а другое решение опирается на PySide, который я хотел бы избегать просто потому, что я не могу установить его на linux. Я бы хотел, чтобы этот код был легко переносимым. Я действительно ожидал, что создание таблицы в png будет легко с python. Вся помощь приветствуется.

4b9b3361

Ответ 1

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.


РЕДАКТИРОВАТЬ:

Вот (по общему признанию довольно хакерский) способ симуляции мультииндексов при построении графиков с использованием метода, описанного выше. Если у вас есть многоиндексный фрейм данных с именем 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'] = ''
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(ax, df, rowLabels=['']*df.shape[0], loc='center')

и вуаля:

enter image description here

Ваша не очень красивая, но полностью функциональная многоиндексированная таблица.

РЕДАКТИРОВАТЬ: УСТАРЕВАНИЕ ПРЕДУПРЕЖДЕНИЯ

Как указано в комментариях, оператор импорта для table:

from pandas.tools.plotting import table

в новых версиях панд теперь устарела в пользу:

from pandas.plotting import table 

Ответ 2

Лучшее решение вашей проблемы возможно:

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

но вам нужно будет получить wkhtmltoimage/wkhtmltopdf самостоятельно. Существует также пакет Python, pdfkit, чтобы вы поняли это, но я не вижу большого преимущества перед запуском команды самостоятельно.

Я хотел бы, чтобы море было более настраиваемым (или, может быть, легко настроить: я просто не мог найти правильный способ украсить это за последние 30 минут).

В моем случае результаты были довольно аккуратными, например:

введите описание изображения здесь

и вы могли бы еще больше настроить CSS, если хотите.

Ответ 3

Хотя я не уверен, что это результат, которого вы ожидаете, вы можете сохранить свой DataFrame в png, построив DataFrame с Seaborn Heatmap с аннотациями, например:

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

Пример карты морского обита с аннотациями нa

Он работает сразу с Pandas Dataframe. Вы можете посмотреть на этот пример: Эффективное построение таблицы в формате csv с использованием Python

Возможно, вы захотите изменить цветовой код, чтобы он отображал только белый фон.

Надеюсь, что это поможет.

Ответ 4

Если у вас все в порядке с форматированием, которое появляется при вызове DataFrame в вашей среде кодирования, тогда самый простой способ - просто использовать экран печати и обрезать изображение с помощью основного программного обеспечения для редактирования изображений.

Вот как это оказалось для меня с помощью Jupyter Notebook и Pinta Image Editor (бесплатная версия Ubuntu).

Ответ 5

Решение @bunji работает для меня, но параметры по умолчанию не всегда дают хороший результат. Я добавил полезный параметр, чтобы настроить внешний вид таблицы.

import pandas as pd
import matplotlib.pyplot as plt
from pandas.tools.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)

Результат: Таблица

Ответ 6

Для правильной форматирования таблицы потребуется обширная настройка, но ее кости работают:

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

Результат выглядит следующим образом:

введите описание изображения здесь

Ответ 7

Как предложено 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 as a heat map