Spaces:
Sleeping
Sleeping
Update charts.py
Browse files
charts.py
CHANGED
|
@@ -8,23 +8,25 @@ import plotly.express as px
|
|
| 8 |
import pandas as pd
|
| 9 |
import numpy as np
|
| 10 |
|
| 11 |
-
# Shared theme
|
| 12 |
-
DARK_BG = "#
|
| 13 |
-
CARD_BG = "#
|
| 14 |
-
BORDER = "#
|
| 15 |
-
TEXT_MAIN = "#
|
| 16 |
-
TEXT_DIM = "#
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
|
|
|
|
|
|
| 23 |
|
| 24 |
PLOTLY_LAYOUT = dict(
|
| 25 |
-
paper_bgcolor="rgba(
|
| 26 |
-
plot_bgcolor="rgba(
|
| 27 |
-
font=dict(family="'DM
|
| 28 |
margin=dict(l=20, r=20, t=40, b=20),
|
| 29 |
)
|
| 30 |
|
|
@@ -44,7 +46,7 @@ def misinfo_gauge(score: float, label: str) -> go.Figure:
|
|
| 44 |
fig = go.Figure(go.Indicator(
|
| 45 |
mode="gauge+number+delta",
|
| 46 |
value=pct,
|
| 47 |
-
number={"suffix": "%", "font": {"size": 32, "color": bar_color, "family": "'
|
| 48 |
delta={"reference": 50, "increasing": {"color": RED}, "decreasing": {"color": GREEN}},
|
| 49 |
title={"text": label, "font": {"size": 13, "color": TEXT_DIM}},
|
| 50 |
gauge={
|
|
@@ -78,7 +80,7 @@ def misinfo_gauge(score: float, label: str) -> go.Figure:
|
|
| 78 |
def sentiment_donut(summary: Dict) -> go.Figure:
|
| 79 |
"""Donut chart: Positively Engagement / Negatively Engagement / Neutral breakdown."""
|
| 80 |
labels = ["Positively Engagement", "Neutral", "Negatively Engagement"]
|
| 81 |
-
values = [summary["
|
| 82 |
colors = [GREEN, TEXT_DIM, RED]
|
| 83 |
|
| 84 |
fig = go.Figure(go.Pie(
|
|
@@ -87,23 +89,24 @@ def sentiment_donut(summary: Dict) -> go.Figure:
|
|
| 87 |
hole=0.62,
|
| 88 |
marker=dict(colors=colors, line=dict(color=DARK_BG, width=3)),
|
| 89 |
textinfo="label+percent",
|
| 90 |
-
textfont=dict(family="'DM
|
| 91 |
hovertemplate="<b>%{label}</b><br>%{value} comments (%{percent})<extra></extra>",
|
| 92 |
rotation=90,
|
| 93 |
))
|
| 94 |
|
| 95 |
# Centre annotation
|
| 96 |
avg = summary.get("avg_compound", 0)
|
| 97 |
-
overall = "๐ Positively
|
| 98 |
fig.add_annotation(
|
| 99 |
text=f"<b>{overall}</b><br><span style='font-size:11px;color:{TEXT_DIM}'>{summary['total']} comments</span>",
|
| 100 |
x=0.5, y=0.5,
|
| 101 |
showarrow=False,
|
| 102 |
-
font=dict(size=13, color=TEXT_MAIN, family="'DM
|
| 103 |
align="center",
|
| 104 |
)
|
| 105 |
fig.update_layout(**PLOTLY_LAYOUT, height=300,
|
| 106 |
-
legend=dict(orientation="h", y=-0.08, font=dict(size=11))
|
|
|
|
| 107 |
return fig
|
| 108 |
|
| 109 |
|
|
@@ -128,21 +131,23 @@ def keyword_bar(
|
|
| 128 |
orientation="h",
|
| 129 |
marker=dict(
|
| 130 |
color=norm,
|
| 131 |
-
colorscale=[[0, f"{
|
| 132 |
line=dict(width=0),
|
| 133 |
),
|
| 134 |
text=[f"{w:.0f}" for w in weights],
|
| 135 |
textposition="inside",
|
| 136 |
-
textfont=dict(size=10, color=
|
| 137 |
hovertemplate="<b>%{y}</b><br>Weight: %{text}<extra></extra>",
|
| 138 |
))
|
| 139 |
fig.update_layout(
|
| 140 |
**PLOTLY_LAYOUT,
|
| 141 |
title=dict(text=title, font=dict(size=13, color=TEXT_DIM), x=0),
|
| 142 |
height=380,
|
| 143 |
-
yaxis=dict(autorange="reversed", tickfont=dict(size=11), gridcolor=BORDER
|
| 144 |
-
|
| 145 |
-
|
|
|
|
|
|
|
| 146 |
)
|
| 147 |
return fig
|
| 148 |
|
|
@@ -214,7 +219,7 @@ def modality_misinfo_distribution(modality_analysis: Dict) -> go.Figure:
|
|
| 214 |
marker=dict(
|
| 215 |
color=[RED, RED, RED],
|
| 216 |
opacity=0.88,
|
| 217 |
-
line=dict(color=
|
| 218 |
),
|
| 219 |
text=[f"{v:.1f}%" for v in misinfo_pcts],
|
| 220 |
textposition="outside",
|
|
@@ -234,7 +239,7 @@ def modality_misinfo_distribution(modality_analysis: Dict) -> go.Figure:
|
|
| 234 |
marker=dict(
|
| 235 |
color=[GREEN, GREEN, GREEN],
|
| 236 |
opacity=0.88,
|
| 237 |
-
line=dict(color=
|
| 238 |
),
|
| 239 |
text=[f"{v:.1f}%" for v in credible_pcts],
|
| 240 |
textposition="outside",
|
|
@@ -271,10 +276,11 @@ def modality_misinfo_distribution(modality_analysis: Dict) -> go.Figure:
|
|
| 271 |
orientation="h",
|
| 272 |
y=1.12,
|
| 273 |
font=dict(size=11),
|
| 274 |
-
bgcolor="rgba(
|
| 275 |
),
|
| 276 |
bargap=0.22,
|
| 277 |
bargroupgap=0.06,
|
|
|
|
| 278 |
)
|
| 279 |
return fig
|
| 280 |
|
|
@@ -308,7 +314,7 @@ def trust_score_by_modality(modality_analysis: Dict) -> go.Figure:
|
|
| 308 |
marker=dict(
|
| 309 |
color=bar_colors,
|
| 310 |
opacity=0.88,
|
| 311 |
-
line=dict(color=
|
| 312 |
),
|
| 313 |
text=[f"{v:.1f}%" for v in trust_vals],
|
| 314 |
textposition="outside",
|
|
@@ -351,6 +357,7 @@ def trust_score_by_modality(modality_analysis: Dict) -> go.Figure:
|
|
| 351 |
ticksuffix="%",
|
| 352 |
),
|
| 353 |
bargap=0.38,
|
|
|
|
| 354 |
)
|
| 355 |
return fig
|
| 356 |
|
|
@@ -388,7 +395,7 @@ def uncertainty_analysis(modality_analysis: Dict) -> go.Figure:
|
|
| 388 |
marker=dict(
|
| 389 |
color=bar_colors,
|
| 390 |
opacity=0.88,
|
| 391 |
-
line=dict(color=
|
| 392 |
),
|
| 393 |
text=[f"{v:.1f}%" for v in uncertainty_vals],
|
| 394 |
textposition="outside",
|
|
@@ -439,6 +446,7 @@ def uncertainty_analysis(modality_analysis: Dict) -> go.Figure:
|
|
| 439 |
ticksuffix="%",
|
| 440 |
),
|
| 441 |
bargap=0.38,
|
|
|
|
| 442 |
)
|
| 443 |
return fig
|
| 444 |
|
|
@@ -452,12 +460,16 @@ def sentiment_timeline(comments_df: pd.DataFrame, sentiments: List[Dict]) -> go.
|
|
| 452 |
|
| 453 |
df = comments_df.copy()
|
| 454 |
df["compound"] = [s.get("compound", 0) for s in sentiments]
|
| 455 |
-
df["label"] = [s.get("label", "
|
| 456 |
-
df["color"] = df["label"].map({
|
|
|
|
|
|
|
|
|
|
|
|
|
| 457 |
df["text_short"] = df["text"].str[:80] + "โฆ"
|
| 458 |
|
| 459 |
fig = go.Figure()
|
| 460 |
-
for lbl, clr in [("
|
| 461 |
sub = df[df["label"] == lbl]
|
| 462 |
if sub.empty:
|
| 463 |
continue
|
|
@@ -482,8 +494,11 @@ def sentiment_timeline(comments_df: pd.DataFrame, sentiments: List[Dict]) -> go.
|
|
| 482 |
title=dict(text="Comment Sentiment (size = likes)", font=dict(size=13, color=TEXT_DIM), x=0),
|
| 483 |
height=320,
|
| 484 |
xaxis=dict(title="Comment index", gridcolor=BORDER, showgrid=False),
|
| 485 |
-
yaxis=dict(title="Compound score", gridcolor=BORDER, range=[-1.1, 1.1]
|
| 486 |
-
|
|
|
|
|
|
|
|
|
|
| 487 |
)
|
| 488 |
return fig
|
| 489 |
|
|
@@ -533,10 +548,12 @@ def keyword_comparison(
|
|
| 533 |
title=dict(text="Sentiment-Weighted Keywords", font=dict(size=13, color=TEXT_DIM), x=0),
|
| 534 |
height=360,
|
| 535 |
barmode="overlay",
|
| 536 |
-
xaxis=dict(title="โ Negatively Engagement | Positively Engagement โ", gridcolor=BORDER,
|
| 537 |
-
zerolinecolor=BORDER, zerolinewidth=2),
|
| 538 |
yaxis=dict(tickfont=dict(size=10)),
|
| 539 |
-
legend=dict(orientation="h", y=1.1),
|
|
|
|
|
|
|
| 540 |
)
|
| 541 |
return fig
|
| 542 |
|
|
@@ -547,5 +564,6 @@ def _empty_fig(title: str) -> go.Figure:
|
|
| 547 |
fig = go.Figure()
|
| 548 |
fig.add_annotation(text="No data available", x=0.5, y=0.5, showarrow=False,
|
| 549 |
font=dict(size=14, color=TEXT_DIM))
|
| 550 |
-
fig.update_layout(**PLOTLY_LAYOUT, title=dict(text=title, x=0), height=250
|
| 551 |
-
|
|
|
|
|
|
| 8 |
import pandas as pd
|
| 9 |
import numpy as np
|
| 10 |
|
| 11 |
+
# Shared theme โ Light Professional
|
| 12 |
+
DARK_BG = "#f4f7fb" # used as bar border / contrast edge
|
| 13 |
+
CARD_BG = "#ffffff"
|
| 14 |
+
BORDER = "#dde3ed"
|
| 15 |
+
TEXT_MAIN = "#1e293b"
|
| 16 |
+
TEXT_DIM = "#7b7b7b" # Flat Grey
|
| 17 |
+
PRIMARY = "#269ccc" # Optimism Blue
|
| 18 |
+
ALGAE = "#9ed2c5" # Blue Algae
|
| 19 |
+
CYAN = "#269ccc" # alias for PRIMARY
|
| 20 |
+
GREEN = "#16a34a"
|
| 21 |
+
RED = "#dc2626"
|
| 22 |
+
AMBER = "#d97706"
|
| 23 |
+
PURPLE = "#7c3aed"
|
| 24 |
+
BLUE = "#2563eb"
|
| 25 |
|
| 26 |
PLOTLY_LAYOUT = dict(
|
| 27 |
+
paper_bgcolor="rgba(255,255,255,0)",
|
| 28 |
+
plot_bgcolor="rgba(255,255,255,0)",
|
| 29 |
+
font=dict(family="'DM Sans', 'Nunito', sans-serif", color=TEXT_MAIN, size=12),
|
| 30 |
margin=dict(l=20, r=20, t=40, b=20),
|
| 31 |
)
|
| 32 |
|
|
|
|
| 46 |
fig = go.Figure(go.Indicator(
|
| 47 |
mode="gauge+number+delta",
|
| 48 |
value=pct,
|
| 49 |
+
number={"suffix": "%", "font": {"size": 32, "color": bar_color, "family": "'Nunito', sans-serif"}},
|
| 50 |
delta={"reference": 50, "increasing": {"color": RED}, "decreasing": {"color": GREEN}},
|
| 51 |
title={"text": label, "font": {"size": 13, "color": TEXT_DIM}},
|
| 52 |
gauge={
|
|
|
|
| 80 |
def sentiment_donut(summary: Dict) -> go.Figure:
|
| 81 |
"""Donut chart: Positively Engagement / Negatively Engagement / Neutral breakdown."""
|
| 82 |
labels = ["Positively Engagement", "Neutral", "Negatively Engagement"]
|
| 83 |
+
values = [summary["Positively Engagement"], summary["Neutral"], summary["Negatively Engagement"]]
|
| 84 |
colors = [GREEN, TEXT_DIM, RED]
|
| 85 |
|
| 86 |
fig = go.Figure(go.Pie(
|
|
|
|
| 89 |
hole=0.62,
|
| 90 |
marker=dict(colors=colors, line=dict(color=DARK_BG, width=3)),
|
| 91 |
textinfo="label+percent",
|
| 92 |
+
textfont=dict(family="'DM Sans', sans-serif", size=11, color=TEXT_MAIN),
|
| 93 |
hovertemplate="<b>%{label}</b><br>%{value} comments (%{percent})<extra></extra>",
|
| 94 |
rotation=90,
|
| 95 |
))
|
| 96 |
|
| 97 |
# Centre annotation
|
| 98 |
avg = summary.get("avg_compound", 0)
|
| 99 |
+
overall = "๐ Positively Engaged" if avg > 0.05 else ("๐ Negatively Engaged" if avg < -0.05 else "๐ Mixed")
|
| 100 |
fig.add_annotation(
|
| 101 |
text=f"<b>{overall}</b><br><span style='font-size:11px;color:{TEXT_DIM}'>{summary['total']} comments</span>",
|
| 102 |
x=0.5, y=0.5,
|
| 103 |
showarrow=False,
|
| 104 |
+
font=dict(size=13, color=TEXT_MAIN, family="'DM Sans', sans-serif"),
|
| 105 |
align="center",
|
| 106 |
)
|
| 107 |
fig.update_layout(**PLOTLY_LAYOUT, height=300,
|
| 108 |
+
legend=dict(orientation="h", y=-0.08, font=dict(size=11)),
|
| 109 |
+
title=dict(text="Sentiment Breakdown", font=dict(size=13, color=TEXT_DIM), x=0))
|
| 110 |
return fig
|
| 111 |
|
| 112 |
|
|
|
|
| 131 |
orientation="h",
|
| 132 |
marker=dict(
|
| 133 |
color=norm,
|
| 134 |
+
colorscale=[[0, f"{PRIMARY}33"], [1, PRIMARY]],
|
| 135 |
line=dict(width=0),
|
| 136 |
),
|
| 137 |
text=[f"{w:.0f}" for w in weights],
|
| 138 |
textposition="inside",
|
| 139 |
+
textfont=dict(size=10, color="#ffffff", family="'DM Sans', sans-serif"),
|
| 140 |
hovertemplate="<b>%{y}</b><br>Weight: %{text}<extra></extra>",
|
| 141 |
))
|
| 142 |
fig.update_layout(
|
| 143 |
**PLOTLY_LAYOUT,
|
| 144 |
title=dict(text=title, font=dict(size=13, color=TEXT_DIM), x=0),
|
| 145 |
height=380,
|
| 146 |
+
yaxis=dict(autorange="reversed", tickfont=dict(size=11), gridcolor=BORDER,
|
| 147 |
+
showgrid=True, gridwidth=1),
|
| 148 |
+
xaxis=dict(showticklabels=False, gridcolor=BORDER, showgrid=False),
|
| 149 |
+
bargap=0.3,
|
| 150 |
+
plot_bgcolor="rgba(248,250,252,0.6)",
|
| 151 |
)
|
| 152 |
return fig
|
| 153 |
|
|
|
|
| 219 |
marker=dict(
|
| 220 |
color=[RED, RED, RED],
|
| 221 |
opacity=0.88,
|
| 222 |
+
line=dict(color=CARD_BG, width=1),
|
| 223 |
),
|
| 224 |
text=[f"{v:.1f}%" for v in misinfo_pcts],
|
| 225 |
textposition="outside",
|
|
|
|
| 239 |
marker=dict(
|
| 240 |
color=[GREEN, GREEN, GREEN],
|
| 241 |
opacity=0.88,
|
| 242 |
+
line=dict(color=CARD_BG, width=1),
|
| 243 |
),
|
| 244 |
text=[f"{v:.1f}%" for v in credible_pcts],
|
| 245 |
textposition="outside",
|
|
|
|
| 276 |
orientation="h",
|
| 277 |
y=1.12,
|
| 278 |
font=dict(size=11),
|
| 279 |
+
bgcolor="rgba(255,255,255,0)",
|
| 280 |
),
|
| 281 |
bargap=0.22,
|
| 282 |
bargroupgap=0.06,
|
| 283 |
+
plot_bgcolor="rgba(248,250,252,0.6)",
|
| 284 |
)
|
| 285 |
return fig
|
| 286 |
|
|
|
|
| 314 |
marker=dict(
|
| 315 |
color=bar_colors,
|
| 316 |
opacity=0.88,
|
| 317 |
+
line=dict(color=CARD_BG, width=1),
|
| 318 |
),
|
| 319 |
text=[f"{v:.1f}%" for v in trust_vals],
|
| 320 |
textposition="outside",
|
|
|
|
| 357 |
ticksuffix="%",
|
| 358 |
),
|
| 359 |
bargap=0.38,
|
| 360 |
+
plot_bgcolor="rgba(248,250,252,0.6)",
|
| 361 |
)
|
| 362 |
return fig
|
| 363 |
|
|
|
|
| 395 |
marker=dict(
|
| 396 |
color=bar_colors,
|
| 397 |
opacity=0.88,
|
| 398 |
+
line=dict(color=CARD_BG, width=1),
|
| 399 |
),
|
| 400 |
text=[f"{v:.1f}%" for v in uncertainty_vals],
|
| 401 |
textposition="outside",
|
|
|
|
| 446 |
ticksuffix="%",
|
| 447 |
),
|
| 448 |
bargap=0.38,
|
| 449 |
+
plot_bgcolor="rgba(248,250,252,0.6)",
|
| 450 |
)
|
| 451 |
return fig
|
| 452 |
|
|
|
|
| 460 |
|
| 461 |
df = comments_df.copy()
|
| 462 |
df["compound"] = [s.get("compound", 0) for s in sentiments]
|
| 463 |
+
df["label"] = [s.get("label", "Neutral") for s in sentiments]
|
| 464 |
+
df["color"] = df["label"].map({
|
| 465 |
+
"Positively Engagement": GREEN,
|
| 466 |
+
"Negatively Engagement": RED,
|
| 467 |
+
"Neutral": AMBER,
|
| 468 |
+
})
|
| 469 |
df["text_short"] = df["text"].str[:80] + "โฆ"
|
| 470 |
|
| 471 |
fig = go.Figure()
|
| 472 |
+
for lbl, clr in [("Positively Engagement", GREEN), ("Negatively Engagement", RED), ("Neutral", AMBER)]:
|
| 473 |
sub = df[df["label"] == lbl]
|
| 474 |
if sub.empty:
|
| 475 |
continue
|
|
|
|
| 494 |
title=dict(text="Comment Sentiment (size = likes)", font=dict(size=13, color=TEXT_DIM), x=0),
|
| 495 |
height=320,
|
| 496 |
xaxis=dict(title="Comment index", gridcolor=BORDER, showgrid=False),
|
| 497 |
+
yaxis=dict(title="Compound score", gridcolor=BORDER, range=[-1.1, 1.1],
|
| 498 |
+
showgrid=True, gridwidth=1),
|
| 499 |
+
legend=dict(orientation="h", y=1.12, font=dict(size=11),
|
| 500 |
+
bgcolor="rgba(255,255,255,0.8)", bordercolor=BORDER, borderwidth=1),
|
| 501 |
+
plot_bgcolor="rgba(248,250,252,0.6)",
|
| 502 |
)
|
| 503 |
return fig
|
| 504 |
|
|
|
|
| 548 |
title=dict(text="Sentiment-Weighted Keywords", font=dict(size=13, color=TEXT_DIM), x=0),
|
| 549 |
height=360,
|
| 550 |
barmode="overlay",
|
| 551 |
+
xaxis=dict(title="โ Negatively Engagement | Positively Engagement โ", gridcolor=BORDER,
|
| 552 |
+
zeroline=True, zerolinecolor=BORDER, zerolinewidth=2),
|
| 553 |
yaxis=dict(tickfont=dict(size=10)),
|
| 554 |
+
legend=dict(orientation="h", y=1.1, bgcolor="rgba(255,255,255,0.8)",
|
| 555 |
+
bordercolor=BORDER, borderwidth=1),
|
| 556 |
+
plot_bgcolor="rgba(248,250,252,0.6)",
|
| 557 |
)
|
| 558 |
return fig
|
| 559 |
|
|
|
|
| 564 |
fig = go.Figure()
|
| 565 |
fig.add_annotation(text="No data available", x=0.5, y=0.5, showarrow=False,
|
| 566 |
font=dict(size=14, color=TEXT_DIM))
|
| 567 |
+
fig.update_layout(**PLOTLY_LAYOUT, title=dict(text=title, x=0), height=250,
|
| 568 |
+
plot_bgcolor="rgba(248,250,252,0.6)")
|
| 569 |
+
return fig
|