python 在3D交互式matplotlib网格上为静态轴添加颜色条

cuxqih21  于 2023-05-05  发布在  Python
关注(0)|答案(1)|浏览(140)

我正在使用matplotlib创建一个交互式3D图,并且在添加功能性颜色条时遇到了一些困难。我给了颜色条自己的轴,这样它就不会随着3D网格旋转。初始图和颜色条正确生成,但是,在第一次与滑块交互时,颜色条消失。在下一次交互时,绘制的数据也消失。这似乎是由于cb.remove()命令。如果cb.remove()命令不存在,则颜色条将在每次交互时简单地绘制自己,使图中有许多杂乱的颜色条堆叠在一起。我创建了colorbar作为它自己的对象,它应该在每个更新的滑块值上重新生成,所以我不太明白为什么它不会重新生成,或者为什么它也会删除绘制的数据。
下面是一些代码来重现这个问题。

import matplotlib.pyplot as plt
from matplotlib.widgets import Slider, Button
import matplotlib.cm as cm
from matplotlib.colors import Normalize
import numpy as np
%matplotlib notebook

class InteractivePlot:
    def __init__(self):
        self.fig = plt.figure(layout='constrained')
        self.ax = self.fig.add_subplot(111, projection='3d')
        #initalize plot
        self.cmap = cm.get_cmap('Blues')
        x = np.random.randint(1, 3, size=(4, 4)) 
        normalizer=Normalize(np.min(x),np.max(x))
        im=cm.ScalarMappable(norm=normalizer, cmap=self.cmap)
        
        self.cax_pos = [0.93, 0.15, 0.02, 0.7] # left, bottom, width, height
        self.cax = self.fig.add_axes(self.cax_pos)
        self.cb = self.fig.colorbar(im, cax=self.cax)

        self.X, self.Y = np.meshgrid(np.linspace(0,1,x.shape[1]), np.linspace(0,1,x.shape[0]))
        self.ax.contourf(x, self.X, self.Y, offset=0, cmap=self.cmap)
        #Create buttons to increment and decrement iteration slider
        self.button1 = Button(plt.axes([0.85, 0.01, 0.05, 0.05]), '-', hovercolor='white')
        self.button2 = Button(plt.axes([0.9, 0.01, 0.05, 0.05]), '+', hovercolor='white')
        
        slider_ax = plt.axes([0.15, 0.01, 0.6, 0.03])
        self.slider = Slider(slider_ax, 'Upper lim', 1, 10, valinit=3, valstep=1)
        self.slider.on_changed(self.update)
        self.button1.on_clicked(self.update)
        self.button2.on_clicked(self.update)
        

    def update(self, val):
        self.ax.clear()
        self.cb.remove()
        
        def increment_slider(event):
            self.slider.set_val(self.slider.val + self.slider.valstep)
        def decrement_slider(event):
            self.slider.set_val(self.slider.val - self.slider.valstep)
        self.button1.on_clicked(decrement_slider)
        self.button2.on_clicked(increment_slider)

        self.x = np.random.randint(1, self.slider.val, size=(4, 4)) 
        normalizer=Normalize(np.min(self.x),np.max(self.x))
        im=cm.ScalarMappable(norm=normalizer, cmap=self.cmap)
        self.ax.contourf(self.x, self.X, self.Y, offset=0, zdirs='z', cmap=self.cmap)
        self.cb = self.fig.colorbar(im, cax=self.cax)
        self.fig.canvas.draw_idle()
        plt.show()
vql8enpb

vql8enpb1#

我已经解决了这个问题,但将离开这个情况下,其他人有类似的问题。由于某些原因,将colorbar轴初始化到类会在从update函数调用它们时导致此问题。相反,您必须在更新函数中独立定义轴及其位置。我不确定调用self.cax是否会导致这个问题,但这里有一些更新的代码,可以按预期工作

import matplotlib.pyplot as plt
from matplotlib.widgets import Slider, Button
import matplotlib.cm as cm
from matplotlib.colors import Normalize
import numpy as np
%matplotlib notebook

class InteractivePlot:
    def __init__(self):
        self.fig = plt.figure(layout='constrained')
        self.ax = self.fig.add_subplot(111, projection='3d')
        #initalize plot
        self.cmap = cm.get_cmap('Blues')
        x = np.random.randint(1, 3, size=(4, 4)) 
        normalizer=Normalize(np.min(x),np.max(x))
        im=cm.ScalarMappable(norm=normalizer, cmap=self.cmap)
        
        cax_pos = [0.93, 0.15, 0.02, 0.7] # left, bottom, width, height
        cax = self.fig.add_axes(cax_pos)
        self.cb = self.fig.colorbar(im, cax=cax)

        self.X, self.Y = np.meshgrid(np.linspace(0,1,x.shape[1]), np.linspace(0,1,x.shape[0]))
        self.ax.contourf(x, self.X, self.Y, offset=0, cmap=self.cmap)
        #Create buttons to increment and decrement iteration slider
        self.button1 = Button(plt.axes([0.85, 0.01, 0.05, 0.05]), '-', hovercolor='white')
        self.button2 = Button(plt.axes([0.9, 0.01, 0.05, 0.05]), '+', hovercolor='white')
        
        slider_ax = plt.axes([0.15, 0.01, 0.6, 0.03])
        self.slider = Slider(slider_ax, 'Upper lim', 1, 10, valinit=3, valstep=1)
        self.slider.on_changed(self.update)
        self.button1.on_clicked(self.update)
        self.button2.on_clicked(self.update)
        

    def update(self, val):
        self.ax.clear()
        self.cb.remove()
        
        def increment_slider(event):
            self.slider.set_val(self.slider.val + self.slider.valstep)
        def decrement_slider(event):
            self.slider.set_val(self.slider.val - self.slider.valstep)
        self.button1.on_clicked(decrement_slider)
        self.button2.on_clicked(increment_slider)

        self.x = np.random.randint(1, self.slider.val, size=(4, 4)) 
        normalizer=Normalize(np.min(self.x),np.max(self.x))
        im=cm.ScalarMappable(norm=normalizer, cmap=self.cmap)
        self.ax.contourf(self.x, self.X, self.Y, offset=0, zdirs='z', cmap=self.cmap)
        cax_pos = [0.93, 0.15, 0.02, 0.7] # left, bottom, width, height
        cax = self.fig.add_axes(cax_pos)
        self.cb = self.fig.colorbar(im, cax=cax)
        self.fig.canvas.draw_idle()
        plt.show()

相关问题