如何在Matplotlib中使用按钮在两个不同的图形之间切换

时间:2019-01-10 15:29:45

标签: python matplotlib

我有两个不同的matplotlib图形,我想在按下按钮时进行切换。当按下按钮时,我拥有的代码会将第二个图形添加到第一个图形下方,但是我希望它替换第一个图形。这是一个有点类似的stackoverflow问题(How to update a matplotlib embedded into tkinter?),但我似乎无法将其应用于我的情况。

我编写的图形graph_one和graph_two是我从matplotlib文档中提取的两个简单图形。在我的实际使用中,我有两个非常不同的非常复杂的图,一个是单个图,另一个是另外的子图。因为我希望在图之间来回切换的图是如此不同,所以对我来说很重要的一点是,该解决方案能够将图输入作为单独的定义来处理。还应注意,我的图嵌入在tkinter小部件中,解决方案也应考虑此嵌入,这一点很重要。 这是我的代码:

import matplotlib
matplotlib.use("TkAgg")
import matplotlib.pyplot as plt
import numpy as np
from tkinter import *
from matplotlib.backends.backend_tkagg import (
    FigureCanvasTkAgg, NavigationToolbar2Tk)
# Implement the default Matplotlib key bindings.
from matplotlib.backend_bases import key_press_handler



def graph_one():
    t = np.arange(0.0, 2.0, 0.01)
    s = 1 + np.sin(2 * np.pi * t)

    fig, ax = plt.subplots()
    ax.plot(t, s)

    ax.set(xlabel='time (s)', ylabel='voltage (mV)',
           title='Graph One')

    #plt.show()
    return fig


def graph_two():
    t = np.arange(0.0, 2.0, 0.01)
    s = 1 + np.cos(2 * np.pi * t)

    fig, ax = plt.subplots()
    ax.plot(t, s)

    ax.set(xlabel='time (s)', ylabel='voltage (mV)',
           title='Graph Two')

    #plt.show()
    return fig

class matplotlibSwitchGraphs:
    def __init__(self, master):
        self.master = master
        self.frame = Frame(self.master)
        self.embed_graph_one()
        self.frame.pack(expand=YES, fill=BOTH)

    def embed_graph_one(self):

        fig = graph_one()

        canvas = FigureCanvasTkAgg(fig, self.master)  
        canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)
        canvas.draw()

        canvas.mpl_connect("key_press_event", self.on_key_press)

        toolbar = NavigationToolbar2Tk(canvas, self.master)
        toolbar.update()
        canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)


        self.button = Button(self.master, text="Quit", 
command=self._quit)
        self.button.pack(side=BOTTOM)
        self.button_switch = Button(self.master, text="Switch Graphs", 
command=self.switch_graphs)
        self.button_switch.pack(side=BOTTOM)

    def embed_graph_two(self):

        fig = graph_two()

        canvas = FigureCanvasTkAgg(fig, self.master)  
        canvas.draw()
        canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)

        canvas.mpl_connect("key_press_event", self.on_key_press)

        toolbar = NavigationToolbar2Tk(canvas, self.master)
        toolbar.update()
        canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)


        self.button = Button(self.master, text="Quit", 
command=self._quit)
        self.button.pack(side=BOTTOM)
        self.button_switch = Button(self.master, text="Switch Graphs", 
command=self.switch_graphs)
        self.button_switch.pack(side=BOTTOM)


    def on_key_press(event):
        print("you pressed {}".format(event.key))
        key_press_handler(event, canvas, toolbar)

    def _quit(self):
        self.master.quit()  # stops mainloop

    def switch_graphs(self):
        self.embed_graph_two()

def main():
    root = Tk()
    matplotlibSwitchGraphs(root)
    root.mainloop()



if __name__ == '__main__':
    main()

看来我应该可以使用

这样的命令
ax.clear()
在switch_graphs def中的

可以清除第一个图形,但这不起作用。任何帮助将不胜感激。

我正在发布更新的代码,以显示我所取得的一些小进展,以及更好地表示我希望在其间切换的两个图表的不同性质。这两个图仍然是直接从matplotlib文档中直接获取的简单图,但是它们更好地表示我的一个图是单个图,而第二个图则有两个图直接位于彼此之上。

