Есть несколько вопросов.
- Изображение, полученное с помощью
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()

Как видите, результат все еще не идеален (например,л в «значениях» немного толще).В целом, гораздо лучшим решением может быть вовсе не помещать изображение внутри осей, а использовать 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()
