【问题标题】:Matplotlib draw vertical lines up to a curveMatplotlib 将垂直线绘制成一条曲线
【发布时间】:2019-12-21 03:40:15
【问题描述】:

我目前正在使用Rectangle 尝试用每个矩形的单一颜色填充曲线下的区域。但是矩形的宽度 > 1 像素。我想画 1 像素宽的线,这样它们就不会重叠。目前曲线下的垂直矩形水平重叠 1 或 2 个像素。

def rect(x,y,w,h,c):
    ax = plt.gca()
    polygon = plt.Rectangle((x,y),w,h,color=c, antialiased=False)
    ax.add_patch(polygon)

def mask_fill(X,Y, fa, cmap='Set1'):
    plt.plot(X,Y,lw=0)  
    plt.xlim([X[0], X[-1]])
    plt.ylim([0, MAX])
    dx = X[1]-X[0]
    for n, (x,y, f) in enumerate(zip(X,Y, fa)):
        color = cmap(f)
        rect(x,0,dx,y,color)

如果我使用下面的代码画线,重叠减少了,但仍然有重叠

def vlines(x_pos, y1, y2, c):
    plt.vlines(x_pos, ymin=y1, ymax=y2, color=c)

def draw_lines(X, Y, trend_len, cmap='Blues_r']):
    plt.plot(X, Y, lw=0)  
    plt.xlim([X[0], X[-1]])
    plt.ylim([0, MAX])
    dx = X[1] - X[0]
    ydeltas = y_trend(Y, trend_len)
    for n, (x, y, yd) in enumerate(zip(X, Y, ydeltas)):
        color = cmap(y / MAX)
        vlines(x, y1=0, y2=y, c=color)

将参数值的前 3 次迭代打印到 vlines 中,我们可以看到 x_pos 递增 1 - 但红线明显与第一条蓝线重叠,如下图所示(NB 第一(LHS)蓝线为 1 像素宽):

x_pos: 0, y1: 0, y2: 143.51, c: (0.7816378316032295,     0.8622683583237216, 0.9389773164167627, 1.0)
x_pos: 1, y1: 0, y2: 112.79092811646952, c: (0.9872049211841599, 0.5313341022683583, 0.405843906189927, 1.0)
x_pos: 2, y1: 0, y2: 123.53185623293905, c: (0.9882352941176471, 0.6059669357939254, 0.4853671664744329, 1.0)

样本数据:

47.8668447889, 1
78.5668447889, 1
65.9768447889, 1
139.658525932, 2
123.749454049, 2
116.660382165, 3
127.771310282, 3
114.792238398, 3

上面的第一列对应系列的y值(x值只是值的数量,从0开始计数) 第二列对应类。

我正在生成两个图像:

每个类别具有唯一值 (0-6),每个具有不同的颜色(7 种唯一颜色),颜色填充到 y 值,这将用作下面数据图像的掩码。

第二张图片(显示示例)对不同的类值(例如 0=Blues_r、1=Reds_r 等)使用不同的颜色图,颜色的强度由 y 的值给出。

计算颜色的代码很好,但我无法让 matplotlib 绘制一个像素宽的垂直线。

【问题讨论】:

  • 为什么需要线条为 1 像素宽?您是否要完全填充曲线下的区域?
  • 是的,用单个像素宽度的线完成填充,每条线都有特定的颜色。我添加了一个使用 vlines 的测试,仍然得到重叠
  • linewidth 是一个浮点数,你有没有尝试过小于一个?看来您可能需要根据 dpi 计算值。
  • 您在寻找fill吗?
  • Re: linewidth 我尝试了 linewidth = 1/DPI 但仍将大多数线条绘制为 2 像素宽而不是 1 像素宽(也变为 antialised=False)

标签: python matplotlib


【解决方案1】:

由于您的目标不是创建交互式图形,并且您正在尝试操作像素列,因此您可以使用 numpy 而不是 matplotlib 来生成结果。

这是一个函数,它将接收ycategory 数组,并创建一个与y 一样宽的图像,并指定height。颜色缩放与您的解决方案类似,其中y 除以最大值。

from matplotlib import pyplot as plt
import numpy as np

def draw_lines(y, category, filename, cmap='Set1', max=None, height=None):
    y = np.asanyarray(y).ravel()
    category = np.asanyarray(category).ravel()
    assert y.size == category.size
    if max is None:
        max = y.max()
    if height is None:
        height = int(np.ceil(max))
    if isinstance(cmap, str):
        cmap = plt.get_cmap(cmap)

    colors = cmap(category)
    colors[:, 3] = y / max
    colors = (255 * colors).astype(np.uint8)
    output = np.repeat(colors[None, ...], height, axis=0)

    heights = np.round(height * (y / max))
    mask = np.arange(height)[:, None] >= heights
    mask = np.broadcast_to(mask[::-1, :, None], output.shape)
    output[mask] = 0

    plt.imsave(filename, output)
    return output

第一部分只是设置输入值。第二部分获取颜色值。调用具有 n 值数组的颜色图会返回 (n, 4) 范围内的颜色数组 [0, 1.0]colors[:, 3] = y / max 设置与高度成比例的 Alpha 通道。然后将颜色垂直涂抹到所需的height。最后一部分根据here提出的方法创建一个掩码,将每列的顶部设置为零。

此版本使用透明度来关闭颜色并修剪形状。如果您愿意缩放颜色而不是调整透明度,您可以对白色背景做同样的事情:

def draw_lines_b(y, category, filename, cmap='Set1', max=None, height=None):
    y = np.asanyarray(y).ravel()
    category = np.asanyarray(category).ravel()
    assert y.size == category.size
    if max is None:
        max = y.max()
    if height is None:
        height = int(np.ceil(max))
    if isinstance(cmap, str):
        cmap = plt.get_cmap(cmap)

    colors = cmap(category)
    colors[..., :3] *= (y / max)[..., None]
    colors = (255 * colors).astype(np.uint8)
    output = np.repeat(colors[None, ...], height, axis=0)

    heights = np.round(height * (y / max))
    mask = np.arange(height)[:, None] >= heights
    mask = np.broadcast_to(mask[::-1, :, None], output.shape)
    output[mask] = 255

    plt.imsave(filename, output)
    return output

在这两种情况下,您可以想象,matplotlib 并不是绝对必要的。您可以定义自己的颜色列表,并使用更合适的库(例如 PIL)来保存图像。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多