К сожалению, для этого нет предпочтительного пути.
Некоторые более или менее сложные обходные пути приходят на ум.
A. Сделав фигуру размером с изображение, увеличьте ее, сохранив
Если цель в основном состоит в том, чтобы создать файл изображения фигуры, проще всего сделать оси графика изображения такими же большими, как фигура, а затем разрешить расширение конечного файла изображения с помощью параметра bbox_inches="tight"
.
Для этого потребуется вручную разместить цветную полосу вне фигуры.
import numpy as np
import matplotlib.pyplot as plt
#create some image, with lines every second pixel
rows = 123
cols = 456
image = np.zeros((rows,cols))
image[:, np.arange(0,image.shape[1], 2)] = 1
image[np.arange(0,image.shape[0], 2), :] = 0.5
dpi = 100
fig, ax = plt.subplots(figsize=(image.shape[1]/dpi, image.shape[0]/dpi), dpi=dpi)
fig.subplots_adjust(0,0,1,1)
im = ax.imshow(image)
cax = fig.add_axes([1.05, 0, 0.03, 1])
fig.colorbar(im, cax=cax)
fig.savefig("test.png", bbox_inches="tight")
Основным недостатком этого является то, что может привести к неправильному изображению на один пиксель. Это связано с тем, что позиции всегда находятся в координатах фигуры, что приводит к ошибкам округления при штамповке размера осей в пикселях.
например. если в приведенном выше примере выбрать dpi=69
, результат будет
Чередующиеся линии позволяют легко определить, что изображение на один пиксель слишком мало по высоте.
B. Сделайте фигуру больше, чем изображение, отрегулируйте поля
Одним из недостатков вышесказанного является то, что украшения осей и цветная полоса находятся за пределами фигуры. Чтобы они были внутри, можно определить все поля и вычислить, насколько большой должна быть конечная цифра. Это но громоздко.
import numpy as np
import matplotlib.pyplot as plt
#create some image
rows = 123
cols = 456
image = np.zeros((rows,cols))
image[:, np.arange(0,image.shape[1], 2)] = 1
image[np.arange(0,image.shape[0], 2), :] = 0.5
dpi = 100
left = right = 60
top = bottom = 40
cbarwidth = 24
wspace = 10
width = left + cols + wspace + cbarwidth + right
height = top + rows + bottom
w = width / dpi
h = height / dpi
fig, (ax, cax) = plt.subplots(ncols = 2, figsize=(w,h), dpi=dpi,
gridspec_kw=dict(width_ratios=[cols, cbarwidth]))
fig.subplots_adjust(left = left/width, right = 1-right/width,
bottom = bottom/height, top = 1-top/height,
wspace = wspace / (cols + cbarwidth))
im = ax.imshow(image)
fig.colorbar(im, cax=cax)
fig.savefig("test2.png")
Он также будет страдать от того же недостатка, что и A. , например если используются нечетные числа, такие как
dpi = 72
left = right = 59
top = bottom = 37
cbarwidth = 19
wspace = 12
C. Используйте figimage
и положите топоры сверху.
Единственный способ убедиться в отсутствии эффектов наложения - использовать figimage
. Это помещает изображение в пиксельных координатах на фигуру. Однако тогда у одного не будет никаких осей по умолчанию. @Anntzer недавно предложил решение , которое заключается в том, чтобы просто поместить оси в положение на рисунке, где figimage
равно.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.transforms import Bbox
#create some image, with lines every second pixel
rows = 123
cols = 456
image = np.zeros((rows,cols))
image[:, np.arange(0,image.shape[1], 2)] = 1
image[np.arange(0,image.shape[0], 2), :] = 0.5
dpi = 100
left = right = 60
top = 40
bottom = 65
cbarwidth = 24
wspace = 10
width = left + cols + wspace + cbarwidth + right
height = top + rows + bottom
w = width / dpi
h = height / dpi
fig = plt.figure(figsize=(w,h), dpi=dpi)
im = fig.figimage(image, xo=left, yo=bottom);
# create axes on top
# bbox in pixels
bbox = Bbox([[left, bottom], [left + cols, bottom + rows]])
ax = fig.add_axes(fig.transFigure.inverted().transform_bbox(bbox))
ax.set_facecolor("None")
# recreate axis limits
ax.set(xlim=(-0.5, cols-0.5), ylim=(rows-0.5, -0.5))
# add colorbar
cbbox = Bbox([[left + cols + wspace, bottom],
[left + cols + wspace + cbarwidth, bottom + rows]])
cax = fig.add_axes(fig.transFigure.inverted().transform_bbox(cbbox))
fig.colorbar(im, cax=cax)
fig.savefig("test3.png")
При этом можно быть уверенным, что само изображение не искажается. Но тики осей могут быть смещены на пиксель или около того, потому что они проходят преобразование фигуры. Кроме того, я не продумал полностью, нужно ли сдвигать координаты bbox на половину единицы или нет. (Комментарии приветствуются по последнему пункту!)