Graphing in Tkinter frame, updating info in Tkinter - python-2.7

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()

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)

Related

Tkinter - Multiple windows opening

Like the title says I'm having a problem with multiple windows being able to open. New window (same window) every time I click the button. I haven't been able to find an answer to this specific scenario. I've even tried disabling the button after opening window (which led to the problem of re-enabling).
Below is enough code to work with, you can see the problem by clicking the button a few times. I am hoping for a somewhat easy solution as I am fairly new to Tkinter. Also, the smaller window needs to resize (expand) with the main window, so I dont think a Toplevel window would work.
There may be others having this same problem, and thanks in advance!
Note: I'm using Python 2.7 (Tkinter)
#!/usr/bin/python
import os
import sys
import Tkinter as tk
from Tkinter import *
from ScrolledText import *
import tkFileDialog
import tkMessageBox
# Main
root = tk.Tk(className = "tex")
root.geometry("500x300")
root.title("tex")
tex = ScrolledText(root, padx=2, pady=2, undo=True, font=('Arial 11'))
def note_area():
btn_frame = Frame()
note = LabelFrame(tex, bd=1, relief='ridge')
tx = Text(note, width=18, relief='flat', padx=2, pady=2)
tx.insert('1.0', "Notes..")
tx.pack(side='top', fill=BOTH, expand=True)
note.pack(side='right', fill=Y)
btn_frame.pack(side='bottom', fill=Y)
# ToolBar Button (should only open one instance of note_area)
toolbar = Frame(root, bd=2, relief='groove')
b4 = Button(toolbar, text="Notes", width=4, command=note_area)
b4.pack(side=RIGHT, padx=4, pady=2)
toolbar.pack(side=TOP, fill=X)
tex.pack(fill="both", expand=True)
root.mainloop()
You just need make up a variable to keep track of if you have a note window open or not.
tex.notes_open = False
def note_area():
if tex.notes_open:
return # abort the function, notes already open
else:
tex.notes_open = True # set the flag for the next time
# rest of your code

Bokeh datetimetickformatter

I'm have some trouble with the DatetimeTickFormatter object from Bokeh. Plots randomly won't generate/update.
I have been searching and found this post at Bokeh, where it states that Plot not shown if DatetimeTickFormatter partially defined. I need some help with how to define it properly. Currently I'm doing this:
from bokeh.models.formatters import DatetimeTickFormatter
from bokeh.plotting import figure
DTF = DatetimeTickFormatter()
DTF.hours = ["%H:%M"]
DTF.days = ["%d/%m/%Y"]
DTF.months = ["%d/%m/%Y"]
DTF.years = ["%d/%m/%Y"]
and
p = figure()
p.xaxis.formatter = DTF
How should I define DTF “properly”?

How do you store the text inputs from the Entry widget into a list?

I've been trying to store it as a single string, let alone appending it to a list, by making a variable for it called "Whatisthisthing", but it's not working. Also, do you know why I can't use "Whatisthisthing" to replace Entry.get() with defining Showoncanvas?
import Tkinter
import random
master = Tkinter.Tk()
Entry = Tkinter.Entry()
Entry.pack()
Whatisthisthing = Entry.get()
Canvas = Tkinter.Canvas()
Canvas.pack()
def Showoncanvas(event):
Canvas.create_text(random.randint(10,100), random.randint(10,100), anchor = "center", text=Entry.get())
Entry.bind("<Return>", Showoncanvas)
print Whatisthisthing
master.mainloop()
An entry widget has an textvariable option in which the current text / content is stored. If you use a StringVar as the textvariable the content is automatically synched with this variable and can be read using StringVar's .get() method.
Since I do not have Python 2.7 installed on my system, I converted your code to Python 3 and used mentioned StringVar and its .get() method:
#!/usr/bin/env python3
# coding: utf-8
import tkinter
import random
master = tkinter.Tk()
Whatisthisthing = tkinter.StringVar()
Entry = tkinter.Entry(textvariable=Whatisthisthing)
Entry.pack()
Canvas = tkinter.Canvas()
Canvas.pack()
def Showoncanvas(event):
Canvas.create_text(random.randint(10,100), random.randint(10,100), anchor="center", text=Whatisthisthing.get())
Entry.bind("<Return>", Showoncanvas)
print(Whatisthisthing.get())
master.mainloop()
The only differences between Python 2 and Python 3 should be the following:
Tkinter --> tkinter
print --> print()

How to update the legend from matplotlib toolbar

I am defining a matplotlib plot for a given data. once the plot is displayed, I am trying to change some line property using navigation tool bar edit option.
When I make change say example solid line to dashdotted, the update get reflected on the lines, but the legends are not updated.
How can I capture this event when the apply button is clicked, so i can use this to refresh the legend. At the moment I am capturing a pick_event as a signal to refresh the legends.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
matplotlib.use('Qt4Agg')
x=np.linspace(0,100,100)
y=np.linspace(100,200,100)
plt.plot(x,y,label='test')
plt.legend()
ax.legend()
plt.show()
#optional code
def on_press(event):
lines, labels = ax.get_legend_handles_labels()
ax.legend(lines, labels, loc=0)
fig.canvas.draw()
cid = fig.canvas.mpl_connect('pick_event', on_press)
After a bit of struggle the only easy way to resolve this solution is to add legend refresh as part of the navigation tool bar call back function
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
def home_callback():
print "home called"
ax.legend()
x=np.linspace(0,100,100)
y=np.linspace(100,200,100)
fig=plt.figure()
ax=fig.add_subplot(111)
ax.plot(x,y,label='test')
ax.legend()
plt.show()
fm = plt.get_current_fig_manager()
fm.toolbar.actions()[0].triggered.connect(home_callback)

Save an animation at the final step as a figure

I wrote a script which animates the results I obtained, using matplotlib.
Besides the animation I got, I wanted to save the figure at the final step of the animation; just before the animation is repeated. I defined a save-flag, to avoid the figure being saved over and over. You can see the simplified version of my code below:
#!/usr/bin/env python
import numpy as np
from matplotlib import pyplot as plt
import matplotlib.animation as animation
x = np.array(range(12))
y = np.array([i**2 for i in range(12)])
fig = plt.figure()
ax = plt.axes(xlim = (0,15), ylim = (0,150))
line, = ax.plot([],[], 'o-')
def init():
line.set_data([], [])
return line,
save_flag = False
def animate(i):
i = (i+1)%(len(x)+1)
line.set_data(x[0:i], y[0:i])
global save_flag
if (save_flag == False) and (i == (len(x)-1)):
print "\nThe figure is being saved!\n"
fig.savefig("foo" + ".png")
save_flag = True
return line,
ani = animation.FuncAnimation(fig, animate, repeat=True, blit=True, init_func=init)
plt.show()
If you run the script, you will probably see that, at the end of the first loop, the the animation becomes erroneous. This error is due to the blit, which is set True. However, if it is set to False, then the figure repeats itself as it should be.
Why is there such a problem; could it be a bug? (My Python version is 2.7.5+.)
Is there a better way to save a figure at the end of an animation?