Python:如何在Tkinter中正确嵌入matplotlib?

时间:2018-10-15 03:31:41

标签: python matplotlib tkinter

在此先感谢您的宝贵帮助! 我无法在tkinter中嵌入matplotlib。你可以引导我吗?

我已经导入了所有正确的模块 matplotlib.pyplot,matplotlib.dates,FigureCanvasTkAgg,NavigationToolbar2Tk,key_press_handler,Figure等。

然后...

root = tk.Tk()
root.wm_title("Embedding in Tk")

def bytespdate2num(fmt, encoding ='utf-8'):
    strconverter = mdates.strpdate2num(fmt)
    def bytesconverter(b):
        s = b.decode(encoding)
        return strconverter(s)
    return bytesconverter 

def graph_data(stock):
    fig = plt.figure()
    ax1 = plt.subplot2grid((1,1), (0,0))
    url_stock = 'https://pythonprogramming.net/yahoo_finance_replacement'
    source_code = urllib.request.urlopen(url_stock).read().decode()
    stock_data = []
    source_split = source_code.split('\n')

    for line in source_split[1:]:
        line_split = line.split(',')
        if len(line_split) == 7:
            if 'values' not in line and 'labels' not in line:
                stock_data.append(line)
    date, closep, highp, lowp, openp, adj_closep, volume = np.loadtxt(stock_data, delimiter =',', unpack= True, converters={0: bytespdate2num('%Y-%m-%d')})

    ax1.plot_date(date, closep, '-', label ='closing price')
    ax1.axhline(closep[0], color='k', linewidth = 2)
    ax1.fill_between(date, closep, closep[0], where=(closep > closep[0]), facecolor='g', alpha=0.5)
    ax1.fill_between(date, closep, closep[0], where=(closep < closep[0]), facecolor ='r', alpha = 0.5)
    ax1.xaxis.label.set_color('c')
    ax1.yaxis.label.set_color('r')
    ax1.set_yticks([0,100,200,300,400,500,600,700,800,900,1000])

    for label in ax1.xaxis.get_ticklabels():
        label.set_rotation(45)
    ax1.grid(True, color= 'r', linestyle='-', linewidth=0.5)

    plt.subplots_adjust(left = 0.09, bottom =0.18, right= 0.94, top= 0.95, wspace=0.2, hspace=0)
    plt.title('stock')
    plt.xlabel('dates')
    plt.ylabel('price')
    plt.legend()
    plt.show()

这是我认为阻碍的地方

    canvas = FigureCanvasTkAgg(fig, master= root)  # A tk.DrawingArea.
    canvas.draw()
    canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)

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

graph_data('EBAY')
tk.mainloop()

再次感谢您;)

1 个答案:

答案 0 :(得分:1)

从您提供的代码中很难完全理解问题。如果您可以更准确地了解错误/问题的性质或发布完整的代码,则可能会更容易获得帮助。

基本思想是,当您嵌入到tkinter中时,不足以使用matplotlib方法(plt.show)显示图像,但是还需要创建canvas元素并在其上绘制图像。因此,我猜应该修改方法graph_data(stock):的最后一部分,例如包括matplotlib(代码here)中的方法draw_figure

def draw_figure(canvas, figure, loc=(0, 0)):
""" Draw a matplotlib figure onto a Tk canvas

loc: location of top-left corner of figure on canvas in pixels.
Inspired by matplotlib source: lib/matplotlib/backends/backend_tkagg.py
"""
  figure_canvas_agg = FigureCanvasAgg(figure)
  figure_canvas_agg.draw()
  figure_x, figure_y, figure_w, figure_h = figure.bbox.bounds
  figure_w, figure_h = int(figure_w), int(figure_h)
  photo = tk.PhotoImage(master=canvas, width=figure_w, height=figure_h)

  # Position: convert from top-left anchor to center anchor
  canvas.create_image(loc[0] + figure_w/2, loc[1] + figure_h/2, image=photo)

  # Unfortunately, there's no accessor for the pointer to the native renderer
  tkagg.blit(photo, figure_canvas_agg.get_renderer()._renderer, colormode=2)

  # Return a handle which contains a reference to the photo object
  # which must be kept live or else the picture disappears
  return photo

def graph_data(stock, canvas): 
  # do you really need stock parameter? it is not used
  fig = plt.figure()
  ax1 = plt.subplot2grid((1,1), (0,0))
  url_stock = 'https://pythonprogramming.net/yahoo_finance_replacement'
  source_code = urllib.request.urlopen(url_stock).read().decode()
  stock_data = []
  source_split = source_code.split('\n')

  for line in source_split[1:]:
    line_split = line.split(',')
    if len(line_split) == 7:
        if 'values' not in line and 'labels' not in line:
            stock_data.append(line)
  date, closep, highp, lowp, openp, adj_closep, volume = np.loadtxt(stock_data, delimiter =',', unpack= True, converters={0: bytespdate2num('%Y-%m-%d')})

  ax1.plot_date(date, closep, '-', label ='closing price')
  ax1.axhline(closep[0], color='k', linewidth = 2)
  ax1.fill_between(date, closep, closep[0], where=(closep > closep[0]), facecolor='g', alpha=0.5)
  ax1.fill_between(date, closep, closep[0], where=(closep < closep[0]), facecolor ='r', alpha = 0.5)
  ax1.xaxis.label.set_color('c')
  ax1.yaxis.label.set_color('r')
  ax1.set_yticks([0,100,200,300,400,500,600,700,800,900,1000])

  for label in ax1.xaxis.get_ticklabels():
    label.set_rotation(45)
  ax1.grid(True, color= 'r', linestyle='-', linewidth=0.5)

  plt.subplots_adjust(left = 0.09, bottom =0.18, right= 0.94, top= 0.95, wspace=0.2, hspace=0)
  plt.title('stock')
  plt.xlabel('dates')
  plt.ylabel('price')
  plt.legend()
  plt.show()

  fig_x, fig_y = 100, 100
  fig_photo = draw_figure(canvas, fig, loc=(fig_x, fig_y))
  fig_w, fig_h = fig_photo.width(), fig_photo.height()

因此,它仅使用您创建的画布并在其上绘制在matplotlib中绘制的图像。很难确定它是否已经可以像这样工作,或者是否需要进行少量编辑,因为我看不到整个代码,但这应该会给您一个提示。

我可以向您指出完整的文档,其中提供了有关如何在tkinter中嵌入一个图像的简单示例, https://matplotlib.org/gallery/user_interfaces/embedding_in_tk_canvas_sgskip.html 您可以尝试使用它作为测试

或通过使用PIL库转换图像(这是我使用的解决方案),然后将其转换为Tkinter(转换后更直接)的另一种方式https://solarianprogrammer.com/2018/04/20/python-opencv-show-image-tkinter-window/