
This project extends our Tkinter real-time data tracker by adding a dynamic Matplotlib graph. The user selects a stock or index, opens a monitoring window and views the latest available intraday values as a time-series graph.
Python threading performs the external data request without blocking Tkinter. A Queue transfers the result back to the GUI thread, where the Labels and graph are updated safely.
Main Tkinter window
|
+--> Select stock
|
v
Stock monitoring window
|
+--> Worker thread
| |
| v
| Fetch data
| |
| v
| Queue
| |
+--------+
|
v
Tkinter main thread
|
+--> Update price
+--> Update time
+--> Draw Matplotlib graph
+--> Schedule next fetch
Show Table of Contents
The application has one main Tkinter window containing a read-only Combobox and a Button.
When the user selects a stock and clicks Monitor Stock, Python opens a new Toplevel window containing:
The user can return to the main window and open another stock. Each monitoring window keeps its own graph data and update schedule.
Tkinter, threading and Queue are available with Python. Install the packages required for retrieving and graphing the data:
pip install yfinance
pip install matplotlib
A Python dictionary connects the readable company or index name shown in the Combobox with the ticker required by the data source.
stock_options={
'Reliance Industries':'RELIANCE.NS',
'Tata Consultancy Services (TCS)':'TCS.NS',
'Infosys':'INFY.NS',
'HDFC Bank':'HDFCBANK.NS',
'ICICI Bank':'ICICIBANK.NS',
'State Bank of India (SBI)':'SBIN.NS',
'Bharti Airtel':'BHARTIARTL.NS',
'Adani Enterprises':'ADANIENT.NS',
'NSE Nifty 50 Index':'^NSEI',
'BSE Sensex Index':'^BSESN'
}
The Combobox displays the dictionary keys while Python obtains the matching ticker from the selected key.
The fetching function contains no Tkinter or Matplotlib operations.
def fetch_stock_price(ticker):
stock=yf.Ticker(ticker)
data=stock.history(
period='1d',
interval='1m'
)
if data.empty:
raise ValueError(
'No intraday data was returned.'
)
close_values=data['Close'].dropna()
if close_values.empty:
raise ValueError(
'No price data is available.'
)
price=float(close_values.iloc[-1])
timestamp=close_values.index[-1]
return price,timestamp
The function returns both the value and the timestamp associated with that returned data point.
A Toplevel window lets the application monitor more than one stock without creating another Tk root window.
monitor=tk.Toplevel(root)
monitor.title(
f'{stock_name} Tracker'
)
monitor.geometry(
'850x600'
)
Each monitoring window gets its own:
This is important because one stock window should not control another stock window.
The older version called the plotting function directly from its background thread. Because the Matplotlib canvas is embedded in Tkinter, drawing should be performed from the Tkinter main thread.
The revised worker does only this:
def fetch_worker():
try:
price,timestamp=fetch_stock_price(
ticker
)
result_queue.put(
(
'ok',
price,
timestamp
)
)
except Exception as e:
result_queue.put(
(
'error',
str(e),
None
)
)
The worker never calls:
canvas.draw()
price_var.set()
status_var.set()
monitor.after()
The Queue is checked using Tkinter's after() method.
When a successful result arrives, the main thread adds the new point and redraws the graph.
timestamps.append(
plot_time
)
prices.append(
price
)
ax.clear()
ax.plot(
timestamps,
prices,
marker='o'
)
canvas.draw_idle()
draw_idle() requests a redraw without forcing unnecessary immediate repeated rendering.
A monitor might remain open for several hours. The example keeps only the latest 60 values in memory:
MAX_POINTS=60
if len(timestamps)>MAX_POINTS:
timestamps= timestamps[-MAX_POINTS:]
prices=prices[-MAX_POINTS:]
This prevents an ever-growing graph while the application is running.
The source request uses one-minute intraday data, so the example refreshes once per minute:
REFRESH_MS=60000
After processing the current result:
state['fetch_after']=monitor.after(
REFRESH_MS,
start_fetch
)
There is no continuous while True loop and no time.sleep(5).
The main window remains available after a monitoring window opens.
For example, the user can open:
Reliance Industries
State Bank of India
NSE Nifty 50 Index
Each receives its own Toplevel window and its own independent update state.
This is different from using one global stop_event for every stock window.
When one monitoring window is closed, its scheduled Tkinter callbacks are cancelled.
def on_close():
state['closed']=True
for key in (
'fetch_after',
'poll_after'
):
after_id=state[key]
if after_id is not None:
try:
monitor.after_cancel(
after_id
)
except tk.TclError:
pass
monitor.destroy()
A worker that is already waiting for a network response is a daemon thread and performs no GUI operations. If it finishes after the window closes, its Queue result is simply no longer processed.
The background worker only retrieves data. It never calls canvas.draw().
Closing the SBI monitor does not stop Reliance or Nifty monitoring.
Each Toplevel manages its own Queue and scheduled callbacks.
One worker performs one request. Tkinter schedules the next request after the result is processed.
The example waits 60 seconds before requesting the next one-minute observation.
The plotted x-axis uses the timestamp associated with the returned price rather than simply calling datetime.now().
Only the latest 60 observations are retained in memory for each monitoring window.
Several useful applications can grow from this project.
Store each successful observation in SQLite and reopen it later in Treeview. This is covered in our Tkinter SQLite stock data project.
Add upper and lower thresholds and display an alert when the latest value crosses one of them.
Use the collected list or a Pandas Series to calculate short moving averages and plot them with the current values.
The same architecture can be adapted for weather readings, sensors, server monitoring, database statistics or other periodically changing data.
The external request can take time. A worker thread keeps the Tkinter event loop responsive while Python waits for the result.
The Matplotlib canvas is embedded in Tkinter, so graph and widget updates should be performed by the Tkinter main thread.
Yes. Each selected stock opens in a separate Toplevel window with its own Queue, data lists, graph and update schedule.
Its scheduled callbacks are cancelled and that monitoring window is destroyed. Other stock windows continue operating independently.
The example requests one-minute intraday data, so repeatedly requesting the same source every five seconds is usually unnecessary.
The limit prevents each open window from continuously increasing its in-memory graph data during a long monitoring session.
No. The application plots the latest available intraday value returned by the source. Availability and delays can vary.
Author & Instructor at plus2net
I write and maintain practical tutorials on Python, PHP, SQL, JavaScript, HTML, jQuery, and web development at plus2net. The tutorials focus on clear explanations, working examples, and code that readers can test and adapt while learning.