Developing grounds for the Radar Chart

This commit is contained in:
Artorias 2025-03-20 19:47:00 +01:00
parent 5d6cb314a1
commit a9edbe8477
5 changed files with 130 additions and 13 deletions

View file

@ -4,6 +4,7 @@ import org.bson.Document;
import org.texttechnologylab.project.gruppe_05_1.database.MongoDBHandler;
import org.texttechnologylab.project.gruppe_05_1.database.MongoPprUtils;
import org.texttechnologylab.project.gruppe_05_1.domain.nlp.NlpInfo;
import org.texttechnologylab.project.gruppe_05_1.domain.nlp.Sentiment;
import org.texttechnologylab.project.gruppe_05_1.domain.nlp.Token;
import org.texttechnologylab.project.gruppe_05_1.domain.nlp.Topic;
import org.texttechnologylab.project.gruppe_05_1.domain.speech.SpeechMetaData;
@ -69,7 +70,8 @@ public class HtmlSpeech {
List<Document> namedEntitiesDocs = nlpDoc.get("namedEntities", MongoDBHandler.DOC_LIST_CLASS);
List<Document> sentimentsDocs = nlpDoc.get("sentiments", MongoDBHandler.DOC_LIST_CLASS);
List<Document> sentimentDocs = nlpDoc.get("sentiments", MongoDBHandler.DOC_LIST_CLASS);
nlp.setSentiments(List.of(Sentiment.readFirstSentimentFromMongo(sentimentDocs)));
List<Document> topicsDocs = nlpDoc.get("topics", MongoDBHandler.DOC_LIST_CLASS);
nlp.setTopics(Topic.readTopicsFromMongo(topicsDocs));

View file

@ -1,5 +1,9 @@
package org.texttechnologylab.project.gruppe_05_1.domain.nlp;
import org.bson.Document;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.StringJoiner;
@ -94,4 +98,15 @@ public class Sentiment {
.add("positive=" + positive)
.toString();
}
public static Sentiment readFirstSentimentFromMongo(List<Document> sentimentDocs) {
Document doc = sentimentDocs.get(0);
return new Sentiment(doc.getInteger("begin"),
doc.getInteger("end"),
doc.getDouble("score"),
doc.getDouble("pos"),
doc.getDouble("neu"),
doc.getDouble("neg")
);
}
}

View file

@ -194,15 +194,25 @@ public class FrontEndController {
}
// NLP: Sentiments
Sentiment speechSentiment = null;
Sentiment sentimentObj = null;
if (speech.getNlp() != null && speech.getNlp().getSentiments() != null && !speech.getNlp().getSentiments().isEmpty()) {
speechSentiment = speech.getNlp().getSentiments().get(0); // Get the first sentiment
Sentiment first = speech.getNlp().getSentiments().get(0);
sentimentObj = new Sentiment(
first.getBegin(),
first.getEnd(),
first.getSentiment(),
first.getNegative(),
first.getNeutral(),
first.getPositive()
);
} else {
// No sentiment found: use a default sentiment with zero values
sentimentObj = new Sentiment(0, 0, 0.0, 0.0, 0.0, 0.0);
}
System.out.println("DEBUG: Speech Sentiment - " + speechSentiment);
// Pass sentiment data to FreeMarker
attributes.put("sentiment", speechSentiment);
System.out.println("DEBUG: Speech Sentiment - " + sentimentObj);
attributes.put("sentiment", sentimentObj);
ctx.render("speech.ftl", attributes);
}

View file

@ -15,11 +15,10 @@
</#if>
<#if s.nlp.sentiments??>
<h3>SentimentsInformation (als Radar Chart)</h3>
<#assign overallSentiment = s.nlp.overallSentiment>
<#assign sentiments = s.nlp.sentiments>
<#include "sentimentsRadarChart.ftl">
<#if s.nlp.sentiment??>
<#assign sentiment = s.nlp.sentiment?first>
<h3>Sentiments Information (als Radar Chart)</h3>
<#include "sentimentsRadarChart.ftl">
<#else>
<h3>Keine Sentiments Information für diese Rede verfügbar</h3>
</#if>

View file

@ -0,0 +1,91 @@
<svg id="sentimentsRadarChart" width="500" height="500"></svg>
<script src="https://d3js.org/d3.v6.min.js"></script>
<script>
// Retrieve sentiment values from the passed attribute "sentiment"
var sentimentData = {
pos: "${sentiment.positive}",
neu: "${sentiment.negative}",
neg: "${sentiment.neutral}"
};
console.log("Sentiment Data:", sentimentData);
// Set up SVG dimensions and center the chart
var width = 500, height = 500;
var svg = d3.select("#sentimentsRadarChart")
.attr("width", width)
.attr("height", height);
var centerX = width / 2, centerY = height / 2;
var maxRadius = 200; // Maximum radius for the chart
// Create a radial scale assuming sentiment values are normalized between 0 and 1
var rScale = d3.scaleLinear()
.domain([0, 1])
.range([0, maxRadius]);
// Define the three axes for the radar chart with fixed angles (in degrees)
var axes = [
{ axis: "Positive", angle: 0, value: sentimentData.pos },
{ axis: "Neutral", angle: 120, value: sentimentData.neu },
{ axis: "Negative", angle: 240, value: sentimentData.neg }
];
// Function to convert polar coordinates to cartesian
function polarToCartesian(cx, cy, r, angleDegrees) {
var angleRadians = (angleDegrees - 90) * Math.PI / 180;
return {
x: cx + r * Math.cos(angleRadians),
y: cy + r * Math.sin(angleRadians)
};
}
// Draw axis lines and labels
axes.forEach(function(d) {
var endPoint = polarToCartesian(centerX, centerY, maxRadius, d.angle);
svg.append("line")
.attr("x1", centerX)
.attr("y1", centerY)
.attr("x2", endPoint.x)
.attr("y2", endPoint.y)
.attr("stroke", "#ccc")
.attr("stroke-width", 1);
var labelOffset = 20;
var labelPoint = polarToCartesian(centerX, centerY, maxRadius + labelOffset, d.angle);
svg.append("text")
.attr("x", labelPoint.x)
.attr("y", labelPoint.y)
.attr("text-anchor", "middle")
.style("font-size", "14px")
.text(d.axis);
});
// Compute radar chart data points from sentiment values
var radarPoints = axes.map(function(d) {
var r = rScale(d.value);
return polarToCartesian(centerX, centerY, r, d.angle);
});
console.log("Radar Points:", radarPoints);
// Create a closed polygon from the radar points
var radarLine = d3.line()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
.curve(d3.curveLinearClosed);
svg.append("path")
.datum(radarPoints)
.attr("d", radarLine)
.attr("stroke", "blue")
.attr("stroke-width", 2)
.attr("fill", "blue")
.attr("fill-opacity", 0.3);
// Draw circles at each radar point
radarPoints.forEach(function(point) {
svg.append("circle")
.attr("cx", point.x)
.attr("cy", point.y)
.attr("r", 4)
.attr("fill", "red");
});
</script>

Before

Width:  |  Height:  |  Size: 0 B

After

Width:  |  Height:  |  Size: 3.1 KiB

Before After
Before After