在我的实际情况下,我试图使用一个按钮来在带有交易量重叠的烛台图表和没有交易量重叠的烛台图表之间切换。发布所有代码以显示烛台图将花费很长的代码,因此我通过使用这些更简单的图形对其进行了简化。为了简单起见,我还取消了matplotlib的导航工具栏。这是我修改后的代码:

import matplotlib
matplotlib.use("TkAgg")
import matplotlib.pyplot as plt
import numpy as np
from tkinter import *
from matplotlib.backends.backend_tkagg import (
    FigureCanvasTkAgg, NavigationToolbar2Tk)
# Implement the default Matplotlib key bindings.
from matplotlib.backend_bases import key_press_handler



class matplotlibSwitchGraphs:
    def __init__(self, master):
        self.master = master
        self.frame = Frame(self.master)
        self.embed_graph_one()
        self.frame.pack(expand=YES, fill=BOTH)

    # the def creates the first matplotlib graph
    def graph_one(self):
        t = np.arange(0.0, 2.0, 0.01)
        s = 1 + np.sin(2 * np.pi * t)

        fig, ax = plt.subplots()
        ax.plot(t, s)

        ax.set(xlabel='time (s)', ylabel='voltage (mV)',
               title='Graph One')

        # plt.show()
        return fig, ax

    # This def creates the second matplotlib graph that uses subplot
    # to place two graphs one on top of the other
    def graph_four(self):
        x1 = np.linspace(0.0, 5.0)
        y1 = np.cos(2 * np.pi * x1) * np.exp(-x1)
        fig = plt.figure()
        ax = plt.subplot2grid((5, 4), (0, 0), rowspan=4, colspan=4)
        ax.plot(x1, y1, 'o-')

        means_men = (20, 35, 30, 35, 27)
        std_men = (2, 3, 4, 1, 2)
        ax2 = plt.subplot2grid((5, 4), (4, 0), sharex=ax, rowspan=1, 
colspan=4)
        ax2.bar(std_men, means_men, color='green', width=0.5, 
align='center')

        return fig, ax

    # this def takes graph one and embeds it in a tkinter widget
    def embed_graph_one(self):

        fig, ax = self.graph_one()

        canvas = FigureCanvasTkAgg(fig, self.master)  
        canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)
        canvas.draw()

        canvas.mpl_connect("key_press_event", self.on_key_press)


        self.button = Button(self.master, text="Quit", 
command=self._quit)
        self.button.pack(side=BOTTOM)
        self.button_switch = Button(self.master, text="Switch Graphs", 
command=lambda: self.switch_graphs(canvas, fig, ax))
        self.button_switch.pack(side=BOTTOM)


    # This def takes the second graph and embeds it in a tkinter 
    # widget
    def embed_graph_two(self):

        fig, ax = self.graph_two()

        canvas = FigureCanvasTkAgg(fig, self.master)  
        canvas.draw()
        canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)

        canvas.mpl_connect("key_press_event", self.on_key_press)


        self.button = Button(self.master, text="Quit", 
command=self._quit)
        self.button.pack(side=BOTTOM)
        self.button_switch = Button(self.master, text="Switch Graphs", 
command=lambda: self.switch_graphs(canvas, fig, ax))
        self.button_switch.pack(side=BOTTOM)

    # the def defines the key press event handler
    def on_key_press(event):
        key_press_handler(event, canvas, toolbar)

    # This def quits the tkinter widget 
    def _quit(self):
        self.master.quit()  # stops mainloop

    # This def switches between the two embedded graphs
    def switch_graphs(self, fig, canvas, ax):
        ax.clear()
        self.embed_graph_two()
        canvas.draw()




def main():
    root = Tk()
    matplotlibSwitchGraphs(root)
    root.mainloop()



if __name__ == '__main__':
    main()

此代码仍然不会用第二张图替换第一张图,而只是将第二张图放在第一张图的下方。对于获得此代码以用第二个图形替换第一个图形的任何帮助,将不胜感激。

我要绘制的图形是OHLC烛台图和带有体积叠加层的OHLC烛台图。不幸的是

self.canvas.draw()
draw_graph defs中的

命令似乎在这里不适用。当我尝试显示图形时,我得到的只是一个空白图。这是我使用的绘制烛台图的代码。这将对应于draw_graph_one。

