是否可以在 matplotlib 中获得曲线下的颜色渐变? [英] Is it possible to get color gradients under curve in matplotlib?

查看:74
本文介绍了是否可以在 matplotlib 中获得曲线下的颜色渐变?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我碰巧在这个),但他们建议采用次优方法.

之前的大多数答案都建议在 pcolormesh 填充上绘制一个白色多边形.这不太理想,原因有两个:

  1. 轴的背景不能是透明的,因为上面有一个填充的多边形
  2. pcolormesh 绘制速度相当慢,而且插值不平滑.

这是一个更多的工作,但有一种方法可以更快地绘制并提供更好的视觉效果:设置使用 imshow 绘制的图像的剪辑路径.

举个例子:

将 numpy 导入为 np导入 matplotlib.pyplot 作为 plt将 matplotlib.colors 导入为 mcolors从 matplotlib.patches 导入多边形np.random.seed(1977)定义主():对于 _ 范围(5):渐变填充(*生成数据(100))plt.show()def generate_data(num):x = np.linspace(0, 100, num)y = np.random.normal(0, 1, num).cumsum()返回 x, ydef gradient_fill(x, y, fill_color=None, ax=None, **kwargs):"""绘制一条线,其下方填充有线性 alpha 渐变.参数----------x, y : 类似数组行的数据值.fill_color : matplotlib 颜色说明符(字符串,元组)或无填充的颜色.如果没有,将使用线条的颜色.ax :matplotlib Axes 实例要绘制的轴.如果没有,将使用当前的 pyplot 轴.附加参数传递给 matplotlib 的plot"函数.退货-------line : Line2D 实例绘制的线.im : 一个 AxesImage 实例透明渐变剪裁到曲线下方的区域."""如果 ax 是 None:ax = plt.gca()线,= ax.plot(x, y, **kwargs)如果 fill_color 是 None:fill_color = line.get_color()zorder = line.get_zorder()alpha = line.get_alpha()alpha = 1.0 如果 alpha 是 None else alphaz = np.empty((100, 1, 4), dtype=float)rgb = mcolors.colorConverter.to_rgb(fill_color)z[:,:,:3] = RGBz[:,:,-1] = np.linspace(0, alpha, 100)[:,None]xmin, xmax, ymin, ymax = x.min(), x.max(), y.min(), y.max()im = ax.imshow(z, aspect='auto', extent=[xmin, xmax, ymin, ymax],origin='lower', zorder=zorder)xy = np.column_stack([x, y])xy = np.vstack([[xmin, ymin], xy, [xmax, ymin], [xmin, ymin]])clip_path = Polygon(xy, facecolor='none', edgecolor='none', closed=True)ax.add_patch(clip_path)im.set_clip_path(clip_path)ax.autoscale(真)返回线,我主要的()

I happened to see a beautiful graph on this page which is shown below:

Is it possible to get such color gradients in matplotlib?

解决方案

There have been a handful of previous answers to similar questions (e.g. https://stackoverflow.com/a/22081678/325565), but they recommend a sub-optimal approach.

Most of the previous answers recommend plotting a white polygon over a pcolormesh fill. This is less than ideal for two reasons:

  1. The background of the axes can't be transparent, as there's a filled polygon overlying it
  2. pcolormesh is fairly slow to draw and isn't smoothly interpolated.

It's a touch more work, but there's a method that draws much faster and gives a better visual result: Set the clip path of an image plotted with imshow.

As an example:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
from matplotlib.patches import Polygon
np.random.seed(1977)

def main():
    for _ in range(5):
        gradient_fill(*generate_data(100))
    plt.show()

def generate_data(num):
    x = np.linspace(0, 100, num)
    y = np.random.normal(0, 1, num).cumsum()
    return x, y

def gradient_fill(x, y, fill_color=None, ax=None, **kwargs):
    """
    Plot a line with a linear alpha gradient filled beneath it.

    Parameters
    ----------
    x, y : array-like
        The data values of the line.
    fill_color : a matplotlib color specifier (string, tuple) or None
        The color for the fill. If None, the color of the line will be used.
    ax : a matplotlib Axes instance
        The axes to plot on. If None, the current pyplot axes will be used.
    Additional arguments are passed on to matplotlib's ``plot`` function.

    Returns
    -------
    line : a Line2D instance
        The line plotted.
    im : an AxesImage instance
        The transparent gradient clipped to just the area beneath the curve.
    """
    if ax is None:
        ax = plt.gca()

    line, = ax.plot(x, y, **kwargs)
    if fill_color is None:
        fill_color = line.get_color()

    zorder = line.get_zorder()
    alpha = line.get_alpha()
    alpha = 1.0 if alpha is None else alpha

    z = np.empty((100, 1, 4), dtype=float)
    rgb = mcolors.colorConverter.to_rgb(fill_color)
    z[:,:,:3] = rgb
    z[:,:,-1] = np.linspace(0, alpha, 100)[:,None]

    xmin, xmax, ymin, ymax = x.min(), x.max(), y.min(), y.max()
    im = ax.imshow(z, aspect='auto', extent=[xmin, xmax, ymin, ymax],
                   origin='lower', zorder=zorder)

    xy = np.column_stack([x, y])
    xy = np.vstack([[xmin, ymin], xy, [xmax, ymin], [xmin, ymin]])
    clip_path = Polygon(xy, facecolor='none', edgecolor='none', closed=True)
    ax.add_patch(clip_path)
    im.set_clip_path(clip_path)

    ax.autoscale(True)
    return line, im

main()

这篇关于是否可以在 matplotlib 中获得曲线下的颜色渐变?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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