我试图在Plotly for Python中绘制几个不同颜色的表面。
具体地说,表面显示了在相空间中不同点处采取动作的预测奖励函数。由于我在每个点上都有几种可能的操作,因此每个表面都是不同的。我想对每个表面进行唯一着色,但与x,y或z坐标无关。
我尝试遵循R中的答案,但是我无法弄清楚自己做错了什么。我总是得到相同的蓝色。由于我在代码的其他部分中使用了PyPlot,因此我从默认的matplotlib表中选择颜色。
这是玩具数据的基本示例。
import matplotlib.pyplot as plt
import numpy as np
import plotly.graph_objs as go
import plotly.offline as off
off.init_notebook_mode()
make_int = np.vectorize(int)
cmap = plt.get_cmap("tab10")
saddle = np.array([[x**2-y**2 for x in np.arange(-10,11)] for y in np.arange(-10,11)])
paraboloid = np.array([[x**2 + y**2-100 for x in np.arange(-10,11)] for y in np.arange(-10,11)])
mycolors_a = make_int(256*np.array(cmap(1)[0:3])).reshape((1, 1,-1)).repeat(21, axis = 0).repeat(21, axis =1)
mycolors_b = make_int(256*np.array(cmap(2)[0:3])).reshape((1, 1,-1)).repeat(21, axis = 0).repeat(21, axis =1)
trace_a = go.Surface(z = saddle, surfacecolor = mycolors_a, opacity = .7, showscale = False, name = "Trace A")
trace_b = go.Surface(z = paraboloid, surfacecolor = mycolors_b, opacity = .7, showscale = False, name = "Trace B")
data = [trace_a, trace_b]
off.iplot(data)
产生以下内容:
我应该看到一个蓝色的鞍和一个橙色的抛物面,但是我没有。请注意,即使将参数更改为cmap
,我也始终获得相同的蓝色。感谢您的帮助!
答案 0 :(得分:4)
documentation在这里有点神秘。
surfacecolor
(列表,numpy数组或Pandas系列的数字,字符串或日期时间。)
设置表面颜色值,用于设置独立于
z
的色标。
我从来没有设法放入一个字符串列表,例如'rgb(0.3,0.5,0)'或RGB元组之类的颜色值。
但是您可以使用所需的颜色定义自己的色阶。
colorscale = [[0, 'rgb' + str(cmap(1)[0:3])],
[1, 'rgb' + str(cmap(2)[0:3])]]
,然后提供一个数字数组,其尺寸与绘制的值相同。
colors_saddle = np.zeros(shape=saddle.shape)
所有值均设置为0
,因此将映射到colorscale
中的第一种颜色。下一种颜色也一样。
此外,您需要手动设置cmax
和cmin
。
完整代码
import numpy as np
import matplotlib.pyplot as plt
import plotly.graph_objs as go
import plotly.offline as off
off.init_notebook_mode()
make_int = np.vectorize(int)
cmap = plt.get_cmap("tab10")
saddle = np.array([[x**2-y**2 for x in np.arange(-10,11)] for y in np.arange(-10,11)])
paraboloid = np.array([[x**2 + y**2-100 for x in np.arange(-10,11)] for y in np.arange(-10,11)])
colors_saddle = np.zeros(shape=saddle.shape)
colors_paraboloid = np.ones(shape=paraboloid.shape)
colorscale = [[0, 'rgb' + str(cmap(1)[0:3])],
[1, 'rgb' + str(cmap(2)[0:3])]]
trace_a = go.Surface(z=saddle,
surfacecolor=colors_saddle,
opacity=.7,
name="Trace A",
cmin=0,
cmax=1,
colorscale=colorscale)
trace_b = go.Surface(z=paraboloid,
surfacecolor=colors_paraboloid,
opacity=.7,
name="Trace B",
cmin=0,
cmax=1,
showscale=False,
colorscale=colorscale)
data = [trace_a, trace_b]
off.iplot(data)
答案 1 :(得分:0)
您可以将所有表面合并为一个,并在每个表面的色标范围内进行设置 它还可以解决重叠问题,因此您会清楚地看到曲面的线相交like here
import numpy as np
import plotly.graph_objs as go
# normalize values to range [start,end] for getting color from cmap
def norm_v_in_range(v,start,end):
v_min = v.min()
v_max = v.max()
range_length = (end - start)
if v_min-v_max == 0 :
v.fill(range_length/5 + start)
return v
return (v-v_min)/(v_max-v_min)*range_length + start
def combine_all_surfaces_in_one(X,Y,*Z) :
# prepare colors and ranges for diffrent surfaces
colors = [ 'rgb(180, 110, 20)', 'rgb( 20, 180, 110)', 'rgb(110, 20, 180)',
'rgb(180, 180, 20)', 'rgb( 20, 180, 180)', 'rgb(180, 20, 180)',
'rgb(180, 20, 20)', 'rgb( 20, 180, 20)', 'rgb( 20, 20, 180)',
'rgb(180, 110, 20)', 'rgb( 20, 180, 110)', 'rgb(110, 20, 180)',
'rgb(255, 127, 127)', 'rgb(127, 255, 127)']
N = len(Z)
points = np.linspace(0, 1, N + 1)
custom_colorscale = []
ranges = []
for i in range(1,N+1) :
ranges.append([points[i-1],points[i]-0.05])
custom_colorscale.append([points[i-1], colors[i]])
custom_colorscale.append([points[i]-0.05,'rgb(255, 250, 220)'])
custom_colorscale.append([1, 'rgb(220, 250, 220)'])
# transparent connection between grahps: np.nan in z prevent ploting points
transparen_link = np.empty_like(X[0], dtype=object)
transparen_link.fill(np.nan)
# include first graph
combined_X = X
combined_Y = Y
combined_Z = Z[0]
# prepare collor matrix for first graph (Z[0])
start = ranges[0][0]
end = ranges[0][1]
custom_surfacecolor = norm_v_in_range(Z[0],start,end)
# second aray combined with first in backward direction, so connection would on one side of graphs, not intersect them
direction = -1
range_index = 1
for next_Z in Z[1:] :
combined_X = np.vstack([combined_X, combined_X[-1], X[::direction][0], X[::direction][0], X[::direction]])
combined_Y = np.vstack([combined_Y, combined_Y[-1], Y[::direction][0], Y[::direction][0], Y[::direction]])
combined_Z = np.vstack([combined_Z, combined_Z[-1], transparen_link, next_Z[::direction][0], next_Z[::direction]])
# prepare collors for next Z_
start = ranges[range_index][0]
end = ranges[range_index][1]
next_surfacecolor = norm_v_in_range(next_Z,start,end)
custom_surfacecolor = np.vstack([custom_surfacecolor,custom_surfacecolor[-1], transparen_link, next_surfacecolor[::direction][0], next_surfacecolor[::direction]])
# change direction
direction *= -1
range_index += 1
return combined_X, combined_Y, combined_Z, custom_surfacecolor, custom_colorscale
X = np.arange(-1.2, 1.06, 0.1)
Y = np.arange(0.2, 1.06, 0.1)
X, Y = np.meshgrid(X, Y)
Z1 = 2*np.sin(np.sqrt(20*X**2+20*Y**2))
Z2 = 2*np.cos(np.sqrt(20*X**2+20*Y**2))
Z3 = X*2+0.5
Z4 = Y*0+1.0
Z5 = Y*0-1.0
Z6 = Y*0+0.0
x,y,z,custom_surfacecolor,custom_colorscale = combine_all_surfaces_in_one(X,Y,Z1,Z2,Z3,Z4,Z5)
# opacity =0.9 - many overlaped areas, better witot it
fig = go.Figure(data=[go.Surface(x=x, y=y, z=z,
surfacecolor=custom_surfacecolor, cmin=0, cmax = 1,
colorscale=custom_colorscale,showscale=False,
)] )
fig.show()