0

So I am currently working on a basic stock program, and I have been able to get my graphs (of stock data from the last month) on my tkinter window any tips on how to actively update my tkinter window would be great! (FYI I am very new to programming, this is my first year, so please try to explain in basic terms!) Heres my code:

import numpy as np
import datetime as dt
import yahoo_finance as yf
import matplotlib.pyplot as plt
from Tkinter import *
import quandl

from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg


root=Tk()
root.geometry('1400x875')
root.title("Stock Information")


fmain=Frame(root, width=1400, height=900, bg='orange',bd=5)
fmain.place(x=100, y=0)

today=dt.date.today()

thirty_day_graph_frame=Frame(fmain, width=645, height=400,bg='green4',bd=5)
thirty_day_graph_frame.place(x=0, y=444)

thirty_days=dt.timedelta(days=43)   
thirty_days_ago=today-thirty_days


five_yrs_graph_frame=Frame(fmain, width=645, height=400, bg='yellow2',bd=5)
five_yrs_graph_frame.place(x=655, y=444)


five_years=dt.timedelta(days=1825)
five_years_ago=today-five_years


def stock_info(stock_name):


    stock=yf.Share(stock_name)
    stock_price=stock.get_price()

    name_price_label=Label(fmain, text=(stock_name,':', stock_price),font=("Times New Roman",23))
    name_price_label.place(x=400, y=10)

    day_high=quandl.get("WIKI/"+str(stock_name)+".2",start_date=str(today),end_date=str(today))

    high_price_label=Label(fmain, text=(str(day_high)), font=("Times New Roman",20))
    high_price_label.place(x=400, y=100)


    thirty_day_data = quandl.get("WIKI/"+str(stock_name), start_date=str(thirty_days_ago), end_date=str(today),column_index=4) #So quandl.get gives a lot of info, so the column_index=4 is just getting closing prices
    five_year_data = quandl.get("WIKI/"+str(stock_name),start_date=str(five_years_ago), end_date=str(today), column_index=4)


    thirty_day_fig = plt.figure(figsize=(8,4)) 
    plt.plot(thirty_day_data)
    canvas = FigureCanvasTkAgg(thirty_day_fig, master=thirty_day_graph_frame)
    plot_widget = canvas.get_tk_widget()
    plot_widget.place(x=0,y=0)


    five_year_fig=plt.figure(figsize=(8,4))
    plt.plot(five_year_data)
    canvas1=FigureCanvasTkAgg(five_year_fig, master=five_yrs_graph_frame)
    plot_widget1=canvas1.get_tk_widget()
    plot_widget1.place(x=1,y=0)
    root.after(5000, stock_info, stock_name)

apple_button=Button(root,text='AAPL', command=lambda:stock_info('AAPL'))
tesla_button=Button(root,text='TSLA', command=lambda:stock_info('TSLA'))
google_button=Button(root,text='GOOG', command=lambda:stock_info('GOOG'))


apple_button.place(x=10, y=15)
tesla_button.place(x=10, y=45)
google_button.place(x=10,y=75)

root.mainloop()
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
Addison
  • 403
  • 8
  • 24

1 Answers1

2

The reason your graphs are plotted from the start is because of the way you assign commands to your buttons. One way to fix this is to assign the command as a lambda expression:

apple_button = Button(root, text='AAPL', command=lambda:stock_info('AAPL'))

To let your GUI update itself over time, you can create a loop using the root.after() method:

# Define the figure and canvas outside the loop
fig = plt.Figure()
a = fig.add_subplot(111)
canvas = FigureCanvasTkAgg(fig, master=f1)
canvas.get_tk_widget().grid()

def stock_info(stock_name):
    # Get stock data and plot it on the GUI
    ...
    a.cla()
    a.plot(data)
    canvas.draw()

    # Schedule the function to call itself again after 5 seconds
    root.after(5000, stock_info, stock_name)
Josselin
  • 2,593
  • 2
  • 22
  • 35
  • thanks thats really cool! it seems to work, however my graphs sort of flicker when I do that. Is there a way to prevent that? Ill update my code on this thread as I haven't in a while so you can see what I have – Addison May 25 '17 at 00:51
  • You're welcome :) Your graphs flicker because you keep destroying and recreating your frames... To prevent this, create your frames, canvases and labels outside the `stock_info()` method, and only **update** them inside (like I did in my answer) – Josselin May 25 '17 at 10:50
  • well when I get rid of the recreation of the window in my function, and bring the .after() into the function, it seems to refresh at random intervals, and it switches stocks randomly. Run my code and you can see. Ill update it – Addison May 25 '17 at 14:06
  • You have to move your `thirty_day_fig`, `five_year_fig`, `canvas` and `canvas1` also outside the function. And add a subplot to each figure like `a = fig.add_subplot(111)` in my answer, so you can update the figures without having to recreate them each time. – Josselin May 25 '17 at 14:54
  • I see. Could I just do root.after(5000,stock.refresh())? My graphs are more long term so it won't matter to update those. – Addison May 25 '17 at 15:04
  • Sure, put in your refresh function what you want to update. Then let your refresh function call **itslef** with the `after()` method. – Josselin May 25 '17 at 15:20