Updated radar chart
This commit is contained in:
parent
b831c34f52
commit
a9e251d5b7
2 changed files with 79 additions and 59 deletions
|
@ -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)>
|
||||
|
|
|
@ -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 |
Loading…
Add table
Add a link
Reference in a new issue