Tkinter Real-Time Stock Graph with Matplotlib

Tkinter Matplotlib graph displaying latest available stock price data

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.

Stock data note: The values returned by yfinance are the latest available intraday values from the upstream source. They are not guaranteed to be exchange-level real-time prices.
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

What We Will Build Top ↑

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 selected stock name;
  • the latest returned value;
  • the source timestamp;
  • a Matplotlib time-series graph;
  • a status message.

The user can return to the main window and open another stock. Each monitoring window keeps its own graph data and update schedule.

Real-Time Stock Price Graph in Tkinter with Matplotlib

Install Required Libraries Top ↑

Tkinter, threading and Queue are available with Python. Install the packages required for retrieving and graphing the data:

pip install yfinance
pip install matplotlib

Stock Selection Dictionary Top ↑

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.

Fetch the Latest Available Price Top ↑

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.

Create a Separate Monitoring Window Top ↑

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:

  • Queue;
  • price list;
  • timestamp list;
  • Matplotlib Figure;
  • refresh timer;
  • closed/open state.

This is important because one stock window should not control another stock window.

Worker Thread and Queue Top ↑

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

Update Matplotlib from the Tkinter Main Thread Top ↑

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.

Limit the Number of Graph Points

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.

Schedule the Next Fetch Top ↑

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

Monitor Multiple Stocks at the Same Time Top ↑

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.

Close One Monitoring Window Safely Top ↑

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.

Complete Multi-Stock Monitoring Program Top ↑

How This Version Improves the Earlier Program Top ↑

Matplotlib Is Updated on the Main Thread

The background worker only retrieves data. It never calls canvas.draw().

Each Window Has Independent State

Closing the SBI monitor does not stop Reliance or Nifty monitoring.

No Global stop_event Is Shared by Every Window

Each Toplevel manages its own Queue and scheduled callbacks.

No Infinite Worker Loop

One worker performs one request. Tkinter schedules the next request after the result is processed.

No Five-Second Polling of One-Minute Data

The example waits 60 seconds before requesting the next one-minute observation.

The Graph Uses the Source Timestamp

The plotted x-axis uses the timestamp associated with the returned price rather than simply calling datetime.now().

The Graph Does Not Grow Indefinitely

Only the latest 60 observations are retained in memory for each monitoring window.

Next Steps Top ↑

Several useful applications can grow from this project.

Save the Graph Data

Store each successful observation in SQLite and reopen it later in Treeview. This is covered in our Tkinter SQLite stock data project.

Add Price Alerts

Add upper and lower thresholds and display an alert when the latest value crosses one of them.

Add Moving Averages

Use the collected list or a Pandas Series to calculate short moving averages and plot them with the current values.

Use Other Data Sources

The same architecture can be adapted for weather readings, sensors, server monitoring, database statistics or other periodically changing data.

The most reusable part of this project is the architecture: external request in a worker thread, Queue for communication, and all Tkinter/Matplotlib updates on the main GUI thread.

Frequently Asked Questions Top ↑

Q1: Why use a worker thread for stock data?

The external request can take time. A worker thread keeps the Tkinter event loop responsive while Python waits for the result.

Q2: Why is Matplotlib not updated from the worker thread?

The Matplotlib canvas is embedded in Tkinter, so graph and widget updates should be performed by the Tkinter main thread.

Q3: Can several stocks be monitored at once?

Yes. Each selected stock opens in a separate Toplevel window with its own Queue, data lists, graph and update schedule.

Q4: What happens when one stock window is closed?

Its scheduled callbacks are cancelled and that monitoring window is destroyed. Other stock windows continue operating independently.

Q5: Why refresh every 60 seconds?

The example requests one-minute intraday data, so repeatedly requesting the same source every five seconds is usually unnecessary.

Q6: Why keep only 60 points on the graph?

The limit prevents each open window from continuously increasing its in-memory graph data during a long monitoring session.

Q7: Is the plotted stock price guaranteed to be real-time?

No. The application plots the latest available intraday value returned by the source. Availability and delays can vary.


Real-Time Stock Tracker Store Stock Data in SQLite

More Projects using Tkinter


Subscribe to our YouTube Channel here



plus2net.com







Python Video Tutorials
Python SQLite Video Tutorials
Python MySQL Video Tutorials
Python Tkinter Video Tutorials
We use cookies to improve your browsing experience. . Learn more
HTML MySQL PHP JavaScript ASP Photoshop Articles Contact us
©2000-2026   plus2net.com   All rights reserved worldwide Privacy Policy Disclaimer