如何将颜色图包括为散点图的迭代器

时间:2019-06-14 16:58:50

标签: python matplotlib iterator colormap

我有一组(xyz)点,并将它们绘制在散点图中。 这组点随时间变化,因此,使用迭代器来更新每个步骤。 目前,我能够提取绘图的最大仰角(在Z方向上),以便定义最大/最小值并标准化颜色图。 但是,一旦步骤更新,我不知道如何将绘图的高程值链接到颜色图(先前定义)。

现在,该代码无需更新颜色即可工作。 我试图将变量colormap包含为迭代器,但找不到执行此任务的命令。

#Python moduels
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
import matplotlib.animation
import pandas as pd

###############################################################################
#Generate data
###############################################################################

np.random.seed(10) #To obtain the same result

n_radii  = 8
n_angles = 120

# Make radii and angles spaces (radius r=0 omitted to eliminate duplication).
radii = np.linspace(0.125, 1.0, n_radii)
angles = np.linspace(0, 2*np.pi, n_angles, endpoint=False)

# Repeat all angles for each radius.
angles = np.repeat(angles[..., np.newaxis], n_radii, axis=1)

# Convert polar (radii, angles) coords to cartesian (x, y) coords.
# (0, 0) is manually added at this stage,  so there will be no duplicate
# points in the (x, y) plane.
x = np.append(0, (radii*np.cos(angles)).flatten())
y = np.append(0, (radii*np.sin(angles)).flatten())

rows = len(x)
dim = 3
samples = 10

data = np.zeros((rows,dim,samples)) # (20 xyz) points stored in 10 sets 

for i in range(samples):
    data[:,0,i] = x
    data[:,1,i] = y
    # Compute z to make the pringle surface.
    data[:,2,i] = np.sin(-i*x*y)

index = np.arange(0,samples,1)

Frame = np.array([np.ones(rows)*index[i] for i in range(samples)]).flatten()

a = np.zeros((len(Frame),3))

for i in range(samples):
    a[i*rows:(i+1)*rows,0] = data[:,0,i]
    a[i*rows:(i+1)*rows,1] = data[:,1,i]
    a[i*rows:(i+1)*rows,2] = data[:,2,i]

df = pd.DataFrame({"Frame": Frame ,"x" : a[:,0], "y" : a[:,1], "z" : a[:,2]})

##############################################################################
#SCATTER PLOT
################################################################################

#Function to update my scatter plot
def update_graph(num):

    data = df[df['Frame'] == index[num]]
    graph._offsets3d = (data.x, data.y, data.z)
    title.set_text(r'How to update the color map for each plot based on the value of, Frame={}'.format(round(index[num],3)))

#Limits of Elevation (U3) in data
print('U3_min',min(a[:,2]))
print('U3_max',max(a[:,2]))

#Define figure
fig = plt.figure(figsize=(10, 8), dpi=200)

title = plt.suptitle(r'How to update the color map for each plot based on the value of, Frame={}'.format(round(index[0],3), fontsize=16))

# cmap will generate a tuple of RGBA values for a given number in the range 0.0 to 1.0 
# (also 0 to 255 - not used in this example).
# To map our z values cleanly to this range, we create a Normalize object.
cmap      = matplotlib.cm.get_cmap('coolwarm')
normalize = matplotlib.colors.Normalize(vmin=min(data[:,2,-1]), vmax=max(data[:,2,-1]))
colors = [cmap(normalize(value)) for value in data[:,2,-1]]

ax1 = fig.add_subplot(111, projection='3d')
ax1.view_init(45,30)
ax1.set_xlabel('X (mm)')
ax1.set_ylabel('Y (mm)')
ax1.set_zlabel('Z Elevation (mm)')

data=df[df['Frame']==1]
graph = ax1.scatter(data.x, data.y, data.z, color=colors)

## Optionally add a colorbar
cax, _ = matplotlib.colorbar.make_axes(ax1, shrink=0.5)
cbar   = matplotlib.colorbar.ColorbarBase(cax, cmap=cmap, norm=normalize)

#Animation
ani = matplotlib.animation.FuncAnimation(fig, update_graph, samples, 
                               interval=40, blit=False)
plt.show()

在附件中,为问题的最后一帧定义了颜色图,其中U3max = 1和U3min = -1。例如,在第一步(帧= 0)期间,没有高程,因此,在“冷暖”比例下,图应为白色,但也应采用蓝色和红色。

欢迎任何建议。

预先感谢

