feat: Implement dose calculation fix and enhance legend feature
Some checks failed
Build and Push Docker Image / build-and-push (push) Has been cancelled
Some checks failed
Build and Push Docker Image / build-and-push (push) Has been cancelled
- Fixed dose calculation logic in `_calculate_daily_dose` to correctly parse timestamps with multiple colons. - Added comprehensive test cases for various dose formats and edge cases in `test_dose_calculation.py`. - Enhanced graph legend to display individual medicines with average dosages and track medicines without dose data. - Updated legend styling and positioning for better readability and organization. - Created new tests for enhanced legend functionality, including handling of medicines with and without data. - Improved mocking for matplotlib components in tests to prevent TypeErrors.
This commit is contained in:
@@ -163,6 +163,10 @@ class GraphManager:
|
||||
"quetiapine",
|
||||
]
|
||||
|
||||
# Track medicines with and without data for legend
|
||||
medicines_with_data = []
|
||||
medicines_without_data = []
|
||||
|
||||
for medicine in medicines:
|
||||
dose_column = f"{medicine}_doses"
|
||||
if self.toggle_vars[medicine].get() and dose_column in df.columns:
|
||||
@@ -174,23 +178,66 @@ class GraphManager:
|
||||
|
||||
# Only plot if there are non-zero doses
|
||||
if any(dose > 0 for dose in daily_doses):
|
||||
medicines_with_data.append(medicine)
|
||||
# Scale doses for better visibility
|
||||
# (divide by 10 to fit with 0-10 scale)
|
||||
scaled_doses = [dose / 10 for dose in daily_doses]
|
||||
|
||||
# Calculate total dosage for this medicine across all days
|
||||
total_medicine_dose = sum(daily_doses)
|
||||
non_zero_doses = [d for d in daily_doses if d > 0]
|
||||
avg_dose = total_medicine_dose / len(non_zero_doses)
|
||||
|
||||
# Create more informative label
|
||||
label = f"{medicine.capitalize()} (avg: {avg_dose:.1f}mg)"
|
||||
|
||||
self.ax.bar(
|
||||
df.index,
|
||||
scaled_doses,
|
||||
alpha=0.6,
|
||||
color=medicine_colors.get(medicine, "#DDA0DD"),
|
||||
label=f"{medicine.capitalize()} (mg/10)",
|
||||
label=label,
|
||||
width=0.6,
|
||||
bottom=-max(scaled_doses) * 1.1 if scaled_doses else -1,
|
||||
)
|
||||
has_plotted_series = True
|
||||
else:
|
||||
# Medicine is toggled on but has no dose data
|
||||
if self.toggle_vars[medicine].get():
|
||||
medicines_without_data.append(medicine)
|
||||
|
||||
# Configure graph appearance
|
||||
if has_plotted_series:
|
||||
self.ax.legend()
|
||||
# Get current legend handles and labels
|
||||
handles, labels = self.ax.get_legend_handles_labels()
|
||||
|
||||
# Add information about medicines without data if any are toggled on
|
||||
if medicines_without_data:
|
||||
# Add a text note about medicines without dose data
|
||||
med_list = ", ".join(medicines_without_data)
|
||||
info_text = f"Tracked (no doses): {med_list}"
|
||||
labels.append(info_text)
|
||||
# Create a dummy handle for the info text (invisible)
|
||||
from matplotlib.patches import Rectangle
|
||||
|
||||
dummy_handle = Rectangle(
|
||||
(0, 0), 1, 1, fc="w", fill=False, edgecolor="none", linewidth=0
|
||||
)
|
||||
handles.append(dummy_handle)
|
||||
|
||||
# Create an expanded legend with better formatting
|
||||
self.ax.legend(
|
||||
handles,
|
||||
labels,
|
||||
loc="upper left",
|
||||
bbox_to_anchor=(0, 1),
|
||||
ncol=2, # Display in 2 columns for better space usage
|
||||
fontsize="small",
|
||||
frameon=True,
|
||||
fancybox=True,
|
||||
shadow=True,
|
||||
framealpha=0.9,
|
||||
)
|
||||
self.ax.set_title("Medication Effects Over Time")
|
||||
self.ax.set_xlabel("Date")
|
||||
self.ax.set_ylabel("Rating (0-10) / Dose (mg)")
|
||||
@@ -239,12 +286,8 @@ class GraphManager:
|
||||
continue
|
||||
|
||||
try:
|
||||
if ":" in entry:
|
||||
# Extract dose part after the timestamp
|
||||
_, dose_part = entry.split(":", 1)
|
||||
else:
|
||||
# Handle cases where there's no timestamp
|
||||
dose_part = entry
|
||||
# Extract dose part after the last colon (timestamp:dose format)
|
||||
dose_part = entry.split(":")[-1] if ":" in entry else entry
|
||||
|
||||
# Extract numeric part from dose (e.g., "150mg" -> 150)
|
||||
dose_value = ""
|
||||
|
||||
Reference in New Issue
Block a user