Как сохранить таблицу pandas DataFrame в виде png
Я построил datachrame pandas результатов. Этот фрейм данных действует как таблица. Существуют столбцы MultiIndexed, и каждая строка представляет собой имя, то есть index=['name1','name2',...]
при создании DataFrame. Я бы хотел отобразить эту таблицу и сохранить ее как png (или любой графический формат). На данный момент самое близкое, что я могу получить, это преобразовать его в html, но я бы хотел png. Похоже, что были заданы аналогичные вопросы, например Как сохранить данные
Тем не менее, отмеченное решение преобразует dataframe в линейный график (а не таблицу), а другое решение опирается на PySide, который я хотел бы избегать просто потому, что я не могу установить его на linux. Я бы хотел, чтобы этот код был легко переносимым. Я действительно ожидал, что создание таблицы в png будет легко с python. Вся помощь приветствуется.
Ответы
Ответ 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]()