比方说,我正在尝试绘制x*y
像素(或英寸)的黑洞图片。与许多其他视图不同,我不想指定图形的总大小,而是要指定图内容的大小(因此,框架中的所有内容,不包括框架本身,刻度线,标签,颜色条,边距,...)。>
首选的方法是什么?
我已经遇到过几次这个问题,但是我现在更喜欢其他一些方法,而不是以前的反复尝试大小的迭代……这是我的“游乐场代码”:
import numpy as np
%matplotlib inline
import matplotlib
from matplotlib import pyplot as plt
import notebook
print(matplotlib.__version__, notebook.__version__)
# 3.0.0, 5.7.0 in my case
# some data
x, y = 456, 123
a = np.random.randn(y, x)
# the following at least gets the actual figure size in browser right,
# but if possible i'd like to avoid large white space margins as well...
# %config InlineBackend.print_figure_kwargs = {'bbox_inches': None}
dpi = plt.rcParams['figure.dpi']
fig, ax = plt.subplots(figsize=(x/dpi, y/dpi), dpi=dpi)
im = ax.imshow(a, interpolation='none')
cb = fig.colorbar(im)
# print sizes
bbox = ax.get_window_extent().transformed(fig.dpi_scale_trans.inverted())
print(f"content size: ({bbox.width}, {bbox.height}) inch, ({bbox.width*fig.dpi}, {bbox.height*fig.dpi}) px")
print(f"fig size: {fig.get_size_inches()} in, {fig.dpi*fig.get_size_inches()} px")
print(f"dpi: {fig.dpi}")
输出:
content size: (4.023888888888889, 1.3870138888888888) inch, (289.72, 99.865) px
fig size: [6.33333333 1.70833333] in, [456. 123.] px
dpi: 72.0
您可以看到打印的图形尺寸为456x123像素,但是如果您实际检查上传的图片(从浏览器粘贴的副本),则会看到它仅为376x119像素。尽管可以固定(如代码中所述),但独立于此的实际“内容”尺寸保持为282x75 px:-/。
有什么想法吗?
答案 0 :(得分:1)
不幸的是,没有首选的方法。 我想到了一些或多或少复杂的解决方法。
如果主要目的是生成图形的图像文件,那么最简单的方法可能是使图像绘图的轴与图形完全一样大,然后通过{{1} }选项。
尽管如此,仍需要在图形外部手动放置一个颜色栏。
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
它也将遭受与 A。相同的缺陷,例如如果使用一些奇数,例如
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")
dpi = 72
left = right = 59
top = bottom = 37
cbarwidth = 19
wspace = 12
并将轴放置在顶部。确保没有混叠效果的唯一方法是使用figimage
。这会将图像以像素坐标放置到图形中。但是,默认情况下将没有任何轴。 @anntzer已proposed recently解决了这个问题,就是将一个轴放在图中figimage
的位置。
figimage
使用此功能可以确保图像本身没有失真。但是轴刻度线可能会偏离一个像素左右,因为它们经历了图形转换。另外,我还没有完全考虑过是否需要将bbox坐标移动半个单位。 (欢迎在最后一点发表评论!)