feat(frontend): reword CulturalStats to improve understandability
This commit is contained in:
@@ -11,6 +11,15 @@ type CulturalStatsProps = {
|
|||||||
const CulturalStats = ({ data }: CulturalStatsProps) => {
|
const CulturalStats = ({ data }: CulturalStatsProps) => {
|
||||||
const identity = data.identity_markers;
|
const identity = data.identity_markers;
|
||||||
const stance = data.stance_markers;
|
const stance = data.stance_markers;
|
||||||
|
const inGroupWords = identity?.in_group_usage ?? 0;
|
||||||
|
const outGroupWords = identity?.out_group_usage ?? 0;
|
||||||
|
const totalGroupWords = inGroupWords + outGroupWords;
|
||||||
|
const inGroupWordRate = typeof identity?.in_group_ratio === "number"
|
||||||
|
? identity.in_group_ratio * 100
|
||||||
|
: null;
|
||||||
|
const outGroupWordRate = typeof identity?.out_group_ratio === "number"
|
||||||
|
? identity.out_group_ratio * 100
|
||||||
|
: null;
|
||||||
const rawEntities = data.avg_emotion_per_entity?.entity_emotion_avg ?? {};
|
const rawEntities = data.avg_emotion_per_entity?.entity_emotion_avg ?? {};
|
||||||
const entities = Object.entries(rawEntities)
|
const entities = Object.entries(rawEntities)
|
||||||
.sort((a, b) => (b[1].post_count - a[1].post_count))
|
.sort((a, b) => (b[1].post_count - a[1].post_count))
|
||||||
@@ -25,77 +34,107 @@ const CulturalStats = ({ data }: CulturalStatsProps) => {
|
|||||||
entries.sort((a, b) => b[1] - a[1]);
|
entries.sort((a, b) => b[1] - a[1]);
|
||||||
const dominant = entries[0] ?? ["emotion_unknown", 0];
|
const dominant = entries[0] ?? ["emotion_unknown", 0];
|
||||||
const dominantLabel = dominant[0].replace("emotion_", "");
|
const dominantLabel = dominant[0].replace("emotion_", "");
|
||||||
return `${dominantLabel} (${dominant[1].toFixed(3)})`;
|
return `${dominantLabel} (${(dominant[1] * 100).toFixed(1)}%)`;
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={styles.page}>
|
<div style={styles.page}>
|
||||||
<div style={{ ...styles.container, ...styles.grid }}>
|
<div style={{ ...styles.container, ...styles.grid }}>
|
||||||
|
<div style={{ ...styles.card, gridColumn: "span 12" }}>
|
||||||
|
<h2 style={styles.sectionTitle}>Community Framing Overview</h2>
|
||||||
|
<p style={styles.sectionSubtitle}>Simple view of how often people use "us" words vs "them" words, and the tone around that language.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Card
|
<Card
|
||||||
label="In-Group Usage"
|
label="In-Group Words"
|
||||||
value={identity?.in_group_usage?.toLocaleString() ?? "—"}
|
value={inGroupWords.toLocaleString()}
|
||||||
sublabel="we/us/our references"
|
sublabel="Times we/us/our appears"
|
||||||
style={{ gridColumn: "span 3" }}
|
style={{ gridColumn: "span 3" }}
|
||||||
/>
|
/>
|
||||||
<Card
|
<Card
|
||||||
label="Out-Group Usage"
|
label="Out-Group Words"
|
||||||
value={identity?.out_group_usage?.toLocaleString() ?? "—"}
|
value={outGroupWords.toLocaleString()}
|
||||||
sublabel="they/them/their references"
|
sublabel="Times they/them/their appears"
|
||||||
style={{ gridColumn: "span 3" }}
|
style={{ gridColumn: "span 3" }}
|
||||||
/>
|
/>
|
||||||
<Card
|
<Card
|
||||||
label="In-Group Posts"
|
label="In-Group Posts"
|
||||||
value={identity?.in_group_posts?.toLocaleString() ?? "—"}
|
value={identity?.in_group_posts?.toLocaleString() ?? "—"}
|
||||||
sublabel="Posts with stronger in-group language"
|
sublabel='Posts leaning toward "us" language'
|
||||||
style={{ gridColumn: "span 3" }}
|
style={{ gridColumn: "span 3" }}
|
||||||
/>
|
/>
|
||||||
<Card
|
<Card
|
||||||
label="Out-Group Posts"
|
label="Out-Group Posts"
|
||||||
value={identity?.out_group_posts?.toLocaleString() ?? "—"}
|
value={identity?.out_group_posts?.toLocaleString() ?? "—"}
|
||||||
sublabel="Posts with stronger out-group language"
|
sublabel='Posts leaning toward "them" language'
|
||||||
style={{ gridColumn: "span 3" }}
|
style={{ gridColumn: "span 3" }}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Card
|
<Card
|
||||||
label="Hedge Markers"
|
label="Balanced Posts"
|
||||||
|
value={identity?.tie_posts?.toLocaleString() ?? "—"}
|
||||||
|
sublabel="Posts with equal us/them signals"
|
||||||
|
style={{ gridColumn: "span 3" }}
|
||||||
|
/>
|
||||||
|
<Card
|
||||||
|
label="Total Group Words"
|
||||||
|
value={totalGroupWords.toLocaleString()}
|
||||||
|
sublabel="In-group + out-group words"
|
||||||
|
style={{ gridColumn: "span 3" }}
|
||||||
|
/>
|
||||||
|
<Card
|
||||||
|
label="In-Group Share"
|
||||||
|
value={inGroupWordRate === null ? "—" : `${inGroupWordRate.toFixed(2)}%`}
|
||||||
|
sublabel="Share of all words"
|
||||||
|
style={{ gridColumn: "span 3" }}
|
||||||
|
/>
|
||||||
|
<Card
|
||||||
|
label="Out-Group Share"
|
||||||
|
value={outGroupWordRate === null ? "—" : `${outGroupWordRate.toFixed(2)}%`}
|
||||||
|
sublabel="Share of all words"
|
||||||
|
style={{ gridColumn: "span 3" }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Card
|
||||||
|
label="Hedging Words"
|
||||||
value={stance?.hedge_total?.toLocaleString() ?? "—"}
|
value={stance?.hedge_total?.toLocaleString() ?? "—"}
|
||||||
sublabel={typeof stance?.hedge_per_1k_tokens === "number" ? `${stance.hedge_per_1k_tokens.toFixed(3)} per 1k tokens` : "Marker frequency"}
|
sublabel={typeof stance?.hedge_per_1k_tokens === "number" ? `${stance.hedge_per_1k_tokens.toFixed(1)} per 1k words` : "Word frequency"}
|
||||||
style={{ gridColumn: "span 3" }}
|
style={{ gridColumn: "span 3" }}
|
||||||
/>
|
/>
|
||||||
<Card
|
<Card
|
||||||
label="Certainty Markers"
|
label="Certainty Words"
|
||||||
value={stance?.certainty_total?.toLocaleString() ?? "—"}
|
value={stance?.certainty_total?.toLocaleString() ?? "—"}
|
||||||
sublabel={typeof stance?.certainty_per_1k_tokens === "number" ? `${stance.certainty_per_1k_tokens.toFixed(3)} per 1k tokens` : "Marker frequency"}
|
sublabel={typeof stance?.certainty_per_1k_tokens === "number" ? `${stance.certainty_per_1k_tokens.toFixed(1)} per 1k words` : "Word frequency"}
|
||||||
style={{ gridColumn: "span 3" }}
|
style={{ gridColumn: "span 3" }}
|
||||||
/>
|
/>
|
||||||
<Card
|
<Card
|
||||||
label="Deontic Markers"
|
label="Need/Should Words"
|
||||||
value={stance?.deontic_total?.toLocaleString() ?? "—"}
|
value={stance?.deontic_total?.toLocaleString() ?? "—"}
|
||||||
sublabel={typeof stance?.deontic_per_1k_tokens === "number" ? `${stance.deontic_per_1k_tokens.toFixed(3)} per 1k tokens` : "Marker frequency"}
|
sublabel={typeof stance?.deontic_per_1k_tokens === "number" ? `${stance.deontic_per_1k_tokens.toFixed(1)} per 1k words` : "Word frequency"}
|
||||||
style={{ gridColumn: "span 3" }}
|
style={{ gridColumn: "span 3" }}
|
||||||
/>
|
/>
|
||||||
<Card
|
<Card
|
||||||
label="Permission Markers"
|
label="Permission Words"
|
||||||
value={stance?.permission_total?.toLocaleString() ?? "—"}
|
value={stance?.permission_total?.toLocaleString() ?? "—"}
|
||||||
sublabel={typeof stance?.permission_per_1k_tokens === "number" ? `${stance.permission_per_1k_tokens.toFixed(3)} per 1k tokens` : "Marker frequency"}
|
sublabel={typeof stance?.permission_per_1k_tokens === "number" ? `${stance.permission_per_1k_tokens.toFixed(1)} per 1k words` : "Word frequency"}
|
||||||
style={{ gridColumn: "span 3" }}
|
style={{ gridColumn: "span 3" }}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div style={{ ...styles.card, gridColumn: "span 6" }}>
|
<div style={{ ...styles.card, gridColumn: "span 6" }}>
|
||||||
<h2 style={styles.sectionTitle}>In-Group Emotion Profile</h2>
|
<h2 style={styles.sectionTitle}>Mood in "Us" Posts</h2>
|
||||||
<p style={styles.sectionSubtitle}>Dominant average emotion where in-group framing is stronger.</p>
|
<p style={styles.sectionSubtitle}>Most likely emotion when in-group wording is stronger.</p>
|
||||||
<div style={styles.topUserName}>{topEmotion(identity?.in_group_emotion_avg)}</div>
|
<div style={styles.topUserName}>{topEmotion(identity?.in_group_emotion_avg)}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ ...styles.card, gridColumn: "span 6" }}>
|
<div style={{ ...styles.card, gridColumn: "span 6" }}>
|
||||||
<h2 style={styles.sectionTitle}>Out-Group Emotion Profile</h2>
|
<h2 style={styles.sectionTitle}>Mood in "Them" Posts</h2>
|
||||||
<p style={styles.sectionSubtitle}>Dominant average emotion where out-group framing is stronger.</p>
|
<p style={styles.sectionSubtitle}>Most likely emotion when out-group wording is stronger.</p>
|
||||||
<div style={styles.topUserName}>{topEmotion(identity?.out_group_emotion_avg)}</div>
|
<div style={styles.topUserName}>{topEmotion(identity?.out_group_emotion_avg)}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ ...styles.card, gridColumn: "span 12" }}>
|
<div style={{ ...styles.card, gridColumn: "span 12" }}>
|
||||||
<h2 style={styles.sectionTitle}>Entity Emotion Averages</h2>
|
<h2 style={styles.sectionTitle}>Entity Mood Snapshot</h2>
|
||||||
<p style={styles.sectionSubtitle}>Most frequent entities and their dominant average emotion signature.</p>
|
<p style={styles.sectionSubtitle}>Most mentioned entities and the mood that appears most with each.</p>
|
||||||
{!entities.length ? (
|
{!entities.length ? (
|
||||||
<div style={styles.topUserMeta}>No entity-level cultural data available.</div>
|
<div style={styles.topUserMeta}>No entity-level cultural data available.</div>
|
||||||
) : (
|
) : (
|
||||||
@@ -104,7 +143,7 @@ const CulturalStats = ({ data }: CulturalStatsProps) => {
|
|||||||
<div key={entity} style={styles.topUserItem}>
|
<div key={entity} style={styles.topUserItem}>
|
||||||
<div style={styles.topUserName}>{entity}</div>
|
<div style={styles.topUserName}>{entity}</div>
|
||||||
<div style={styles.topUserMeta}>
|
<div style={styles.topUserMeta}>
|
||||||
{aggregate.post_count.toLocaleString()} posts • Dominant emotion: {topEmotion(aggregate.emotion_avg)}
|
{aggregate.post_count.toLocaleString()} posts • Likely mood: {topEmotion(aggregate.emotion_avg)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ const AutoScrapePage = () => {
|
|||||||
Select sources and scrape settings, then queue processing automatically.
|
Select sources and scrape settings, then queue processing automatically.
|
||||||
</p>
|
</p>
|
||||||
<p style={{ ...styles.subtleBodyText, marginTop: 6, color: "#9a6700" }}>
|
<p style={{ ...styles.subtleBodyText, marginTop: 6, color: "#9a6700" }}>
|
||||||
Warning: Scraping more than 250 posts from any single site can take hours.
|
Warning: Scraping more than 250 posts from any single site can take hours due to rate limits.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
|
|||||||
Reference in New Issue
Block a user