def ohlc_daily_date_axis(self, stock_sym):
    mondays = WeekdayLocator(MONDAY)  # major ticks on the mondays
    alldays = DayLocator()  # minor ticks on the days
    weekFormatter = DateFormatter('%b %d %Y')  # e.g., Jan 12 2018
    dayFormatter = DateFormatter('%d')  # e.g., 12

    quotes = get_stock_price_data_list_of_tuples(stock_sym)
    graph_header_text = 'Daily OHLC Candlestick Chart: ' + stock_sym + ' Date Range: ' + str(
        num2date(quotes[0][0]).date()) + ' - ' + str(num2date(quotes[-1][0]).date())

    if len(quotes) == 0:
        raise SystemExit

    self.fig, self.ax = plt.subplots(figsize=(18, 5))
    plt.subplots_adjust(bottom=0.2)
    self.ax.xaxis.set_major_locator(mondays)
    self.ax.xaxis.set_minor_locator(alldays)
    self.ax.xaxis.set_major_formatter(weekFormatter)
    # ax.xaxis.set_minor_formatter(dayFormatter)
    plt.title(graph_header_text)
    self.ax.set_ylabel('Share Price ($)', size=10)

    # plot_day_summary(ax, quotes, ticksize=3)
    candlestick_ohlc(self.ax, quotes, width=0.6)

    self.ax.xaxis_date()
    self.ax.autoscale_view()
    plt.setp(plt.gca().get_xticklabels(), rotation=45, horizontalalignment='right')
    self.ax.format_coord = self.get_ohlc_from_date_xy
    # ax.fmt_xdata = get_ohlc_from_date_x

    #plt.show()
    self.canvas.draw() 

我将如何修改它以使其显示数据?

2 个答案:

答案 0 :(得分:1)

包含Tk嵌入的新答案(与其他答案相比有重大变化,因此添加新答案而不是编辑该答案)。我将<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <button class="delivery1">5</button> <span id=nextday data-price=5></span>graph_one()移到了开关图包装器类中,并将它们重命名为graph_two()draw_graph_one()。这两个新的类方法替换了draw_graph_two()embed_graph_one()方法。 embed_graph_two()方法中的大多数内容都是重复的,因此被移动到embed()方法中,该方法在实例化类对象时被调用。创建了一些类数据成员以捕获plt变量(例如config_window()canvasax),并创建了一个新的数据成员以跟踪当前显示的图形({{1 }}),这样我们就可以在调用fig时正确绘制正确的图形(而不是像原始代码那样每次进行“ switch”调用时都调用graphIndex)。 (可选)您可以从switch_graphs()方法中取出embed_graph_two()并将其设为类数据成员(如果t的值不变)。

draw

输出(两个窗口,每当单击切换图按钮时交替显示): enter image description here

答案 1 :(得分:0)

从matplotlib的documentation on buttonsstackoverflow question you linked开始,这是实现您所要表达的基础知识的代码。抱歉,我没有使用您的代码,但是它太大了。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Button

# Button handler object
class Index(object):
    ind = 0

    # This function is called when bswitch is clicked
    def switch(self, event):
        self.ind = (self.ind+1) % len(functions)
        ydata = 1 + functions[self.ind](2 * np.pi * t)
        l.set_ydata(ydata)
        ax.set(title='Graph '+str(self.ind + 1))
        plt.draw()

    # This function is called when bquit is clicked
    def quit(self, event):
        plt.close()

# Store the functions you want to use to plot the two different graphs in a list
functions = [np.sin, np.cos]

# Adjust bottom to make room for Buttons
fig, ax = plt.subplots()
plt.subplots_adjust(bottom=0.25)

# Get t and s values for Graph 1
t = np.arange(0.0, 2.0, 0.01)
s = 1 + np.sin(2 * np.pi * t)

# Plot Graph 1 and set axes and title
l, = plt.plot(t, s, lw=2)
ax.set(xlabel='time (s)', ylabel='voltage (mV)',
           title='Graph 1')

# Initialize Button handler object
callback = Index()

# Connect to a "switch" Button, setting its left, top, width, and height
axswitch = plt.axes([0.40, 0.07, 0.2, 0.05])
bswitch = Button(axswitch, 'Switch graph')
bswitch.on_clicked(callback.switch)

# Connect to a "quit" Button, setting its left, top, width, and height
axquit = plt.axes([0.40, 0.01, 0.2, 0.05])
bquit = Button(axquit, 'Quit')
bquit.on_clicked(callback.quit)

# Show
plt.show()

结果:

enter image description here

单击“切换图”,您将得到:

enter image description here