使用matplotlib.widgets.Button更改轴范围

时间:2020-11-10 15:38:00

标签: matplotlib matplotlib-widget

我有一个绘图,其中x轴包含datetime.datetime个对象。我正在尝试使用多个matplotlib.widgets.Button来更改x轴的范围。一个按钮显示所有日期时间,而另一个按钮仅显示最后两秒钟。单击一个按钮后,该按钮应变为绿色,而另一个按钮应变为红色。

下面是一个显示我的问题的最小工作示例。有两种情况:

  1. 运行脚本。单击“仅显示最后两秒钟”。作品。然后单击“显示所有时间”。作品。此时,“仅显示最后两秒钟”停止工作。
  2. 运行脚本。点击“显示所有时间”。作品。然后单击“仅显示最后两秒钟”。这什么也没做。

我添加了一些打印语句(在最小的工作示例中作了注释)以尝试找出问题所在。看起来当一个按钮被激活时,另一个按钮并没有立即被取消激活,这正是本意。也就是说,在activated循环中将False属性设置为while并不能正常工作。按钮的颜色也有问题。

如何修改最小工作示例以产生预期的行为?随时提出其他修改建议。

#!/usr/bin/env python3

from datetime import datetime
from datetime import timedelta
from matplotlib.widgets import Button
import matplotlib.pyplot as plt
import random

class ButtonClickProcessor:
    def __init__(self, axes, label):
        self.button = Button(axes, label, color = 'red')
        self.button.on_clicked(self.process)
        self.activated = False
    def process(self, event):
        self.activated = True
        self.button.color = 'green'
        plt.gcf().canvas.draw()
        #print('ButtonClickProcessor.process', self.activated)

def main():

    start_time = datetime.now()

    fig, axes = plt.subplots()
    datetimes = []
    y_values = []

    button_show_all_times = ButtonClickProcessor(axes = plt.axes([0.0, 0.0, 0.5, 0.1]), label = 'Show all times')
    button_show_only_last_2_seconds = ButtonClickProcessor(axes = plt.axes([0.5, 0.0, 0.5, 0.1]), label = 'Show only last 2 seconds')

    while True:
        #print('Start of while True; button_show_all_times', button_show_all_times.activated)
        #print('Start of while True; button_show_only_last_2_seconds', button_show_only_last_2_seconds.activated)
        now = datetime.now()
        datetimes.append(now)
        y_values.append(random.randint(a = 0, b = 10))

        axes.plot(datetimes, y_values)

        time_difference = now - start_time
        if time_difference.total_seconds() > 2:
            delta = timedelta(seconds = 2)

            if button_show_all_times.activated is True:
                button_show_only_last_2_seconds.activated = False
                button_show_only_last_2_seconds.button.color = 'red'
                fig.canvas.draw()
                axes.set_xlim(left = datetimes[0])
                #print('button_show_all_times.activated is True:', button_show_all_times.activated, button_show_only_last_2_seconds.activated)
            if button_show_only_last_2_seconds.activated is True:
                button_show_all_times.activated = False
                button_show_all_times.button.color = 'red'
                fig.canvas.draw()
                axes.set_xlim(left = now - delta)
                #print('button_show_only_last_2_seconds.activated', button_show_all_times.activated, button_show_only_last_2_seconds.activated)

        fig.tight_layout(rect = [0, 0.1, 1, 1])
        plt.pause(0.0001)
        axes.clear()

    plt.show()

if __name__ == '__main__':
    main()

1 个答案:

答案 0 :(得分:0)

以防将来有人偶然发现此问题,下面是我的解决方案。我最终通过all_buttons属性使每个按钮了解所有按钮。这解决了激活我单击的按钮并同时停用其他按钮的问题。为了更改颜色,关键要素是button.ax.set_facecolor方法。没有这个,在我移动鼠标之前按钮的颜色不会改变。这样,一旦我单击按钮,颜色就会改变。我不知道这是最好还是最有效的解决方案,但是它有效。我仍然愿意提出改进建议。

#!/usr/bin/env python3

from datetime import datetime
from datetime import timedelta
from matplotlib.widgets import Button
import matplotlib.pyplot as plt
import random

class ButtonClickProcessor:
    def __init__(self, axes, label):
        self.button = Button(ax = axes, label = label, color = 'red', hovercolor = 'red')
        self.button.on_clicked(self.process)
        self.activated = False
        self.all_buttons = None
    def process(self, event):
        for button in self.all_buttons:
            button.activated = False
            button.button.color = 'red'
            button.button.hovercolor = button.button.color
            button.button.ax.set_facecolor(button.button.color)
        self.activated = True
        self.button.color = 'green'
        self.button.hovercolor = self.button.color
        self.button.ax.set_facecolor(self.button.color)
        self.button.ax.figure.canvas.draw()

def main():

    start_time = datetime.now()

    fig, axes = plt.subplots()
    datetimes = []
    y_values = []

    button_show_all_times = ButtonClickProcessor(axes = plt.axes([0.01, 0.01, 0.5, 0.1]), label = 'Show all times')
    button_show_only_last_2_seconds = ButtonClickProcessor(axes = plt.axes([0.5, 0.01, 0.49, 0.1]), label = 'Show only last 2 seconds')
    all_buttons = (button_show_all_times, button_show_only_last_2_seconds)
    button_show_all_times.all_buttons = all_buttons
    button_show_only_last_2_seconds.all_buttons = all_buttons

    while True:
        now = datetime.now()
        datetimes.append(now)
        y_values.append(random.randint(a = 0, b = 10))

        axes.plot(datetimes, y_values)

        time_difference = now - start_time
        if time_difference.total_seconds() > 2:
            delta = timedelta(seconds = 2)

            if button_show_all_times.activated is True:
                axes.set_xlim(left = datetimes[0])
            if button_show_only_last_2_seconds.activated is True:
                axes.set_xlim(left = now - delta)

        fig.tight_layout(rect = [0, 0.1, 1, 1])
        plt.pause(0.0001)
        axes.clear()

    plt.show()

if __name__ == '__main__':
    main()