«Неровный» вывод из точечного файла - PullRequest
0 голосов
/ 31 января 2019

Я пытался вставить граф .dot из дерева решений sklearn в подплот Pyplot, и изо всех сил пытался это сделать.Библиотека pygraphviz отказывается работать в моей системе Windows, поэтому я использовал следующее для вставки изображений:

from subprocess import check_call
from PIL import Image
import matplotlib.pyplot as plt 

gridSpec = fig.add_gridspec(3, 2)
treeSubPlot = plt.subplot(gridSpec.new_subplotspec((2, 1)))
treeSubPlot.tick_params(axis = "both", which = "both", bottom = False, top = False, labelbottom = False, right = False, left = False, labelleft = False)
treeSubPlot.set_xlabel("Final model")

# Obtain the size of a single plot in inches to inform the dot picture creator.
height = treeSubPlot.get_window_extent().y1 - treeSubPlot.get_window_extent().y0
width = treeSubPlot.get_window_extent().x1 - treeSubPlot.get_window_extent().x0

check_call(['dot','-Tpng', "-Gsize=" + str(width/100) + "," + str(height/100) + "!", "-Gdpi=100", "-Gratio=fill", 'random_tree.dot','-o','random.png'])
randImg = Image.open("random.png")
treeSubplot.imshow(randImg, aspect = "auto")

С файлом .dot:

digraph Tree {
node [shape=box] ;
0 [label="B field <= 332.72\nsamples = 19\nvalue = 0.41"] ;
1 [label="samples = 11\nvalue = 0.67"] ;
0 -> 1 [labeldistance=2.5, labelangle=45, headlabel="True"] ;
2 [label="B field <= 576.73\nsamples = 8\nvalue = 0.04"] ;
0 -> 2 [labeldistance=2.5, labelangle=-45, headlabel="False"] ;
3 [label="samples = 4\nvalue = 0.05"] ;
2 -> 3 ;
4 [label="samples = 4\nvalue = 0.03"] ;
2 -> 4 ;
}

Какие результатыэто сюжет, но он выглядит крайне «неровным», из-за отсутствия лучшего термина: Resulting subplot

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

1 Ответ

0 голосов
/ 31 января 2019

Есть несколько вопросов.

  • Изображение, полученное с помощью dot, на самом деле не является точным размером, указанным в параметре -Gsize={},{}!.
  • Есть ошибки округления, поскольку оси matplotlib расположены на относительном рисункекоординаты и те, которые позже, не точно совпадают с целочисленными позициями пикселей.
  • Наконец, оси, на которых показано изображение, чрезвычайно малы, поэтому вышеупомянутые эффекты становятся еще более выраженными.

Решение, которое можно найти, - найти приблизительный размер осей, вызвать программу dot и извлечь из нее изображение.Затем установите фактический размер осей в соответствии с фактическим размером изображения (это может сместить оси на несколько пикселей по сравнению с их исходным положением).В приведенном ниже коде я взял большие оси.Также обратите внимание, что более высокое значение dpi или размер рисунка увеличат читабельность.

import numpy as np
from subprocess import check_call
from PIL import Image
import matplotlib.pyplot as plt
import matplotlib.transforms as mtrans

dpi = 100
fig = plt.figure(dpi=dpi)
gridSpec = fig.add_gridspec(3, 2)
ax = plt.subplot(gridSpec.new_subplotspec((2, 1)))
#ax = fig.add_subplot(111)

ax.tick_params(axis = "both", which = "both", bottom = False, top = False, 
                        labelbottom = False, right = False, left = False, labelleft = False)
ax.set_xlabel("Final model")

# calculate nominal size supplied to `dot`
ext = ax.get_position().transformed(fig.transFigure).extents
bbox = mtrans.Bbox.from_extents(np.array(ext).astype(int))

height = bbox.height
width = bbox.width

# get image from dot
check_call(['dot','-Tpng', "-Gsize={},{}!".format(width/100, height/100),
            "-Gdpi={}".format(100), "-Gratio=fill", 'random_tree.dot','-o','random.png'])
randImg = np.array(Image.open("random.png"))

# get ACTUAL size from produced image
aheight, awidth, _ = randImg.shape

# create new bounding box from actual size
abbox = mtrans.Bbox.from_bounds(bbox.x0, bbox.y0, awidth, aheight)
# transform bbox to figure coordintes
abboxf = bbox.transformed(fig.transFigure.inverted())
# Use the thus created bbox to modify the position of the axes
ax.set_position(abboxf)

# finally plot the data
ax.imshow(randImg, aspect = "auto")
# save image (this should now be correct)
plt.savefig("randomdot_mpl.png")
# show image (this might still be slightly wrong, 
#             if the GUI changes the figure size on the fly.)
plt.show()

enter image description here

Как видите, результат все еще не идеален (например,л в «значениях» немного толще).В целом, гораздо лучшим решением может быть вовсе не помещать изображение внутри осей, а использовать figimage, то есть изображение без передискретизации, помещенное внутри фигуры.Если вы все еще хотите показать оси вокруг него, вам нужно сделать оси прозрачными для «прозрачности».

Это будет выполнено с помощью следующего кода

import numpy as np
from subprocess import check_call
from PIL import Image
import matplotlib.pyplot as plt
import matplotlib.transforms as mtrans

dpi = 100
fig = plt.figure(dpi=dpi)
#gridSpec = fig.add_gridspec(3, 2)
#ax = plt.subplot(gridSpec.new_subplotspec((2, 1)))
ax = fig.add_subplot(111)

ax.tick_params(axis = "both", which = "both", bottom = False, top = False, 
                        labelbottom = False, right = False, left = False, labelleft = False)
ax.patch.set_visible(False)
ax.set_xlabel("Final model")

# calculate nominal size supplied to `dot`
ext = ax.get_position().transformed(fig.transFigure).extents
bbox = mtrans.Bbox.from_extents(np.array(ext).astype(int))

height = bbox.height
width = bbox.width

# get image from dot
check_call(['dot','-Tpng', "-Gsize={},{}!".format(width/100, height/100),
            "-Gdpi={}".format(100), "-Gratio=fill", 'random_tree.dot','-o','random.png'])
randImg = np.array(Image.open("random.png"))

# produce a figimage, i.e. a non-resampled image
fig.figimage(randImg, xo=bbox.x0, yo=bbox.y0)

# save image (this should now be perfect)
plt.savefig("randomdot_mpl.png")
# show image (this should now be perfect)
plt.show()

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...