Python Matplotlib-动态打印高度,水平条始终为1px高度

Python Matplotlib-动态打印高度,水平条始终为1px高度,python,matplotlib,plot,Python,Matplotlib,Plot,我正在使用MatPlotLib动态生成一个水平条形图。在人们试图绘制大量数据点之前,它在大多数情况下都运行良好。MatPlotLib试图将所有条压入绘图,它们开始消失 理想的解决方案是生成绘图,使每个水平条的高度为一个像素,每个条之间用1px分隔。结果打印图像的总高度将取决于条数。但是,由于MatPlotLib中的所有内容都是相对的,我真的被困在了如何做到这一点上。任何帮助都将不胜感激 此示例显示如何以1像素宽度绘制线: yinch = 2 fig, ax = plt.subplots(fig

我正在使用MatPlotLib动态生成一个水平条形图。在人们试图绘制大量数据点之前,它在大多数情况下都运行良好。MatPlotLib试图将所有条压入绘图,它们开始消失


理想的解决方案是生成绘图,使每个水平条的高度为一个像素,每个条之间用1px分隔。结果打印图像的总高度将取决于条数。但是,由于MatPlotLib中的所有内容都是相对的,我真的被困在了如何做到这一点上。任何帮助都将不胜感激

此示例显示如何以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\u inches='tight'
添加到savefig中,以包括正常0-1范围之外的艺术家。如果你花了很多时间在坐标轴内“精确”绘制,我认为将坐标轴拉伸到整个图形尺寸更容易。当然,您可以采用不同的方法,但这也需要您以英寸为单位计算轴的大小。两个角度都可以,这取决于你的具体情况,哪一个更方便


还要注意,Matplotlib的旧版本(一个选项是生成以条形图为像素的图像

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


请注意,滴答标签可能看起来有点不准确,这是matplotlib的一个不准确之处;我不知道如何克服。请显示一些代码,以及问题的说明。您可以指定图形大小(以英寸为单位),这与dpi的像素有关。如果您拉伸轴以跨越整个图形,您应该能够计算te像素精确位置。抱歉,当前代码是。现在需要运行,但明天将尝试制作一个最小的示例。太棒了,谢谢!可以用绘图区域周围的间距来完成吗?我有轴、绘图标题、图例等。我想应该提一下,当且仅当dpi设置为72时,此功能才起作用。实际上,它是依赖于在y方向上将绘图周围的间距设置为0,这是不可取的。@tallphil,当然没问题,请参阅我的更新答案。添加
bbox\u inches='tight'
将负责在生成的图形中获得所有绘制的
artist
。@ImportanceOfBeingErnest,它适用于每个dpi,但在使用
pl>时ot()
第一种方法实际上是有用的。你是否碰巧知道为什么标签会脱落一个小节(在中也是如此)?非常感谢@ImportanceOfBeingErnest!我将尝试两种解决方案。。
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()