I'm creating a GUI in Tkinter that has an embedded matplotlib graph. I change the contents of the graph based on a couple of Radiobuttons. These Radiobuttons are linked to a function which redefines the data in the graph, and ends with a call to self.canvas.draw(). I used Unable to update Tkinter matplotlib graph with buttons and custom data substantially, and I got it to work perfectly: the graph is updated with the desired new data.
The problem I run into is that (I'm using dates for the x-tick labels) after the redraw function is called, the x-tick labels get rotated back to horizontal, causing them to overlap. Below is a simplified form of my application, which has no dependencies so can be run directly.
import tkinter
from tkinter import *
from tkinter.ttk import *
import csv
import datetime as dt
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
class MainApp:
def __init__(self,parent):
self.RightFrame = LabelFrame(parent,text='RightFrame')
self.RightFrame.pack(side='right')
self.plot_fig=plt.figure(figsize=(4,4),dpi=100)
self.fig = Figure()
self.ax = self.fig.add_subplot(111)
self.fig.autofmt_xdate(rotation=30) ### Sets tick rotation Initially
self.ax.fmt_xdata=mdates.DateFormatter('%Y-%m-%d')
self.ax.hold(False)
self.canvas = FigureCanvasTkAgg(self.fig,master=self.RightFrame)
self.canvas.show()
self.canvas.get_tk_widget().pack(side=TOP)
self.plot_radio_frame = LabelFrame(self.RightFrame)
self.plot_radio_frame.pack(side=BOTTOM)
self.plot_time_radio_var = IntVar()
self.plot_time_radio_var.set(7)
modes = [('1 Week',3),('1 Month',4),('1 Year',5),('5 Years',6),('All',0)]
for text,value in modes:
b= Radiobutton(self.plot_radio_frame,text=text,variable=self.plot_time_radio_var,value=value)
b.pack(side=LEFT)
self.plot_time_radio_var.trace('w',self.plotting_function)
def plotting_function(self, varname, elementname, mode):
plot_time = self.plot_time_radio_var.get()
try:
data_hist = [['2016-12-16',116.4700],
['2016-12-19',115.8000],
['2016-12-20',116.7400],
['2016-12-21',116.8000],
['2016-12-22',116.3500],
['2016-12-23',115.5900],
['2016-12-27',116.5200],
['2016-12-28',117.5200],
['2016-12-29',116.4500],
['2016-12-30',116.6500]
]
days = int(plot_time)
spacing = 1
dates = [line[0] for line in data_hist[-days::spacing]]
new_dates = [dt.datetime.strptime(d,'%Y-%m-%d').date() for d in dates]
Y_DATA = [line[1] for line in data_hist[-days::spacing]]
#print(adj_close)
self.curve = self.ax.plot(new_dates,Y_DATA)
self.canvas.draw()
except Exception as e:
print(str(e))
root = Tk()
MainApp(root)
root.mainloop()
Related
Newbie here, i am working on a program which allows the users to see the animation of spring extension after adjusting the slider(higher frequency=higher extension). However, based on what i did, the spring will move immediately after the slider is moved. How should i change my code so that the spring will show its extension from 0 to the desired length like a full animation?
from tkinter import *
import math
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
from matplotlib.figure import Figure
import matplotlib.patches as patches
window = Tk()
window.geometry("700x700")
window.configure(bg="white")
fig= Figure(figsize=(3, 3), dpi=100)
pg = fig.add_subplot(111)
def plot_graph():
pg.axis([0,800,-500,1000])
pg.get_yaxis().set_visible(False)
pg.set_title("Mass Spring Simulation ")
pg.set_xlabel("Spring extension (m)")
pg.set_ylabel("Displacement")
pg.grid()
def sine_graph():
pg.clear()
coorx=[]
coory=[]
for x in range(0,round(62.5*frequency)):
coorx.append(x)
y = amplitude*math.sin(x/(frequency))+250
coory.append(y)
rect = patches.Rectangle((coorx[-1], 0), 80,500, color='black')
pg.add_patch(rect)
Line= pg.plot(coorx,coory,label='Spring')
plot_graph()
fig.canvas.draw()
def update_fre(value):
global frequency
frequency = slider2.get()
sine_graph()
amplitude,frequency = 250,1
canvas = FigureCanvasTkAgg(fig, window)
canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)
toolbar = NavigationToolbar2Tk(canvas,window)
toolbar.update()
L2 = Label(window,text="Force")
L2.pack()
slider2 = Scale(window,from_=1,to=10,orient=HORIZONTAL,command=update_fre)
slider2.pack()
sc= Label(window,text="Spring Constant = 0.0143N/m")
sc.pack()
sine_graph()
window.mainloop()
what i have tried (clearing the page and redrawing),but my computer will crash automatically when adjusting slider:
def sine_graph():
pg.clear()
coorx=[]
coory=[]
z=1
for i in range (frequency):
for x in range(1,round(62.5*z)):
pg.clear()
coorx.append(x)
y = amplitude*math.sin(x/(frequency))+250
coory.append(y)
z+=1
I need help, I am trying to figure out why the style i chose in mplfinance is not working when I plot it into a tkinter canvas plot.
This is my code:
from tkinter import *
import datetime as dt
import yfinance as yf
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
import mplfinance as mpf
gui = Tk()
gui.geometry("800x700")
stock = 'SPY'
end = dt.datetime.now()
start = end - dt.timedelta(days=6)
df = yf.download(stock.upper(), start, end, interval = '5m')
def Plot_data(type='candle', grid= '-', style='nightclouds'):
fig = plt.Figure(figsize=(7,5), dpi=100)
chart = fig.add_subplot(111)
chart_canvas = FigureCanvasTkAgg(fig, master=gui)
chart_canvas.get_tk_widget().place(relx = .05, rely=.25)
s = mpf.make_mpf_style(base_mpf_style=style, gridstyle=grid)
mpf.plot(df, ax= chart, type = type, style = s)
Plot_data()
mainloop()
#Plotting it without tkinter and without the lines "" fig = plt.Figure()/
#chart = fig.add_subplot(111)"" works just fine,
#this is the customization I want in the tkinter window. Thank you.
def Plot_data(type='candle', grid= '', style='nightclouds'):
s = mpf.make_mpf_style(base_mpf_style=style, gridstyle=grid)
mpf.plot(df, type = type, style = s)
Plot_data()```
The the style you chose in mplfinance is not working because you have created the Figure object external to mplfinance.
Instead of fig = plt.Figure(figsize=(7,5), dpi=100), try
def Plot_data(type='candle', grid= '-', style='nightclouds'):
s = mpf.make_mpf_style(base_mpf_style=style, gridstyle=grid)
fig = mpf.figure(figsize=(7,5), dpi=100, style=s)
You can then remove the style= kwarg from the call to mpf.plot().
I'm trying to place a pie chart inside the Tkinter frame with an absolute positioning.
How do I place the pie at the upper left side of the frame?
So far I tried:
from tkinter import *
from PIL import Image, ImageTk
import datetime as dt
import time
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
class Dashboard:
def __init__(self, filterdDf):
self.filterdDf = filterdDf
root =Tk()
root.title('Dashboard')
root.geometry('1300x1000')
root.resizable(False, False)
frame = Frame(root, width=1000, height=680)
frame.configure(background="gray28")
frame.pack(fill=BOTH, expand=True)
frameChartsLT = Frame(root)
frameChartsLT.pack()
fig = Figure() # create a figure object
ax = fig.add_subplot(111) # add an Axes to the figure
ax.pie(filterdDf[('Sum', '')], radius=1, shadow=True)
chart1 = FigureCanvasTkAgg(fig, frameChartsLT)
chart1.get_tk_widget().pack()
root.mainloop()
Thanks!
I have the following code:
from tkinter import *
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
class tkPlot:
def __init__(self,master):
frame = Frame(master)
frame.pack()
canvasSubFrame=Frame(frame)
canvasSubFrame.grid(row=0, column=0)
f = Figure(figsize=(8,8), dpi=100)
subplotA = f.add_subplot(211)
subplotA.set_title("Plot A")
subplotB = f.add_subplot(212)
subplotB.set_title("Plot B")
subplotA.plot([1,2,3,4,5,6],[1,4,9,16,25,36])
subplotB.plot([1,2,3,4,5,6],[1,1/2,1/3,1/4,1/5,1/6])
canvas = FigureCanvasTkAgg(f, master=canvasSubFrame)
canvas.draw()
canvas.get_tk_widget().pack(expand=False)
if __name__ == "__main__":
root = Tk()
app = tkPlot(root)
root.mainloop()
Ideally, i would like to have a textbox or spin control besides every top and bottom of each subplot to set the y axes min and max scales (y limits)
What is the proper way to do this. It should work for any number of subplots.
I was wondering if anyone had an idea as to why the code below does not display a graph with a line in it after the button on the GUI is pressed. I would like to create a program that executes a long list of commands after a set of data is imported by clicking a button. One of these commands would be to display the spectral data on a graph within the same window. Here is what I have so far:
# import modules that I'm using
import matplotlib
matplotlib.use('TKAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import matplotlib.pyplot as pltlib
import Tkinter
from Tkinter import *
import numpy as np
import scipy as sc
#import matplotlib.pyplot as pltlib
# lmfit is imported becuase parameters are allowed to depend on each other along with bounds, etc.
from lmfit import minimize, Parameters, Minimizer
#Make object for application
class App_Window(Tkinter.Tk):
def __init__(self,parent):
Tkinter.Tk.__init__(self,parent)
self.parent = parent
self.initialize()
def initialize(self):
button = Tkinter.Button(self,text="Open File",command=self.OnButtonClick).pack(side=Tkinter.TOP)
self.canvasFig=pltlib.figure(1)
Fig = matplotlib.figure.Figure(figsize=(5,4),dpi=100)
FigSubPlot = Fig.add_subplot(111)
x=[]
y=[]
self.line1, = FigSubPlot.plot(x,y,'r-')
self.canvas = matplotlib.backends.backend_tkagg.FigureCanvasTkAgg(Fig, master=self)
self.canvas.show()
self.canvas.get_tk_widget().pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=1)
self.canvas._tkcanvas.pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=1)
self.resizable(True,False)
self.update()
def refreshFigure(self,x,y):
self.line1.set_xdata(x)
self.line1.set_ydata(y)
self.canvas.draw()
def OnButtonClick(self):
# file is opened here and some data is taken
# I've just set some arrays here so it will compile alone
x=[]
y=[]
for num in range(0,1000):x.append(num*.001+1)
# just some random function is given here, the real data is a UV-Vis spectrum
for num2 in range(0,1000):y.append(sc.math.sin(num2*.06)+sc.math.e**(num2*.001))
X = np.array(x)
Y = np.array(y)
self.refreshFigure(X,Y)
if __name__ == "__main__":
MainWindow = App_Window(None)
MainWindow.mainloop()
That is because the range of xaxis & yaxis doesn't change to new data's range, change your refreshFigure as following:
def refreshFigure(self,x,y):
self.line1.set_data(x,y)
ax = self.canvas.figure.axes[0]
ax.set_xlim(x.min(), x.max())
ax.set_ylim(y.min(), y.max())
self.canvas.draw()