Mar-19-2024, 03:17 AM
(This post was last modified: Mar-19-2024, 03:17 AM by deanhystad.)
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()