如何在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?

查看:66
本文介绍了如何在Matplotlib中获得以像素为单位的固定高度,数据x/y纵横比的固定值并自动删除删除水平空白边距?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

让我们以此为起点,基于:

但是,图的左侧和右侧有很多空白区域.此空间是由于我也想要固定的 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要求您手动计算分辨率:

在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:

Tested on Inkscape 0.92.5.

这篇关于如何在Matplotlib中获得以像素为单位的固定高度,数据x/y纵横比的固定值并自动删除删除水平空白边距?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