Python中的2D颜色映射

2024-05-16 12:50:09 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个2d向量(x,y),我需要找到一个2d颜色贴图,将这些坐标映射到平滑的颜色贴图。颜色代码将仅取决于(x,y)值。比如说,

  • 中间是白色
  • 当我们去东北部的时候,红色会越来越多
  • 当我们向东南走的时候,蓝色越来越多
  • 我们往西北方向走的时候会更绿
  • 当我们去西南部时,绿色会越来越多

换言之:

green         red
       white
green         blue

我在{}中找不到符合我需要的东西。我曾想过将坐标转换为幅值和相位,但问题仍然是一样的。我还考虑在向量(x,y)中添加一个虚拟维度,使其成为三维维度,然后对生成的三维向量进行规格化。然后,将其馈送到matplotlib图中的cmap参数。但是,这会产生不平滑的颜色。有线索吗

颜色贴图的示例:

sample color map


Tags: matplotlib颜色greenbluered方向向量蓝色
2条回答

我会使用像hsl或hsv这样的颜色空间,固定亮度值(l或v),并使用x作为h,y作为s来表示所有颜色。您将需要规范化x和y的值,使其与颜色空间组件兼容

因此,为了重申这个问题以确保我正确理解它:您希望有两个不同的colormap通道,而不是一个

在matplotlib中,我看不到直接的方法,有两个选项:

  • 使用不同的颜色通道/颜色贴图/透明胶片多次打印相同的数据
  • 定义自己的自定义2D到RGB颜色贴图,并将RGB三元组数组传递给plotting函数

对于“hack-y”多重打印解决方案:

import numpy as np
from matplotlib.colors import hsv_to_rgb, rgb_to_hsv
import matplotlib.pyplot as plt

xydata = np.array([(x,y) for x in np.arange(-1.,1.1,0.1) for y in np.arange(-1.,1.1,0.1)], dtype=float)
x_colorfunc = lambda xy: xy.T[0].max() - np.abs(xy.T[0])
y_colorfunc = lambda xy: np.abs(xy.T[1])
y_colormap_coord = y_colorfunc(xydata)
x_colormap_coord = x_colorfunc(xydata)
x_colormap = "plasma"
y_colormap = "Greys"


plt.figure("2d_colormap_hack")
plt.scatter(xydata.T[0], xydata.T[1], c=x_colormap_coord, cmap= x_colormap, alpha=1.0)
plt.scatter(xydata.T[0], xydata.T[1], c=y_colormap_coord, cmap= y_colormap, alpha=0.6)

产生

2-channel hack graph

您可以对自定义2D到颜色功能执行任何操作,但这里有两个建议:

def xy_color_func(xy):
    # using np.divide handles `RuntimeWarning: divide by zero encountered in true_divide`
    xy_ratio = np.divide(xy.T[1], xy.T[0], out=np.ones_like(xy.T[0]), where=(xy.T[0]!=0) )
    xy_angle_frac = (4/np.pi)*np.abs(np.arctan(xy_ratio))
    xy_mag = np.linalg.norm(xy, axis=-1)
    hsl_hue = 1 - 1./6*xy_angle_frac   # hue goes from red to blue 
    hsl_sat = 1 - xy_mag/xy_mag.max()  # 0 is full color saturation, 1 is equal RGB values
    hsl_luminance = 0.75 - 0.25*(xy_mag/xy_mag.max())  # brighter at the "target" point of (0, 0)
    hsv = hsl_to_hsv(hsl_hue, hsl_sat, hsl_luminance)
    rgb = hsv_to_rgb(hsv)
    return rgb

def hsl_to_hsv(hsl_hue, hsl_sat, hsl_luminance):
    hsv_hue = hsl_hue
    hsv_v = hsl_luminance + hsl_sat*np.minimum(hsl_luminance, 1-hsl_luminance)
    hsv_sat = 2*(1-np.divide(hsl_luminance, hsv_v, out=np.ones_like(hsv_v), where=(hsv_v!=0) ))
    hsv = np.vstack((hsv_hue, hsv_sat, hsv_v)).T
    return hsv

xy_colors = xy_color_func(xydata)
plt.figure("2d_colormap_func")
plt.scatter(xydata.T[0], xydata.T[1], c=xy_colors)

产生

2D color function graph

看起来您所需的颜色贴图需要更多的规则来将XY区域转换为所需的颜色,并使用渐变/混合函数从一个区域过渡到另一个区域,类似于4中所示的梯形混合。在你想要的地图上面

  • “绿色”是x<=0
  • “红色”是x >0 & y < 0
  • “蓝色”是x > 0 & y >= 0,并且
  • white是{}

实现这一点的一种方法可能是在图形程序(如Gimp或Inkscape)中创建具有所需颜色的点网格,调整关键坐标和指定的颜色三元组(RGB、HSL或HSV),直到您对外观满意,然后使用scipy.interpolate.griddata5为XY数据插值3个颜色通道中的每一个,例如:

key_xy_points = np.array([[0,0],[1,0],[1,1],[1,-1],[-1,1], [-1,-1]],dtype=float)
key_xy_RGBs = np.array([[1,1,1], [1,1,1], [0,0,1], [1,0,0], [0,1,0], [0,1,0]],dtype=float)

from scipy.interpolate import griddata

reds = griddata(key_xy_points, key_xy_RGBs.T[0], xydata)
greens = griddata(key_xy_points, key_xy_RGBs.T[1], xydata)
blues = griddata(key_xy_points, key_xy_RGBs.T[2], xydata)

xy_colors_griddata = np.vstack((reds, greens, blues)).T
plt.figure("2d_colormap_griddata")
plt.scatter(xydata.T[0], xydata.T[1], c=xy_colors_griddata)

产生

2D color function graph from griddata

注意:只要我编写自己的颜色空间转换函数,我就可以直接从HSL转换为RGB3,但也许有一位评论员可以解释为什么matplotlib.colors有hsv_to_rgb而没有hsl_to_rgb(运行matplotlib v.3.3.2)

相关问题 更多 >