import os import pandas as pd import matplotlib.pyplot as plt import seaborn as sns from flask import url_for from abc import ABC, abstractmethod from .base import BaseAnalysis from app.analysis.data_utils import prepare_data, mk_plotdir import matplotlib matplotlib.use('Agg') # ------------------------------------------- # Base Class for All Plot Analyses # ------------------------------------------- class BasePlotAnalysis(BaseAnalysis, ABC): """ Base class for all plot-based analyses. It enforces a structure for: - Data preparation - Transformation - Plot generation - Memory cleanup """ plot_filename = "default_plot.png" alt_text = "Default Alt Text" def execute(self, df: pd.DataFrame): """Executes the full analysis pipeline""" df = prepare_data(df) # Step 1: Prepare data paths = mk_plotdir(self.plot_filename) self.output_path, self.plot_url = paths['output_path'], paths['plot_url'] df = self.transform_data(df) # Step 2: Transform data (implemented by subclass) self.plot_data(df) # Step 3: Create the plot plt.savefig(self.output_path, bbox_inches="tight") plt.close() del df # Step 4: Free memory return f'{self.note}' @abstractmethod def transform_data(self, df: pd.DataFrame) -> pd.DataFrame: """Subclasses must define how they transform the data""" pass @abstractmethod def plot_data(self, df: pd.DataFrame): """Subclasses must define how they generate the plot""" pass