Spaces:
Running
Running
Update ui/analytics_plot_generator.py
Browse files
ui/analytics_plot_generator.py
CHANGED
@@ -86,9 +86,11 @@ def create_placeholder_plot(title="No Data or Plot Error", message="Data might b
|
|
86 |
# --- Generic and Reusable Plotting Functions ---
|
87 |
|
88 |
def generate_generic_time_series_plot(df, date_column, value_column, title, ylabel, color='cyan'):
|
89 |
-
"""
|
|
|
|
|
90 |
if df is None or df.empty or date_column not in df.columns or value_column not in df.columns:
|
91 |
-
logging.info(f"len df {len(df) if df else 0},
|
92 |
return create_placeholder_plot(title=title, message="No data available.")
|
93 |
|
94 |
fig = None
|
@@ -97,10 +99,13 @@ def generate_generic_time_series_plot(df, date_column, value_column, title, ylab
|
|
97 |
df_copy[date_column] = pd.to_datetime(df_copy[date_column], errors='coerce')
|
98 |
df_copy[value_column] = pd.to_numeric(df_copy[value_column], errors='coerce')
|
99 |
df_copy = df_copy.dropna(subset=[date_column, value_column]).set_index(date_column)
|
|
|
100 |
if df_copy.empty:
|
101 |
-
return create_placeholder_plot(title=title, message="No valid data.")
|
102 |
|
|
|
103 |
data_over_time = df_copy.resample('D')[value_column].sum()
|
|
|
104 |
if data_over_time.empty:
|
105 |
return create_placeholder_plot(title=title, message="No data in the selected period.")
|
106 |
|
@@ -109,16 +114,30 @@ def generate_generic_time_series_plot(df, date_column, value_column, title, ylab
|
|
109 |
|
110 |
ax.plot(data_over_time.index, data_over_time.values, marker='o', linestyle='-', color=color, zorder=1, markersize=5, alpha=0.8)
|
111 |
ax.fill_between(data_over_time.index, data_over_time.values, color=color, alpha=0.1, zorder=1)
|
|
|
112 |
ax.set_title(title, fontsize=14, weight='bold')
|
113 |
ax.set_xlabel('Date', fontsize=10)
|
114 |
ax.set_ylabel(ylabel, fontsize=10)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
115 |
plt.xticks(rotation=30, ha="right")
|
116 |
fig.tight_layout(pad=1.5)
|
117 |
return fig
|
|
|
118 |
except Exception as e:
|
119 |
logging.error(f"Error generating {title}: {e}", exc_info=True)
|
120 |
-
if fig:
|
121 |
-
|
|
|
122 |
|
123 |
|
124 |
def generate_generic_bar_plot(data_series, title, xlabel, ylabel, color_map='viridis'):
|
|
|
86 |
# --- Generic and Reusable Plotting Functions ---
|
87 |
|
88 |
def generate_generic_time_series_plot(df, date_column, value_column, title, ylabel, color='cyan'):
|
89 |
+
"""
|
90 |
+
Generic function to create a theme-aware time series plot with explicit date formatting.
|
91 |
+
"""
|
92 |
if df is None or df.empty or date_column not in df.columns or value_column not in df.columns:
|
93 |
+
logging.info(f"DataFrame is empty or columns are missing. len df: {len(df) if df is not None else 0}, date_column: {date_column}, value_column: {value_column}")
|
94 |
return create_placeholder_plot(title=title, message="No data available.")
|
95 |
|
96 |
fig = None
|
|
|
99 |
df_copy[date_column] = pd.to_datetime(df_copy[date_column], errors='coerce')
|
100 |
df_copy[value_column] = pd.to_numeric(df_copy[value_column], errors='coerce')
|
101 |
df_copy = df_copy.dropna(subset=[date_column, value_column]).set_index(date_column)
|
102 |
+
|
103 |
if df_copy.empty:
|
104 |
+
return create_placeholder_plot(title=title, message="No valid data after cleaning.")
|
105 |
|
106 |
+
# Resample data by day. This correctly aggregates your data.
|
107 |
data_over_time = df_copy.resample('D')[value_column].sum()
|
108 |
+
|
109 |
if data_over_time.empty:
|
110 |
return create_placeholder_plot(title=title, message="No data in the selected period.")
|
111 |
|
|
|
114 |
|
115 |
ax.plot(data_over_time.index, data_over_time.values, marker='o', linestyle='-', color=color, zorder=1, markersize=5, alpha=0.8)
|
116 |
ax.fill_between(data_over_time.index, data_over_time.values, color=color, alpha=0.1, zorder=1)
|
117 |
+
|
118 |
ax.set_title(title, fontsize=14, weight='bold')
|
119 |
ax.set_xlabel('Date', fontsize=10)
|
120 |
ax.set_ylabel(ylabel, fontsize=10)
|
121 |
+
|
122 |
+
# --- FIX STARTS HERE ---
|
123 |
+
# Use an automatic date locator and a concise formatter for smart,
|
124 |
+
# adaptive date ticks that work well for any time range. This avoids
|
125 |
+
# cluttering the axis when the date range is large.
|
126 |
+
locator = mdates.AutoDateLocator()
|
127 |
+
formatter = mdates.ConciseDateFormatter(locator)
|
128 |
+
ax.xaxis.set_major_locator(locator)
|
129 |
+
ax.xaxis.set_major_formatter(formatter)
|
130 |
+
# --- FIX ENDS HERE ---
|
131 |
+
|
132 |
plt.xticks(rotation=30, ha="right")
|
133 |
fig.tight_layout(pad=1.5)
|
134 |
return fig
|
135 |
+
|
136 |
except Exception as e:
|
137 |
logging.error(f"Error generating {title}: {e}", exc_info=True)
|
138 |
+
if fig:
|
139 |
+
plt.close(fig)
|
140 |
+
return create_placeholder_plot(title=f"Error in {title}", message=str(e))
|
141 |
|
142 |
|
143 |
def generate_generic_bar_plot(data_series, title, xlabel, ylabel, color_map='viridis'):
|