如何在Matplotlib中获得以像素为单位的固定高度,数据x/y纵横比的固定值并自动删除删除水平空白边距? [英] How to obtain a fixed height in pixels, fixed data x/y aspect ratio and automatically remove remove horizontal whitespace margin in Matplotlib?
问题描述
让我们以此为起点,基于:
但是,图的左侧和右侧有很多空白区域.此空间是由于我也想要固定的 1
长宽比(x和y数据具有相同的大小).我们可以通过删除 set_aspect
调用来确认这一点,它给出了一个具有合理大小边距的图形:
但是我也想要1/1的宽高比.
我尝试使用以下几种方法删除此空间:
但是高度不再是我想要的400:
main.png PNG 189x345 189x345 + 0 + 0 8位sRGB 4792B 0.000u 0:00.000
或者如果我尝试添加:
plt.tight_layout(pad=0)
高度是正确的,但它没有去除水平空间:
我可以做的一件事是显式设置宽度:
import sys将numpy导入为np导入matplotlib.pyplot作为plt将Matplotlib导入为mplh = int(sys.argv [1])w = int(sys.argv[2])无花果,ax = plt.subplots(nrows = 2,ncols = 1)wi, hi = fig.get_size_inches()fig.set_size_inches(hi *(w/h),hi)t = np.arange(-10.,10.,1.)a = ax[0]a.set_aspect(1)a.plot(t, t, '.')a =斧[1]a.plot(t,-t,'.')a.set_aspect(1)plt.tight_layout(pad=1)plt.savefig('main.png',格式='png',dpi=h/facecolor='y',)
并运行:
./main.py 400 250 &&识别main.png
通过反复试验选择了250个像素,它的确提供了确切的像素尺寸和美观的输出:
但是我不想经过反复试验才能找到值250,我希望可以由matplotlib自动确定该值.
这可能是
bbox_inches ='tight'
给出了看起来不错的图像,没有太多的边框,但是却使我失去了确切的尺寸,因此我们使用SVG输出作为解决此问题的方法.
这应该很有效,因为 SVG 是一种矢量格式,因此应该可以无缝缩放到任何大小.
我使用Inkscape进行转换,因为Imagemagick要求您手动计算分辨率:
- https://superuser.com/questions/598849/imagemagick-convert-how-to-production-sharp-resized-png-files-from-svg-files/1602059#1602059
- 如何将 SVG 转换为 PNGImageMagick?
在Inkscape 0.92.5上进行了测试.
Let's take this as a starting point based on: Specifying and saving a figure with exact size in pixels
#!/usr/bin/env python3
import sys
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
h = int(sys.argv[1])
fig, ax = plt.subplots(nrows=2, ncols=1)
t = np.arange(-10., 10., 1.)
a = ax[0]
a.set_aspect(1)
a.plot(t, t, '.')
a = ax[1]
a.plot(t, -t, '.')
a.set_aspect(1)
plt.savefig(
'main.png',
format='png',
dpi=h/fig.get_size_inches()[1],
facecolor='y',
)
which allows me to do:
./main.py 400 && identify main.png
to generate an image with the correct desired height of 400 pixels:
main.png PNG 533x400 533x400+0+0 8-bit sRGB 6058B 0.000u 0:00.000
However, there's a lot of empty space to the left and right of the plots. This space is due to the fixed aspect ratio of 1
that I also want (x and y data have the same sizes). We can confirm that by removing the set_aspect
calls, which gives a figure with reasonably sized margins:
but I want the 1/1 aspect ratio as well.
I've tried to remove this space with several methods from: Removing white space around a saved image in matplotlib but none gave what I wanted.
For example, if I add:
plt.savefig(bbox_inches='tight',
I get the desired image:
but the height is not 400 anymore as I want it to be:
main.png PNG 189x345 189x345+0+0 8-bit sRGB 4792B 0.000u 0:00.000
Or if I try instead to add:
plt.tight_layout(pad=0)
the height is correct, but it didn't remove the horizontal space:
One thing I could do is to explicitly set the width as in:
import sys
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
h = int(sys.argv[1])
w = int(sys.argv[2])
fig, ax = plt.subplots(nrows=2, ncols=1)
wi, hi = fig.get_size_inches()
fig.set_size_inches(hi*(w/h), hi)
t = np.arange(-10., 10., 1.)
a = ax[0]
a.set_aspect(1)
a.plot(t, t, '.')
a = ax[1]
a.plot(t, -t, '.')
a.set_aspect(1)
plt.tight_layout(pad=1)
plt.savefig(
'main.png',
format='png',
dpi=h/hi,
facecolor='y',
)
and run that with:
./main.py 400 250 && identify main.png
where 250 is selected by trial and error, and that does give the exact pixel dimensions and good looking output:
but I'd rather not have to do the trial and error to find the value 250, I want that to be determined automatically by matplotlib.
This might be what matplotlib: Set width or height of figure without changing aspect ratio is asking, but it is hard to be sure without concrete examples.
Tested on matplotlib==3.2.2.
SVG output + plt.savefig(bbox_inches='tight'
+ Inkscape convert
This is terrible, but it does what I want without a lot of extra boilerplate, so here we go:
#!/usr/bin/env python3
import sys
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
h = int(sys.argv[1])
fig, ax = plt.subplots(nrows=2, ncols=1)
t = np.arange(-10., 10., 1.)
a = ax[0]
a.set_aspect(1)
a.plot(t, t, '.')
a = ax[1]
a.plot(t, -t, '.')
a.set_aspect(1)
plt.savefig(
'main.svg',
format='svg',
dpi=h/fig.get_size_inches()[1],
facecolor='y',
bbox_inches='tight',
)
and then:
inkscape -b FFF -e main.png -h 400 main.svg
output:
bbox_inches='tight'
gives a decent looking image without too much borders, but makes me lose the exact size, so we use the SVG output as a way to work around that.
This should work well since SVG is a vector format, and therefore should scale to any size seamlessly.
I use Inkscape for the conversion because Imagemagick requires you to manually calculate the resolution:
- https://superuser.com/questions/598849/imagemagick-convert-how-to-produce-sharp-resized-png-files-from-svg-files/1602059#1602059
- How to convert a SVG to a PNG with ImageMagick?
Tested on Inkscape 0.92.5.
这篇关于如何在Matplotlib中获得以像素为单位的固定高度,数据x/y纵横比的固定值并自动删除删除水平空白边距?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!