import os import pandas as pd import matplotlib.pyplot as plt import seaborn as sns 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 Attributes: plot_filename (str): The filename for the output plot. alt_text (str): The alt text for the plot. """ plot_filename = "default_plot.png" alt_text = "Default Alt Text" def execute(self, df: pd.DataFrame): """ Executes the full analysis pipeline. Parameters: df (pd.DataFrame): The input DataFrame containing user activity data. Returns: str: HTML img tag containing the URL to the generated plot. """ 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. Parameters: df (pd.DataFrame): The input DataFrame containing user activity data. Returns: pd.DataFrame: The transformed DataFrame. """ pass @abstractmethod def plot_data(self, df: pd.DataFrame): """ Subclasses must define how they generate the plot. Parameters: df (pd.DataFrame): The transformed DataFrame containing data to be plotted. """ pass