Updated radar chart

This commit is contained in:
Artorias 2025-03-23 21:22:40 +01:00
parent b831c34f52
commit a9e251d5b7
2 changed files with 79 additions and 59 deletions

View file

@ -5,7 +5,8 @@
<#include "header.ftl">
<script src="https://d3js.org/d3.v7.min.js"></script>
<body>
<h2>Chart Sortiment</h2>
<h1>Chart Sortiment</h1>
<h2>NLP Analyse aller Reden</h2>
<div class="chart-container">
<div class="chart">
<#if aggregatedTopics?? && (aggregatedTopics?size gt 0)>

View file

@ -13,105 +13,124 @@
<#else>
sentimentData.push({ pos: 0, neu: 0, neg: 0 });
</#if>
console.log("Sentiment Data:", sentimentData);
var width = 1000, height = 1000;
var svg = d3.select("#sentimentsRadarChart")
.attr("width", width)
.attr("height", height);
var centerX = width / 2, centerY = height / 2;
var maxRadius = 400; // Maximum radius for the chart
// Create a radial scale (assumes sentiment values are normalized between 0 and 1)
var rScale = d3.scaleLinear()
.domain([0, 1])
.range([0, maxRadius]);
var centerX = width / 2 - 100, centerY = height / 2;
var maxRadius = 400;
// All relevant radar chart axes
var rScale = d3.scaleLinear().domain([0,1]).range([0,maxRadius]);
var axes = [
{ axis: "Positive", angle: 0 },
{ axis: "Neutral", angle: 120 },
{ axis: "Negative", angle: 240 }
];
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)
};
function polarToCartesian(cx, cy, r, angle) {
var rad = (angle - 90) * Math.PI/180;
return { x: cx + r * Math.cos(rad), y: cy + r * Math.sin(rad) };
}
// Draw grid (web) lines
// Draw grid (web)
var gridSteps = 5;
var gridLine = d3.line()
.x(d => d.x)
.y(d => d.y)
.curve(d3.curveLinearClosed);
for (var i = 1; i <= gridSteps; i++) {
var step = i / gridSteps;
var gridPoints = axes.map(function(d) {
var r = step * maxRadius;
return polarToCartesian(centerX, centerY, r, d.angle);
});
var pts = axes.map(d => polarToCartesian(centerX, centerY, step * maxRadius, d.angle));
svg.append("path")
.datum(gridPoints)
.attr("d", d3.line()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
.curve(d3.curveLinearClosed)
)
.datum(pts)
.attr("d", gridLine)
.attr("stroke", "#aaa")
.attr("stroke-width", 1)
.attr("fill", "none");
}
// Draw axis lines and labels
axes.forEach(function(d) {
var endPoint = polarToCartesian(centerX, centerY, maxRadius, d.angle);
// Draw axes & labels
axes.forEach(d => {
var end = 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", "#aaaaaa")
.attr("x1", centerX).attr("y1", centerY)
.attr("x2", end.x).attr("y2", end.y)
.attr("stroke", "#aaa")
.attr("stroke-width", 1);
var labelOffset = 20;
var labelPoint = polarToCartesian(centerX, centerY, maxRadius + labelOffset, d.angle);
var lbl = polarToCartesian(centerX, centerY, maxRadius + 20, d.angle);
svg.append("text")
.attr("x", labelPoint.x)
.attr("y", labelPoint.y)
.attr("x", lbl.x).attr("y", lbl.y)
.attr("text-anchor", "middle")
.style("font-size", "14px")
.text(d.axis);
});
var colors = d3.schemeCategory10;
// Generate unique random colors
var colors = [];
sentimentData.forEach(() => {
let color;
do {
color = '#' + Math.floor(Math.random() * 16777215).toString(16).padStart(6, '0');
} while (colors.includes(color));
colors.push(color);
});
var radarLine = d3.line()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
.x(d => d.x)
.y(d => d.y)
.curve(d3.curveLinearClosed);
sentimentData.forEach(function(sent, i) {
// Map each axis to a point using the sentiment value for that axis.
var polygonPoints = axes.map(function(d) {
var value;
if (d.axis === "Positive") {
value = sent.pos;
} else if (d.axis === "Neutral") {
value = sent.neu;
} else if (d.axis === "Negative") {
value = sent.neg;
}
var r = rScale(value);
return polarToCartesian(centerX, centerY, r, d.angle);
// Plot radar series
sentimentData.forEach((sent, i) => {
var pts = axes.map(d => {
var val = d.axis === "Positive" ? sent.pos : (d.axis === "Neutral" ? sent.neu : sent.neg);
return polarToCartesian(centerX, centerY, rScale(val), d.angle);
});
svg.append("path")
.datum(polygonPoints)
.datum(pts)
.attr("class", "radar-path radar-path-" + i)
.attr("d", radarLine)
.attr("stroke", colors[i % colors.length])
.attr("stroke", colors[i])
.attr("stroke-width", 2)
.attr("fill", colors[i % colors.length])
.attr("fill", colors[i])
.attr("fill-opacity", 0.3);
});
// Legend with wrap every 30 entries & hover highlight + bring to front
var legend = svg.append("g").attr("transform", "translate(" + (width - 200) + ",50)");
sentimentData.forEach((_, i) => {
var col = Math.floor(i/30), row = i%30;
var entry = legend.append("g")
.attr("transform", "translate(" + (col*100) + "," + (row*20) + ")")
.on("mouseover", () => {
d3.select(".radar-path-" + i).raise()
.attr("stroke-width", 4)
.attr("fill-opacity", 0.6);
})
.on("mouseout", () => {
d3.select(".radar-path-" + i)
.attr("stroke-width", 2)
.attr("fill-opacity", 0.3);
});
entry.append("rect")
.attr("width", 12)
.attr("height", 12)
.attr("fill", colors[i]);
entry.append("text")
.attr("x", 16)
.attr("y", 10)
.style("font-size", "12px")
.text(i === 0 ? "Rede" : "Satz " + i);
});
</script>

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Before After
Before After