elon_py/pkg/dash/func/render.py
NY 681f501c1c -line chart
-Probability
2025-03-21 12:22:12 +08:00

111 lines
4.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from datetime import datetime, timedelta
from dash.dependencies import Input, Output
from pkg.dash.app_init import app
from pkg.config import render_data
from pkg.tool import aggregate_data, minutes_to_time, get_tweets_since_last_friday
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')]
)
def render_tab_content(tab, interval, days_to_display):
warning = ""
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."
multi_data_agg = render_data.global_agg_df[render_data.global_agg_df['date'].isin(selected_dates)].copy()
if multi_data_agg.empty:
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()
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)
if tab == 'heatmap':
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()
if date.weekday() == 4:
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"
)
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']
hour = int(minute // 60)
interval_idx = int((minute % 60) // interval)
if hour < 24:
z_values[hour][interval_idx] = row['tweet_count']
x_labels = [f"{i * interval:02d}" for i in range(intervals_per_hour)]
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)]
fig = go.Figure(data=go.Heatmap(
z=z_values,
x=x_labels,
y=[f"{h:02d}" for h in hours],
colorscale='Viridis',
hoverongaps=False,
customdata=rate_values,
hovertemplate='%{y}:%{x} EST<br>Tweets: %{z}<br>Rate: %{customdata:.2%}<extra></extra>'
))
fig.update_layout(
title=f'One-Day Heatmap Tweet Frequency (Interval: {interval} minutes, EST, {len(selected_dates)} days)',
xaxis_title='Minutes',
yaxis_title='Hour of Day',
height=600,
yaxis=dict(autorange='reversed')
)
summary = f"Total tweets: {get_tweets_since_last_friday()}"
return dcc.Graph(figure=fig), warning, summary