150 lines
5.2 KiB
Python
150 lines
5.2 KiB
Python
import tkinter as tk
|
|
from tkinter import ttk
|
|
|
|
import matplotlib.figure
|
|
import matplotlib.pyplot as plt
|
|
import pandas as pd
|
|
from matplotlib.axes import Axes
|
|
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
|
|
|
|
|
|
class GraphManager:
|
|
"""Handle all graph-related operations for the application."""
|
|
|
|
def __init__(self, parent_frame: ttk.LabelFrame) -> None:
|
|
self.parent_frame: ttk.LabelFrame = parent_frame
|
|
|
|
# Configure graph frame to expand
|
|
self.parent_frame.grid_rowconfigure(0, weight=1)
|
|
self.parent_frame.grid_columnconfigure(0, weight=1)
|
|
|
|
# Initialize toggle variables for chart elements
|
|
self.toggle_vars: dict[str, tk.BooleanVar] = {
|
|
"depression": tk.BooleanVar(value=True),
|
|
"anxiety": tk.BooleanVar(value=True),
|
|
"sleep": tk.BooleanVar(value=True),
|
|
"appetite": tk.BooleanVar(value=True),
|
|
}
|
|
|
|
# Create control frame for toggles
|
|
self.control_frame: ttk.Frame = ttk.Frame(self.parent_frame)
|
|
self.control_frame.grid(row=0, column=0, sticky="ew", padx=5, pady=5)
|
|
|
|
# Create toggle checkboxes
|
|
self._create_toggle_controls()
|
|
|
|
# Create graph frame
|
|
self.graph_frame: ttk.Frame = ttk.Frame(self.parent_frame)
|
|
self.graph_frame.grid(row=1, column=0, sticky="nsew", padx=5, pady=5)
|
|
|
|
# Reconfigure parent frame for new layout
|
|
self.parent_frame.grid_rowconfigure(1, weight=1)
|
|
self.parent_frame.grid_columnconfigure(0, weight=1)
|
|
|
|
# Initialize matplotlib figure and canvas
|
|
self.fig: matplotlib.figure.Figure
|
|
self.ax: Axes
|
|
self.fig, self.ax = plt.subplots()
|
|
self.canvas: FigureCanvasTkAgg = FigureCanvasTkAgg(
|
|
figure=self.fig, master=self.graph_frame
|
|
)
|
|
self.canvas.get_tk_widget().pack(fill="both", expand=True)
|
|
|
|
# Store current data for replotting
|
|
self.current_data: pd.DataFrame = pd.DataFrame()
|
|
|
|
def _create_toggle_controls(self) -> None:
|
|
"""Create toggle controls for chart elements."""
|
|
ttk.Label(self.control_frame, text="Show/Hide Elements:").pack(
|
|
side="left", padx=5
|
|
)
|
|
|
|
toggle_configs = [
|
|
("depression", "Depression"),
|
|
("anxiety", "Anxiety"),
|
|
("sleep", "Sleep"),
|
|
("appetite", "Appetite"),
|
|
]
|
|
|
|
for key, label in toggle_configs:
|
|
checkbox = ttk.Checkbutton(
|
|
self.control_frame,
|
|
text=label,
|
|
variable=self.toggle_vars[key],
|
|
command=self._on_toggle_changed,
|
|
)
|
|
checkbox.pack(side="left", padx=5)
|
|
|
|
def _on_toggle_changed(self) -> None:
|
|
"""Handle toggle changes by replotting the graph."""
|
|
if not self.current_data.empty:
|
|
self._plot_graph_data(self.current_data)
|
|
|
|
def update_graph(self, df: pd.DataFrame) -> None:
|
|
"""Update the graph with new data."""
|
|
self.current_data = df.copy() if not df.empty else pd.DataFrame()
|
|
self._plot_graph_data(df)
|
|
|
|
def _plot_graph_data(self, df: pd.DataFrame) -> None:
|
|
"""Plot the graph data with current toggle settings."""
|
|
self.ax.clear()
|
|
if not df.empty:
|
|
# Convert dates and sort
|
|
df = df.copy() # Create a copy to avoid modifying the original
|
|
df["date"] = pd.to_datetime(df["date"])
|
|
df = df.sort_values(by="date")
|
|
df.set_index(keys="date", inplace=True)
|
|
|
|
# Track if any series are plotted
|
|
has_plotted_series = False
|
|
|
|
# Plot data series based on toggle states
|
|
if self.toggle_vars["depression"].get():
|
|
self._plot_series(
|
|
df, "depression", "Depression (0:good, 10:bad)", "o", "-"
|
|
)
|
|
has_plotted_series = True
|
|
if self.toggle_vars["anxiety"].get():
|
|
self._plot_series(df, "anxiety", "Anxiety (0:good, 10:bad)", "o", "-")
|
|
has_plotted_series = True
|
|
if self.toggle_vars["sleep"].get():
|
|
self._plot_series(df, "sleep", "Sleep (0:bad, 10:good)", "o", "dashed")
|
|
has_plotted_series = True
|
|
if self.toggle_vars["appetite"].get():
|
|
self._plot_series(
|
|
df, "appetite", "Appetite (0:bad, 10:good)", "o", "dashed"
|
|
)
|
|
has_plotted_series = True
|
|
|
|
# Configure graph appearance
|
|
if has_plotted_series:
|
|
self.ax.legend()
|
|
self.ax.set_title("Medication Effects Over Time")
|
|
self.ax.set_xlabel("Date")
|
|
self.ax.set_ylabel("Rating (0-10)")
|
|
self.fig.autofmt_xdate()
|
|
|
|
# Redraw the canvas
|
|
self.canvas.draw()
|
|
|
|
def _plot_series(
|
|
self,
|
|
df: pd.DataFrame,
|
|
column: str,
|
|
label: str,
|
|
marker: str,
|
|
linestyle: str,
|
|
) -> None:
|
|
"""Helper method to plot a data series."""
|
|
self.ax.plot(
|
|
df.index,
|
|
df[column],
|
|
marker=marker,
|
|
linestyle=linestyle,
|
|
label=label,
|
|
)
|
|
|
|
def close(self) -> None:
|
|
"""Clean up resources."""
|
|
plt.close(self.fig)
|