简体   繁体   中英

How to update the facecolors in a mplot3d object?

I'm trying to create a 3D surface plot whose facecolors values can be interactively updated through sliders. It is worth noting that in my case the facecolors values don't have anything to do with the coordinates position of the surface. The surface is there only to represent a certain geometry, and the facecolors are the values mapped into that geometry.

As a basic example, I tried to create a plane with the facecolors are provided by a function of an euclidean distance to a given center. The center is the parameter that I will be able to adjust through the sliders. Here is my code:

from numpy import pi, sin
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm, colors
from matplotlib.widgets import Slider, Button, RadioButtons

def signal(amp, freq):
    return amp * sin(2 * pi * freq * t)

axis_color = 'lightgoldenrodyellow'

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

# Adjust the subplots region to leave some space for the sliders and buttons
fig.subplots_adjust(bottom=0.25)

x = np.linspace(0.0, 1.0, num=50)
y = np.linspace(0.0, 1.0, num=50)
t = np.linspace(0.0, 1.0, num=50)
x, y = np.meshgrid(x, y)
z = 1.0 * x + 2.0 * y
def colormapping_values(x_center, y_center):
    return (x-x_center)**2 + (y-y_center)**2

x0 = 0.5
y0 = 0.5
norm = colors.Normalize()
somtethin = cm.jet(norm(colormapping_values(x0, y0)))
surf = ax.plot_surface(x, y, z, facecolors=somtethin)
# Draw the initial plot
# The 'line' variable is used for modifying the line later

# Add two sliders for tweaking the parameters

# Define an axes area and draw a slider in it
x_center_slider_pos  = fig.add_axes([0.15, 0.15, 0.65, 0.03], facecolor=axis_color)
x_center_slider = Slider(x_center_slider_pos, 'X center', 0.0, 1.0, valinit=x0)

# Draw another slider
y_center_slider_pos = fig.add_axes([0.15, 0.1, 0.65, 0.03], facecolor=axis_color)
y_center_slider = Slider(y_center_slider_pos, 'Y center', 0.0, 1.0, valinit=y0)
# Define an action for modifying the line when any slider's value changes
def sliders_on_changed(val):
    print(cm.jet(colormapping_values(x_center_slider.val, y_center_slider.val)).shape)
    surf.set_facecolors(cm.jet(colormapping_values(x_center_slider.val, y_center_slider.val)))
    fig.canvas.draw_idle()
x_center_slider.on_changed(sliders_on_changed)
y_center_slider.on_changed(sliders_on_changed)

# Add a button for resetting the parameters
reset_button_ax = fig.add_axes([0.8, 0.025, 0.1, 0.04])
reset_button = Button(reset_button_ax, 'Reset', color=axis_color, hovercolor='0.975')
def reset_button_on_clicked(mouse_event):
    y_center_slider.reset()
    x_center_slider.reset()
reset_button.on_clicked(reset_button_on_clicked)

plt.show()

The initial plot is correct, however when I click the slider, I get a "ValueError: Invalid RGBA argument", in the line "surf.set_facecolors(cm.jet(colormapping_values(x_center_slider.val, y_center_slider.val)))". I suppose I am doing something wrong when using that function. I've done my research, but I have not yet come to a conclusion of what I am doing wrong, as the use is almost identical to what I am doing when I pass the parameter facecolors

You need to give a 1D array or list of colours to .set_facecolors() , rather than the 2D array you are currently giving it.

To do this, reshape your array to something with the shape ((len(x)-1 * len(y)-1), 4) . (note that the 4 is for the 4-channel colour value).

c_len = (len(x)-1 * len(y)-1)

def sliders_on_changed(val):
    print(cm.jet(colormapping_values(x_center_slider.val, y_center_slider.val)).shape)
    surf.set_facecolors(
            cm.jet(colormapping_values(x_center_slider.val, y_center_slider.val)
                )[:-1, :-1].reshape(c_len, 4))
    surf.set_edgecolors(
            cm.jet(colormapping_values(x_center_slider.val, y_center_slider.val)
                )[:-1, :-1].reshape(c_len, 4))    
    fig.canvas.draw_idle()

Note you also need to set the edgecolors in the same way.

Testing this out with some different slider values:

在此处输入图片说明 在此处输入图片说明 在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM