elon_py/pkg/dash/func/render.py

111 lines
4.4 KiB
Python
Raw Normal View History

2025-03-05 10:24:46 +08:00
from datetime import datetime, timedelta
from dash.dependencies import Input, Output
from pkg.dash.app_init import app
from pkg.config import render_data
2025-03-21 12:22:12 +08:00
from pkg.tool import aggregate_data, minutes_to_time, get_tweets_since_last_friday
2025-03-05 10:24:46 +08:00
from dash import dcc
import plotly.graph_objs as go
import pandas as pd
@app.callback(
[Output('tabs-content', 'children'),
Output('multi-day-warning', 'children'),
Output('multi-tweet-summary', 'children')],
[Input('tabs', 'value'),
Input('multi-interval-picker', 'value'),
Input('days-display-picker', 'value')]
)
2025-03-21 12:22:12 +08:00
def render_tab_content(tab, interval, days_to_display):
2025-03-05 10:24:46 +08:00
warning = ""
2025-03-21 12:22:12 +08:00
available_dates = sorted(render_data.global_agg_df['date'].unique(), reverse=True)
selected_dates = available_dates[:days_to_display] if available_dates else [datetime.now().date()]
if not available_dates:
warning = "No data available. Showing todays date with zero tweets."
2025-03-05 10:24:46 +08:00
multi_data_agg = render_data.global_agg_df[render_data.global_agg_df['date'].isin(selected_dates)].copy()
if multi_data_agg.empty:
2025-03-06 10:16:59 +08:00
multi_data_agg = pd.DataFrame({
'date': selected_dates,
'minute_of_day': [0] * len(selected_dates),
})
tweet_count_total = multi_data_agg.get('tweet_count', pd.Series([0] * len(multi_data_agg))).sum()
2025-03-05 10:24:46 +08:00
multi_data_raw = render_data.global_df[render_data.global_df['date'].isin(selected_dates)].copy()
if multi_data_raw.empty:
tweet_count_total = 0
agg_data = aggregate_data(multi_data_agg, interval)
2025-03-21 12:22:12 +08:00
if tab == 'heatmap':
2025-03-05 10:24:46 +08:00
pivot_data = agg_data.pivot(index='date', columns='interval_group', values='tweet_count').fillna(0)
pivot_data.index = pivot_data.index.astype(str)
fig = go.Figure(data=go.Heatmap(
z=pivot_data.values,
x=[minutes_to_time(m) for m in pivot_data.columns],
y=pivot_data.index,
colorscale='Viridis',
hoverongaps=False,
hovertemplate='%{y} %{x} EST<br>Tweets: %{z}<extra></extra>'
))
for i, date_str in enumerate(pivot_data.index):
date = datetime.strptime(date_str, '%Y-%m-%d').date()
2025-03-21 12:22:12 +08:00
if date.weekday() == 4:
2025-03-05 10:24:46 +08:00
prev_date = date - timedelta(days=1)
if str(prev_date) in pivot_data.index:
y_position = i / len(pivot_data.index)
fig.add_hline(
y=1 - y_position,
line_dash="dash",
line_color="white",
xref="x",
yref="paper"
)
2025-03-05 11:18:21 +08:00
fig.update_layout(
title=f'Tweet Heatmap (Interval: {interval} minutes, EST, {len(selected_dates)} days)',
xaxis_title='Time of Day (HH:MM EST)',
yaxis_title='Date',
height=max(400, len(selected_dates) * 20),
yaxis=dict(autorange='reversed')
)
elif tab == 'one_day_heatmap':
one_day_data = agg_data.groupby('interval_group')['tweet_count'].sum().reset_index()
hours = list(range(24))
intervals_per_hour = 60 // interval
z_values = [[0] * intervals_per_hour for _ in range(24)]
for _, row in one_day_data.iterrows():
minute = row['interval_group']
2025-03-21 12:22:12 +08:00
hour = int(minute // 60)
interval_idx = int((minute % 60) // interval)
2025-03-05 11:18:21 +08:00
if hour < 24:
z_values[hour][interval_idx] = row['tweet_count']
x_labels = [f"{i * interval:02d}" for i in range(intervals_per_hour)]
2025-03-12 17:40:20 +08:00
rate_values = [[z_values[h][i] / tweet_count_total if tweet_count_total > 0 else 0
for i in range(intervals_per_hour)]
for h in range(24)]
2025-03-05 11:18:21 +08:00
fig = go.Figure(data=go.Heatmap(
z=z_values,
x=x_labels,
2025-03-05 11:48:14 +08:00
y=[f"{h:02d}" for h in hours],
2025-03-05 11:18:21 +08:00
colorscale='Viridis',
hoverongaps=False,
2025-03-12 17:40:20 +08:00
customdata=rate_values,
hovertemplate='%{y}:%{x} EST<br>Tweets: %{z}<br>Rate: %{customdata:.2%}<extra></extra>'
2025-03-05 11:18:21 +08:00
))
2025-03-05 10:24:46 +08:00
fig.update_layout(
2025-03-21 12:22:12 +08:00
title=f'One-Day Heatmap Tweet Frequency (Interval: {interval} minutes, EST, {len(selected_dates)} days)',
xaxis_title='Minutes',
yaxis_title='Hour of Day',
2025-03-05 10:24:46 +08:00
height=600,
2025-03-21 12:22:12 +08:00
yaxis=dict(autorange='reversed')
2025-03-05 10:24:46 +08:00
)
2025-03-21 11:57:34 +08:00
summary = f"Total tweets: {get_tweets_since_last_friday()}"
2025-03-05 11:18:21 +08:00
return dcc.Graph(figure=fig), warning, summary