Pyqtgraph & 根据曲面图的高度更改颜色

问题描述 投票:0回答:2

我正在寻找一种方法使我的表面绘图项目根据高度改变颜色。以下是我目前的方法:

def __init__(self, s):

    self.traces = dict()
    self.app = QtGui.QApplication(sys.argv)
    self.w = gl.GLViewWidget()
    self.w.opts['distance'] = 2000
    self.w.setWindowTitle('pyqtgraph example: GLLinePlotItem')
    self.w.setGeometry(0, 0, 600, 600)
    self.w.show()
    self.socket = s

    self.timer = QtCore.QTimer()
    self.timer.setInterval(1) # in milliseconds
    self.timer.start()
    self.timer.timeout.connect(self.onNewData)

    # create the background grids
    #gx is the y grid
    #gz is the x gid
    gx = gl.GLGridItem()
    gx.rotate(90, 0, 1, 0)
    gx.translate(0, 0, 0)
    self.w.addItem(gx)
    gz = gl.GLGridItem()
    gz.translate(200, 0, -500)
    self.w.addItem(gz)
    gx.scale(100, 10, 100)
    gz.scale(20, 10, 100)


    self.y = np.linspace(0, 100, 10)
    self.x = np.linspace(60,400, 708)
    temp_z = np.zeros((10,708))
    self.surf = gl.GLSurfacePlotItem(x=self.y, y=self.x, z=temp_z, shader='heightColor',
                                     computeNormals=False, smooth=False)
    self.surf.scale(3,1,1)
    self.surf.shader()['colorMap'] = np.array([0.7, 2, 0.5, 0.2, 0.7, 0.7, 0.2, 0, 2])
    self.w.addItem(self.surf)

但是这个方法效果并不好。当 Z 值变得非常高时,表面会变得完全白色。顺便说一句,我不知道我在用颜色图做什么,我只是把它从示例中删除了。

python opengl pyqtgraph
2个回答
5
投票

我建议您使用

colors
GLSurfacePlotItem
选项。 这个想法是计算与表面的 z 值(高度)相关的颜色并使它们标准化(在 0 和 1 之间)。有了这个,您可以计算表面每个点的颜色,例如使用
cmap
matlotlib

# -*- coding: utf-8 -*-
from __future__ import print_function, absolute_import
from pyqtgraph.Qt import QtCore, QtGui
import pyqtgraph as pg
import pyqtgraph.opengl as gl
import matplotlib.pyplot as plt
import numpy as np
import os
from PyQt4.QtGui import QFileDialog
import sys

if not( 'app' in locals()):
    app = QtGui.QApplication([])

traces = dict()
# app = QtGui.QApplication(sys.argv)
w = gl.GLViewWidget()
w.opts['distance'] = 2000
w.setWindowTitle('pyqtgraph example: GLLinePlotItem')
w.setGeometry(0, 0, 600, 600)
w.show()
# socket = s

# timer = QtCore.QTimer()
# timer.setInterval(1) # in milliseconds
# timer.start()
# timer.timeout.connect(onNewData)

# create the background grids
#gx is the y grid
#gz is the x gid
gx = gl.GLGridItem()
gx.rotate(90, 0, 1, 0)
gx.translate(0, 0, 0)
w.addItem(gx)
gz = gl.GLGridItem()
gz.translate(200, 0, -500)
w.addItem(gz)
gx.scale(100, 10, 100)
gz.scale(20, 10, 100)


y = np.linspace(0, 100, 10)
print(y)
x = np.linspace(0,100, 10)
print(x)
temp_z = np.random.rand(len(x),len(y))*100.

cmap = plt.get_cmap('jet')

minZ=np.min(temp_z)
maxZ=np.max(temp_z)
rgba_img = cmap((temp_z-minZ)/(maxZ -minZ))


surf = gl.GLSurfacePlotItem(x=y, y=x, z=temp_z, colors = rgba_img )

surf.scale(3,1,1)
# surf.shader()['colorMap'] = np.array(list(np.linspace(-100, 100, 1000)))
w.addItem(surf)

if __name__ == '__main__':
    import sys

    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
        QtGui.QApplication.instance().exec_()

给出:


0
投票

正确的方法确实是使用“heightMap”着色器。

使用

color
GLSurfacePlotItem
选项时,颜色会在顶点(网格点)之间平滑插值。这是可以的,只要顶点彼此之间的垂直距离不是太远,因为插值颜色可能与颜色图的实际颜色一致。这可以在下图中看到,其中 left 侧是使用 colormap 绘制的,而 right 侧是使用 heightMap 着色器绘制的:

但是,一旦数据出现大幅跳跃,您就会开始看到插值伪影,如下图所示(最明显的是在某些地方出现的绿色色调)。使用着色器时这不是问题,并且高度图将正确着色。

不幸的是,使用着色器实现这一目标并非易事。高度图着色器有一种奇怪的方式来指定其颜色。根据代码中的注释:

red   = pow(colorMap[0]*(z + colorMap[1]), colorMap[2])

green = pow(colorMap[3]*(z + colorMap[4]), colorMap[5])

blue  = pow(colorMap[6]*(z + colorMap[7]), colorMap[8])

让它匹配任何现有的颜色图有点像一场噩梦。以下是我设法找出的一些近似值:

def default_scaled(z):
    '''
    scales the default shader to z: 
    - lowest will be black
    - mid will be orange-brown
    - highest will be white
    '''
    z_min, z_range = z.min(), z.ptp()
    return [
        2/z_range, -z_min - .00*z_range, 1,  # blue channel
        2/z_range, -z_min - .25*z_range, 1,  # green channel
        2/z_range, -z_min - .50*z_range, 1,  # red channel
    ]


def grayscale(z):
    '''lowest values are black, highest values are white'''
    z_min, z_range = z.min(), z.ptp()
    return 3*[1/z_range, -z_min, 1]  # all channels are the same


def plasma(z):
    '''poor approximation of the `plasma` colormap'''
    z_min, z_range = z.min(), z.ptp()
    return [
        2/z_range, -z_min, 1,  # red channel
        2/z_range, -(z_min+0.5*z_range), 1,  # green channel
        -2/z_range, -(z_min+z_range), 1,  # blue channel
    ]


def cet_l4(z):
    '''poor approximation of the `CET-L4` colormap'''
    z_min, z_range = z.min(), z.ptp()
    return [
        1.5/z_range, -z_min, 0.7,  # red channel
        1.7/z_range, -(z_min+0.4*z_range), 1,  # green channel
        0, 0, 1,  # blue channel is empty
    ]

然后可以按如下方式应用这些:

import numpy as np

import pyqtgraph as pg
import pyqtgraph.opengl as gl

# prepare data
x = np.linspace(-10, 10, 21)
y = np.linspace(0, 10, 11)
z = np.random.rand(len(x), len(y))*10-5

# make app & viewer
app = pg.mkQApp()
w = gl.GLViewWidget()

# create grid
gx = gl.GLGridItem()
gx.rotate(90, 1, 0, 0)
w.addItem(gx)

# create the shaded surface
surf1 = gl.GLSurfacePlotItem(x, y, z)
surf1.setShader('heightColor')
surf1.shader()['colorMap'] = cet_l4(z)
w.addItem(surf1)

# create the colored surface
cmap = pg.colormap.get('CET-L4')
c = cmap.map((z-z.min())/z.ptp(), cmap.FLOAT)
surf2 = gl.GLSurfacePlotItem(x, y, z, c)
surf2.translate(0, -10, 0)
w.addItem(surf2)

w.show()
pg.exec()
© www.soinside.com 2019 - 2024. All rights reserved.