使用matplotlib.pyplot,imshow()和savefig()以全分辨率进行绘制? [英] Plotting at full resolution with matplotlib.pyplot, imshow() and savefig()?

查看:139
本文介绍了使用matplotlib.pyplot,imshow()和savefig()以全分辨率进行绘制?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个中等大小的数组(例如1500x3000),因为它是一幅图像,所以我想按比例绘制.但是,垂直和水平比例是非常不同的.为了简化起见,假设有1米/行和10/列.然后,该图应生成c的图像. 1500x30000.我将kwarg范围用于比例尺和Aspect = 1,以避免变形. 无论是使用绘图窗口(QT4)和imshow()还是使用savefig(),我都无法成功生成大规模和全分辨率的图像.

I have a medium-sized array (e.g. 1500x3000) that I want to plot at scale since it is an image. However, the vertical and horizontal scales are very different. For simplification let say that there is one meter/row and 10/column. The plot should then produce an image which is c. 1500x30000. I use the kwarg extent for the scales and aspect = 1 to avoid deformation. Either by using the plotting windows (QT4) and imshow() or by using savefig(), I never succeeded in producing the image at scale and at full resolution.

我已经查看了许多建议的解决方案,如此处,<请在href ="https://stackoverflow.com/questions/28635270/force-pyplot-imshow-to-produce-image-with-higher-resolution">此处,或,如果是漏洞.我已经更改了matplotlibrc并将其放置在〜/.config/matplotlib中,以尝试强制使用我的display/savefig选项,但无济于事.我也尝试了pcolormesh(),但是没有成功.我使用来自Ubuntu 14.04和QT4Agg的仓库中的python 2.7和matplotlib 1.3作为后端.我也尝试过TkAgg,但是它很慢并且给出相同的结果.我的印象是,在x轴上分辨率是正确的,但肯定是在垂直方向上进行了下采样.这是一段应该模拟我的问题的代码.

I have looked to many proposed solutions as indicated in here, here, or here and there or there in case it was a bug. I have altered my matplotlibrc and placed it in ~/.config/matplotlib to try forcing the my display / savefig options but to no avail. I also tried with pcolormesh() but without success. I use python 2.7 and matplotlib 1.3 from the repo of Ubuntu 14.04 and QT4Agg as a backend. I tried TkAgg too but it is slow and gives the same results. I have the impression that in the x axis the resolution is right but it is definitely downsampled in the vertical direction. Here is a piece of code which should simulate my issue.

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors

R, C = 1500, 3000
DATA = np.random.random((R, C))
DATA[::2, :] *= -1  # make every other line negative
Yi, Xi = 1, 10 # increment
CMP = 'seismic'
ImageFormat ='pdf'
Name = 'Image'


DataRange = (np.absolute(DATA)).max() # I want my data centred on 0
EXTENT = [0, Xi*C, 0 ,Yi*R]
NORM = matplotlib.colors.Normalize(vmin =-DataRange, vmax= DataRange, clip =True)

for i in range(1,4):
    Fig=plt.figure(figsize=(45, 10), dpi = 100*i, tight_layout=True)
    Fig.suptitle(Name+str(i)+'00DPI')
    ax = Fig.add_subplot(1, 1, 1)
    Plot = ax.imshow(DATA, cmap=plt.get_cmap(CMP), norm = NORM, extent = EXTENT, aspect = 1, interpolation='none') 
    ax.set_xlabel('metres')
    ax.set_ylabel('metres')
    Fig.savefig(Name+str(i)+'00DPI.'+ImageFormat,  format = ImageFormat, dpi = Fig.dpi)
plt.close()

在imshow()中,插值='none'或'nearest'或'bilinear'不会由于某些原因而改变分辨率,尽管我认为至少应该在Qt4窗口中使用show()而不是savefig(). 请注意,无论您在plt.figure(dpi =)中进行了设置,保存的数字中的分辨率都是相同的.

In imshow(), interpolation = 'none' or 'nearest' or 'bilinear' does not change the resolution for some reason although I think it is supposed to at least in the Qt4 window if I do show() instead of savefig(). Notice that the resolution is the same in the figures saved whatever you setup in the plt.figure(dpi=).

我对这个系统是如何工作的想法不甚了解.任何帮助都非常欢迎.

