Python Forum
User Interaction with Graph in GUI
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
User Interaction with Graph in GUI
#2
Instead of a calculate button, the code below binds the plot update method to changes made in any of the entries. Insead of repeating the code three times for the three Entry widgets U made a special Entry class that does the binding. By making a new class, it was easy to add input validation and a value property.
import tkinter as tk
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import (
    FigureCanvasTkAgg, NavigationToolbar2Tk)


class Entry(tk.Entry):
    """Special tk Entry for numbers with a command callback."""
    def __init__(self, *args, command=None, **kwargs):
        super().__init__(*args, width=10, justify=tk.RIGHT, **kwargs)
        self.command = command
        self.bg = self["bg"]
        self.var = tk.StringVar(self, "0")
        self.var.trace_add("write", self._validate)
        self.configure(textvariable=self.var)

    def _validate(self, *_):
        """Set red background if text is inalid, else call command."""
        if self.value is None:
            self["bg"] = "red"
        else:
            self["bg"] = self.bg
            if self.command:
                self.command()

    @property
    def value(self):
        """Return value as number or None if text is not valid str."""
        try:
            return float(self.var.get())
        except ValueError:
            pass
        return None

    @value.setter
    def value(self, new_value):
        """Set value."""
        self.var.set(str(new_value))
        self._validate


class App(tk.Tk):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.wm_title("DGA Analysis Tool Using Duval Triangle")
        self.hold = False

        tk.Label(self, text="C2H2").grid(row=0, column=0, sticky="e")
        self.c2h2 = Entry(self, command=self.plot)
        self.c2h2.grid(row=0, column=1, sticky="w")

        tk.Label(self, text="C2H4").grid(row=0, column=2, sticky="e")
        self.c2h4 = Entry(self, command=self.plot)
        self.c2h4.grid(row=0, column=3, sticky="w")

        tk.Label(self, text="CH4").grid(row=0, column=4, sticky="e")
        self.ch4 = Entry(self, command=self.plot)
        self.ch4.grid(row=0, column=5, sticky="w")

        fig, self.ax1 = plt.subplots()
        self.ax1.grid(linestyle='--', alpha=0.4, axis='both')
        self.ax1.set_xlim(0, 600)
        self.ax1.set_ylim(0, 550)
        self.canvas = FigureCanvasTkAgg(fig, self)
        self.canvas.get_tk_widget().grid(row=1, column=0, columnspan=6)
        self.toolbar = NavigationToolbar2Tk(
            self.canvas, self, pack_toolbar=False
        )
        self.toolbar.grid(row=2, column=0, columnspan=6, sticky="news")
        self.plot()

    def plot(self):
        """Update plot to show new sample point."""
        # Don't plot if held or an input is invalid.
        sample_point = self.c2h2.value, self.c2h4.value, self.ch4.value
        if self.hold or None in sample_point:
            return

        # Changing the sample point forces clearing the axis.
        # Need to create the regions and labels even though they
        # don't change.
        self.ax1.clear()
        AT = np.transpose(
            np.array([[5, 2.5, 50], [0, 5 * np.sqrt(3)/2, 50], [0, 0, 1]])
        )

        v = np.array([
            [0, 0, 1], [0, 100, 1], [100, 0, 1], [0, 87, 1], [0, 96, 1],
            [0, 98, 1], [2, 98, 1], [23, 0, 1], [23, 64, 1], [20, 76, 1],
            [20, 80, 1], [40, 31, 1], [40, 47, 1], [50, 35, 1], [50, 46, 1],
            [50, 50, 1], [71, 0, 1], [85, 0, 1]
        ]) @ AT
        for color, region in (
            ('#2e962d', v[[5, 1, 6], :]),
            ('#bebe12', v[[4, 5, 6, 10, 9], :]),
            ('#ff642b', v[[9, 10, 15, 14], :]),
            ('#b46414', v[[13, 15, 2, 17], :]),
            ('#10b4a7', v[[0, 3, 8, 7], :]),
            ('#121eb4', v[[7, 8, 12, 11, 16], :]),
            ('#f217d0', v[[3, 4, 14, 13, 17, 16, 11, 12], :])
        ):
            self.ax1.fill(region[:, 0], region[:, 1], color)

        for label, x, y in (
            ('%C2H2', 45, -5), ('0', 95, -5), ('100', 5, -5),
            ('%CH4', -10, 55), ('0', -7, 5), ('100', -7, 95),
            ('%C2H4', 45, 55), ('0', 5, 95), ('100', 95, 5)
        ):
            x, y, _ = (x, y, 1) @ AT
            self.ax1.text(x, y, label)

        # This is the part that changes.
        x, y, _ = np.array(sample_point) @ AT
        self.ax1.scatter(x, y, marker='o', color='r', edgecolors=['w'], zorder=2)
        self.canvas.draw()

    def set_concentrations(self, c2h2=None, c2h4=None, ch4=None):
        """Set concentration value(s)."""
        self.hold = True
        self.c2h2.value = c2h2 or self.c2h2.value
        self.c2h4.value = c2h4 or self.c2h4.value
        self.hold = False
        self.ch4.value = ch4 or self.ch4.value

window = App()
window.set_concentrations(41, 41, 1)
window.mainloop()
Marty23 likes this post
Reply


Messages In This Thread
User Interaction with Graph in GUI - by Marty23 - Mar-18-2024, 08:59 AM
RE: User Interaction with Graph in GUI - by deanhystad - Mar-19-2024, 03:17 AM

Possibly Related Threads…
Thread Author Replies Views Last Post
  Help with tkinter Button and Label interaction issues ... sealyons 0 4,751 Jun-01-2017, 06:58 PM
Last Post: sealyons

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020