У меня есть два разных графика matplotlib, которые я хотел бы переключать при нажатии кнопки. Код, который я имею, добавит второй график ниже первого графика, когда кнопка нажата, но я хочу, чтобы он заменил первый график. Это в некоторой степени похожий вопрос stackoverflow ( Как обновить matplotlib, встроенный в 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()
в def_graphs switch, чтобы очистить первый график, но это не работает. Любая помощь будет оценена.
Я публикую обновленный код, чтобы показать небольшой прогресс, которого я достиг, а также чтобы лучше представить различную природу двух графиков, между которыми я хочу переключиться. Оба графика все еще являются простыми графиками, взятыми непосредственно из документации по 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 здесь не применима. Когда я пытаюсь отобразить графики, все, что я получаю, это пустой рисунок. Вот код, который я использую для построения графика свечи. Это будет соответствовать 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()
Как бы я изменил это, чтобы оно показывало данные?