1 个答案:

答案 0 :(得分:0)

最后,我得到了解决方案(感谢@ImportanceOfBeingErnest提供指导)。 所需步骤为: a)定义cmapnormalize变量以创建“全局颜色图” b)标准化每一帧的每个高度(Z)值,并将列表存储在数据帧的额外插槽中。 c)在update_graph(num)内部,使用scat.set_array(array)传递以前标准化的高度值。 d)使用c参数定义图形。 附件中,您可以看到最终代码。

#Python modules
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
import matplotlib.animation
import pandas as pd
from mpl_toolkits.mplot3d import Axes3D

###############################################################################
#Generate data
###############################################################################

np.random.seed(10) #To obtain the same result

n_radii  = 8
n_angles = 120

# Make radii and angles spaces (radius r=0 omitted to eliminate duplication).
radii = np.linspace(0.125, 1.0, n_radii)
angles = np.linspace(0, 2*np.pi, n_angles, endpoint=False)

# Repeat all angles for each radius.
angles = np.repeat(angles[..., np.newaxis], n_radii, axis=1)

# Convert polar (radii, angles) coords to cartesian (x, y) coords.
# (0, 0) is manually added at this stage,  so there will be no duplicate
# points in the (x, y) plane.
x = np.append(0, (radii*np.cos(angles)).flatten())
y = np.append(0, (radii*np.sin(angles)).flatten())

rows = len(x)
dim = 3
samples = 5

data = np.zeros((rows,dim,samples)) # (20 xyz) points stored in 10 sets 

for i in range(samples):
    data[:,0,i] = x
    data[:,1,i] = y
    # Compute z to make the pringle surface.
    data[:,2,i] = np.sin(-i*x*y)

index = np.arange(0,samples,1)

Frame = np.array([np.ones(rows)*index[i] for i in range(samples)]).flatten()

a = np.zeros((len(Frame),4))

for i in range(samples):
    a[i*rows:(i+1)*rows,0] = data[:,0,i]
    a[i*rows:(i+1)*rows,1] = data[:,1,i]
    a[i*rows:(i+1)*rows,2] = data[:,2,i]

# cmap will generate a tuple of RGBA values for a given number in the range 0.0 to 1.0 
# (also 0 to 255 - not used in this example).
# To map our z values cleanly to this range, we create a Normalize object.
cmap      = matplotlib.cm.get_cmap('coolwarm') #'viridis')#
normalize = matplotlib.colors.Normalize(vmin=min(a[:,2]), vmax=max(a[:,2]))

colors    = [cmap(normalize(value)) for value in data[:,2,-1]]
color_list= []

for i in range(samples):
   color_temp = [normalize(value) for value in data[:,2,i]]
   color_list = color_list + color_temp 

df = pd.DataFrame({"Frame": Frame ,"x" : a[:,0], "y" : a[:,1], "z" : a[:,2], "colors":color_list})

##############################################################################
#SCATTER PLOT
################################################################################

#Function to update my scatter plot
def update_graph(num):

    data_plot = df[df['Frame'] == index[num]]
    graph._offsets3d = (data_plot.x, data_plot.y, data_plot.z) #Update data
    graph.set_array(data_plot.colors) #Update colors

    title.set_text(r'How to update the color map for each plot based on the value of, Frame={}'.format(round(index[num],3)))

    return

#Limits of Elevation (U3) in data
print('U3_min',min(a[:,2]))
print('U3_max',max(a[:,2]))

#Define figure
fig = plt.figure(figsize=(10, 8), dpi=200)

title = plt.suptitle(r'How to update the color map for each plot based on the value of, Frame={}'.format(round(index[0],3), fontsize=16))

ax1 = fig.add_subplot(111, projection='3d')
ax1.view_init(45,30)
ax1.set_xlabel('X (mm)')
ax1.set_ylabel('Y (mm)')
ax1.set_zlabel('Z Elevation (mm)')

data_plot = df[df['Frame']==1]
graph     = ax1.scatter(data_plot.x, data_plot.y, data_plot.z, cmap=cmap, c=data_plot.colors, edgecolors='none')

## Optionally add a colorbar
cax, _ = matplotlib.colorbar.make_axes(ax1, shrink=0.5)
cbar   = matplotlib.colorbar.ColorbarBase(cax, cmap=cmap, norm=normalize, extend='both')

#Animation
ani = matplotlib.animation.FuncAnimation(fig, update_graph, frames = range(samples),) 


plt.show()