我使用MatPlotLib动态生成水平条形图。它在大多数情况下都能很好地工作,直到人们试图绘制大量的数据点。 MatPlotLib试图将所有条形图压入图中,它们开始消失。
理想的解决方案是生成绘图,使每个水平条的高度为一个像素,每个条形图分隔1px。然后,得到的绘图图像的总高度将取决于条的数量。但由于MatPlotLib中的所有东西都是相对的,我真的陷入了如何做到这一点。任何帮助将不胜感激!
答案 0 :(得分:3)
一种选择是使用条形作为像素生成图像。
import matplotlib.pyplot as plt
import numpy as np
dpi = 100
N = 100 # numbner of bars (approx. half the number of pixels)
w = 200 #width of plot in pixels
sp = 3 # spacing within axes in pixels
bp = 50; lp = 70 # bottom, left pixel spacing
bottom=float(bp)/(2*N+2*sp+2*bp)
top = 1.-bottom
left=float(lp)/(w+2*lp)
right=1.-left
figheight = (2*N+2*sp)/float(dpi)/(1-(1-top)-bottom) #inch
figwidth = w/float(dpi)/(1-(1-right)-left)
# this is the input array to plot
inp = np.random.rand(N)+0.16
ar = np.zeros((2*N+2*sp,w))
ninp = np.round(inp/float(inp.max())*w).astype(np.int)
for n in range(N):
ar[2*n+sp, 0: ninp[n]] = np.ones(ninp[n])
fig, ax=plt.subplots(figsize=(figwidth, figheight), dpi=dpi)
plt.subplots_adjust(left=left, bottom=bottom, right=right, top=top)
plt.setp(ax.spines.values(), linewidth=0.5)
ext = [0,inp.max(), N-0.5+(sp+0.5)/2., -(sp+0.5)/2.]
ax.imshow(ar, extent=ext, interpolation="none", cmap="gray_r", origin="upper", aspect="auto")
ax.set_xlim((0,inp.max()*1.1))
ax.set_ylabel("item")
ax.set_xlabel("length")
plt.savefig(__file__+".png", dpi=dpi)
plt.show()
这适用于dpi
的任何设置
请注意,ticklabels可能看起来有点偏离,这是来自matplotlib的不准确;我不知道如何克服。
答案 1 :(得分:1)
此示例显示如何绘制1像素宽度的线:
yinch = 2
fig, ax = plt.subplots(figsize=(3,yinch), facecolor='w')
fig.subplots_adjust(left=0, right=1, bottom=0, top=1)
ypixels = int(yinch*fig.get_dpi())
for i in range(ypixels):
if i % 2 == 0:
c = 'k'
else:
c = 'w'
ax.plot([0,np.random.rand()], [i,i], color=c, linewidth=72./fig.get_dpi())
ax.set_ylim(0,ypixels)
ax.axis('off')
结果如下(放大200%):
使用不同的dpi不是问题,但是使用plot()
变得不太有用,因为您无法指定线宽单位。您可以计算所需的线宽,但我认为在这种情况下使用barh()
会更清楚。
在上面的示例中,我只是禁用了轴来聚焦在1px条上,如果删除它可以正常绘制。围绕它的间距不是问题,因为Matplotlib没有绑定到图的0-1范围,但是您想要将bbox_inches='tight'
添加到您的savefig以包括正常0-1范围之外的艺术家。如果您在轴内花费大量时间进行“精确”绘图,我认为更容易拉伸轴以跨越整个图形尺寸。您当然采用不同的方法,但这需要您还以英寸计算轴尺寸。这两个角度都可以工作,这取决于您的确切情况,这可能更方便。
另请注意,旧版本的Matplotlib(< 2.0?)具有不同的默认figure.dpi
和savefig.dpi
。您可以通过在dpi=fig.get_dpi()
语句中添加savefig
来避免这种情况。升级的众多原因之一。 ;)
yinch = 2
dpi = 128
fig, ax = plt.subplots(figsize=(3,yinch), facecolor='w', dpi=dpi)
fig.subplots_adjust(left=0, right=1, bottom=0, top=1)
ypixels = int(yinch*fig.get_dpi())
for i in range(ypixels):
if i % 2 == 0:
c = '#aa0000'
else:
c = 'w'
ax.barh(i,np.random.rand(), height=1, color=c)
ax.set_title('DPI %i' % dpi)
ax.set_ylim(0,ypixels)
fig.savefig('mypic.png', bbox_inches='tight')