I am out of idea and at the limit of my understanding on how things work with this system. Any help is very welcome.

提前谢谢.

推荐答案

运行您的示例,缩放后在matplotlib中一切看起来都不错:无论分辨率如何,结果都是一样的,我每轴单位看到一个像素. 另外,尝试使用较小的数组,pdf(或其他格式)也可以很好地工作.

Running your example, everything looks good in matplotlib after zooming: no matter the resolution, results are the same and I see one pixel per axis unit. Also, trying with smaller arrays, pdfs (or other formats) work well.

这是我的解释:设置图形dpi时,就是在设置整个图形的dpi(不仅是数据区域).在我的系统上,这导致绘图区域垂直占据整个图形的20%.如果将300 dpi和高度设置为10,则垂直数据轴的总像素为300x10x0.2 = 600像素,不足以表示1500点,这向我解释了为什么必须对输出进行重新采样.减小宽度有时偶然会起作用,因为这会改变数据图所占图形的比例.

This is my explanation: when you set figure dpi, you are setting the dpi of the entire figure (not only the data area). On my system, this results in the plot area occupying vertically about 20% of the entire figure. If you set 300 dpi and 10 in height, you get for vertical data axis a total of 300x10x0.2=600 pixels, that are not enough to represent 1500 points, this explains to me why output must be resampled. Note that reducing the width sometimes incidentally works because it changes the fraction of figure occupied by the data plot.

然后,您必须提高dpi并设置"interpolation ='none"(分辨率设置是否完美无关紧要,但只要分辨率足够接近就无关紧要). 另外,您可以调整绘图位置和大小以占据图形的较大部分,但要返回最佳分辨率设置,理想情况下,您希望轴上的像素数是数据点的倍数,否则,必须进行某种插值(考虑如何在三个像素上绘制两个点,反之亦然).

Then you have to increase the dpi and also set interpolation='none' (it shouldn't matter if resolution is perfectly set, but it matters if it is just close enough). Also you can adjust the plot position and size to take a larger part of the figure, but going back to the optimal resolution settings, ideally you want to have a number of pixel on the axis that is a multiple of your data points, otherwise some kind of interpolation must happen (think how you can plot two points on three pixels, or viceversa).

我不知道以下方法是否是最好的方法,matplotlib中可能有更合适的方法和属性,但是我会尝试类似的方法来计算最佳dpi:

I don't know if the following is the best way to do it, there might be more suitable methods and properties in matplotlib, but I would try something like this to calculate the optimal dpi:

vsize=ax.get_position().size[1]  #fraction of figure occupied by axes
axesdpi= int((Fig.get_size_inches()[1]*vsize)/R)  #(or Yi*R according to what you want to do)

然后您的代码(减少到第一个循环)变为:

Then your code (reduced to the first loop), becomes:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors

R, C = 1500, 3000
DATA = np.random.random((R, C))
DATA[::2, :] *= -1  # make every other line negative
Yi, Xi = 1, 10 # increment
CMP = 'seismic'
ImageFormat ='pdf'
Name = 'Image'


DataRange = (np.absolute(DATA)).max() # I want my data centred on 0
EXTENT = [0, Xi*C, 0 ,Yi*R]
NORM = matplotlib.colors.Normalize(vmin =-DataRange, vmax= DataRange, clip =True)

for i in (1,):
    print i 
    Fig=plt.figure(figsize=(45, 10), dpi = 100*i, tight_layout=True)
    Fig.suptitle(Name+str(i)+'00DPI')
    ax = Fig.add_subplot(1, 1, 1)
    Plot = ax.imshow(DATA, cmap=plt.get_cmap(CMP), norm = NORM, extent = EXTENT, aspect = 1, interpolation='none') 
    ax.set_xlabel('metres')
    ax.set_ylabel('metres')
    vsize=ax.get_position().size[1]  #fraction of figure occupied by axes
    axesdpi= int((Fig.get_size_inches()[1]*vsize)/R)  #(or Yi*R according to what you want to do)
    Fig.savefig(Name+str(axesdpi)+'DPI.'+ImageFormat,  format = ImageFormat, dpi = axesdpi)
    #plt.close()

这对我来说合理.

这篇关于使用matplotlib.pyplot,imshow()和savefig()以全分辨率进行绘制?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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