UX: Make sentiment trends more readable (#1018)

Instead of a stacked chart showing a separate series for positive and negative, this PR introduces a simplification to the overall sentiment dashboard. It comprises the sentiment into a single series of the difference between `positive - negative` instead. This should allow for the data to be more easy to scan and look for trends
This commit is contained in:
Keegan George 2024-12-12 02:13:18 +09:00 committed by GitHub
parent 5fc7a730ef
commit a4440c507b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 15 additions and 25 deletions

View File

@ -400,9 +400,7 @@ en:
sentiment: sentiment:
reports: reports:
overall_sentiment: overall_sentiment: "Overall sentiment (Positive - Negative)"
positive: "Positive"
negative: "Negative"
post_emotion: post_emotion:
sadness: "Sadness 😢" sadness: "Sadness 😢"
surprise: "Surprise 😱" surprise: "Surprise 😱"

View File

@ -11,7 +11,7 @@ module DiscourseAi
sentiment_count_sql = Proc.new { |sentiment| <<~SQL } sentiment_count_sql = Proc.new { |sentiment| <<~SQL }
COUNT( COUNT(
CASE WHEN (cr.classification::jsonb->'#{sentiment}')::float > :threshold THEN 1 ELSE NULL END CASE WHEN (cr.classification::jsonb->'#{sentiment}')::float > :threshold THEN 1 ELSE NULL END
) AS #{sentiment}_count )
SQL SQL
grouped_sentiments = grouped_sentiments =
@ -19,8 +19,7 @@ module DiscourseAi
<<~SQL, <<~SQL,
SELECT SELECT
DATE_TRUNC('day', p.created_at)::DATE AS posted_at, DATE_TRUNC('day', p.created_at)::DATE AS posted_at,
#{sentiment_count_sql.call("positive")}, #{sentiment_count_sql.call("positive")} - #{sentiment_count_sql.call("negative")} AS sentiment_count
-#{sentiment_count_sql.call("negative")}
FROM FROM
classification_results AS cr classification_results AS cr
INNER JOIN posts p ON p.id = cr.target_id AND cr.target_type = 'Post' INNER JOIN posts p ON p.id = cr.target_id AND cr.target_type = 'Post'
@ -32,30 +31,26 @@ module DiscourseAi
cr.model_used = 'cardiffnlp/twitter-roberta-base-sentiment-latest' AND cr.model_used = 'cardiffnlp/twitter-roberta-base-sentiment-latest' AND
(p.created_at > :report_start AND p.created_at < :report_end) (p.created_at > :report_start AND p.created_at < :report_end)
GROUP BY DATE_TRUNC('day', p.created_at) GROUP BY DATE_TRUNC('day', p.created_at)
ORDER BY 1 ASC
SQL SQL
report_start: report.start_date, report_start: report.start_date,
report_end: report.end_date, report_end: report.end_date,
threshold: threshold, threshold: threshold,
) )
data_points = %w[positive negative]
return report if grouped_sentiments.empty? return report if grouped_sentiments.empty?
report.data = report.data = {
data_points.map do |point| req: "overall_sentiment",
{ color: report.colors[:lime],
req: "sentiment_#{point}", label: I18n.t("discourse_ai.sentiment.reports.overall_sentiment"),
color: point == "positive" ? report.colors[:lime] : report.colors[:purple],
label: I18n.t("discourse_ai.sentiment.reports.overall_sentiment.#{point}"),
data: data:
grouped_sentiments.map do |gs| grouped_sentiments.map do |gs|
{ x: gs.posted_at, y: gs.public_send("#{point}_count") } { x: gs.posted_at, y: gs.public_send("sentiment_count") }
end, end,
} }
end end
end end
end end
end end
end
end end

View File

@ -77,11 +77,8 @@ RSpec.describe DiscourseAi::Sentiment::EntryPoint do
sentiment_classification(pm, positive_classification) sentiment_classification(pm, positive_classification)
report = Report.find("overall_sentiment") report = Report.find("overall_sentiment")
positive_data_point = report.data[0][:data].first[:y].to_i overall_sentiment = report.data[:data][0][:y].to_i
negative_data_point = report.data[1][:data].first[:y].to_i expect(overall_sentiment).to eq(0)
expect(positive_data_point).to eq(1)
expect(negative_data_point).to eq(-1)
end end
end end