Public
Edited
Dec 9, 2023
Insert cell
md`# Tonal Sad music`
Insert cell
Part A.csv
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
myfile
Insert cell
Untitled spreadsheet - Sheet2.csv
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
data1 = [
//E1
{ axis: "Valence", value: 76.35, type: "E1" },
{ axis: "Arousal", value: 79.83, type: "E1" },
{ axis: "Pleasure", value: 64.00, type: "E1" },
{ axis: "Familiarity", value: 21.15, type: "E1" },
//E4
{ axis: "Valence", value: 69.52, type: "E4" },
{ axis: "Arousal", value: 66.68, type: "E4" },
{ axis: "Pleasure", value: 62.57, type: "E4" },
{ axis: "Familiarity", value: 17.98, type: "E4" }
];
Insert cell
data1.map(d => d.type) // you need to define the filter category which is by song, so in your data you need to have a song column do you can filter by that define it here
.filter((value, index, self) => self.indexOf(value) === index)
Insert cell
Insert cell
cell = {

//////////////////////////////////////////////////////////////
//////////////////////// Set-Up //////////////////////////////
//////////////////////////////////////////////////////////////

////////////E5-E8//////////Tonal Sad

var margin = { top: 100, right: 100, bottom: 100, left: 100 },
width = Math.min(700, window.innerWidth - 10) - margin.left - margin.right,
height = Math.min(
width,
window.innerHeight - margin.top - margin.bottom - 20
);

//////////////////////////////////////////////////////////////
////////////////////////// Data //////////////////////////////
//////////////////////////////////////////////////////////////

var data = [
[
//E7
{ axis: "Valence", value: -41.05 },
{ axis: "Arousal", value: -46.97 },
{ axis: "Pleasure", value: -6.13 },
{ axis: "Familiarity", value: -23.83 }
],
[
//E5
{ axis: "Valence", value: -32.08 },
{ axis: "Arousal", value: -40.05 },
{ axis: "Pleasure", value: 25.00 },
{ axis: "Familiarity", value: 0.63 }
],
[
//E6
{ axis: "Valence", value: -24.02 },
{ axis: "Arousal", value: -28.17 },
{ axis: "Pleasure", value: 45.10 },
{ axis: "Familiarity", value: 7.42 }
],
[
//E8
{ axis: "Valence", value: -24.78 },
{ axis: "Arousal", value: -27.43 },
{ axis: "Pleasure", value: 37.25 },
{ axis: "Familiarity", value: 1.30 }
]
];
//////////////////////////////////////////////////////////////
//////////////////// Draw the Chart //////////////////////////
//////////////////////////////////////////////////////////////

var color = d3.scaleOrdinal().range(["#8F00FF", "#FFA500", "#FFE5B4", "#964B00"]); //lilac, salmon, peach, sky blue

var radarChartOptions = {
w: width,
h: height,
margin: margin,
maxValue: 0.5,
levels: 5,
roundStrokes: true,
color: color
};
//Call function to draw the Radar chart
return RadarChart(data, radarChartOptions);
}
Insert cell
function RadarChart(data, options) {

/////////////////////////////////////////////////////////
/////////////////// Helper Function /////////////////////
/////////////////////////////////////////////////////////

//Taken from http://bl.ocks.org/mbostock/7555321
//Wraps SVG text
function wrap(text, width) {
text.each(function() {
var text = d3.select(this),
words = text
.text()
.split(/\s+/)
.reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = 1.4, // ems
y = text.attr("y"),
x = text.attr("x"),
dy = parseFloat(text.attr("dy")),
tspan = text
.text(null)
.append("tspan")
.attr("x", x)
.attr("y", y)
.attr("dy", dy + "em");

while ((word = words.pop())) {
line.push(word);
tspan.text(line.join(" "));
if (tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(" "));
line = [word];
tspan = text
.append("tspan")
.attr("x", x)
.attr("y", y)
.attr("dy", ++lineNumber * lineHeight + dy + "em")
.text(word);
}
}
});
} //wrap

var cfg = {
w: 600, //Width of the circle
h: 600, //Height of the circle
margin: { top: 20, right: 20, bottom: 20, left: 20 }, //The margins of the SVG
levels: 3, //How many levels or inner circles should there be drawn
maxValue: 0, //What is the value that the biggest circle will represent
labelFactor: 1.25, //How much farther than the radius of the outer circle should the labels be placed
wrapWidth: 60, //The number of pixels after which a label needs to be given a new line
opacityArea: 0.35, //The opacity of the area of the blob
dotRadius: 4, //The size of the colored circles of each blog
opacityCircles: 0.1, //The opacity of the circles of each blob
strokeWidth: 2, //The width of the stroke around each blob
roundStrokes: false, //If true the area and stroke will follow a round path (cardinal-closed)
color: d3.scaleOrdinal(d3.schemeCategory10) //Color function
};

//Put all of the options into a variable called cfg
if ("undefined" !== typeof options) {
for (var i in options) {
if ("undefined" !== typeof options[i]) {
cfg[i] = options[i];
}
} //for i
} //if

//If the supplied maxValue is smaller than the actual one, replace by the max in the data
var maxValue = Math.max(
cfg.maxValue,
d3.max(data, function(i) {
return d3.max(
i.map(function(o) {
return o.value;
})
);
})
);

var allAxis = data[0].map(function(i, j) {
return i.axis;
}), //Names of each axis
total = allAxis.length, //The number of different axes
radius = Math.min(cfg.w / 2, cfg.h / 2), //Radius of the outermost circle
Format = d3.format("%"), //Percentage formatting
angleSlice = (Math.PI * 2) / total; //The width in radians of each "slice"

//Scale for the radius
var rScale = d3
.scaleLinear()
.range([0, radius])
.domain([0, maxValue]);

/////////////////////////////////////////////////////////
//////////// Create the container SVG and g /////////////
/////////////////////////////////////////////////////////

//Calculate width and height
var height = cfg.h + cfg.margin.top + cfg.margin.bottom;
var width = cfg.w + cfg.margin.left + cfg.margin.right;
//Initiate the radar chart SVG
var svg = d3
.select(DOM.svg(width, height))
.attr("class", +new Date());
//Append a g element
var g = svg
.append("g")
.attr(
"transform",
"translate(" +
(cfg.w / 2 + cfg.margin.left) +
"," +
(cfg.h / 2 + cfg.margin.top) +
")"
);

/////////////////////////////////////////////////////////
////////// Glow filter for some extra pizzazz ///////////
/////////////////////////////////////////////////////////

//Filter for the outside glow
var filter = g
.append("defs")
.append("filter")
.attr("id", "glow"),
feGaussianBlur = filter
.append("feGaussianBlur")
.attr("stdDeviation", "2.5")
.attr("result", "coloredBlur"),
feMerge = filter.append("feMerge"),
feMergeNode_1 = feMerge.append("feMergeNode").attr("in", "coloredBlur"),
feMergeNode_2 = feMerge.append("feMergeNode").attr("in", "SourceGraphic");

/////////////////////////////////////////////////////////
/////////////// Draw the Circular grid //////////////////
/////////////////////////////////////////////////////////

//Wrapper for the grid & axes
var axisGrid = g.append("g").attr("class", "axisWrapper");

//Draw the background circles
axisGrid
.selectAll(".levels")
.data(d3.range(1, cfg.levels + 1).reverse())
.enter()
.append("circle")
.attr("class", "gridCircle")
.attr("r", function(d, i) {
return (radius / cfg.levels) * d;
})
.style("fill", "#CDCDCD")
.style("stroke", "#CDCDCD")
.style("fill-opacity", cfg.opacityCircles)
.style("filter", "url(#glow)");

//Text indicating at what % each level is
axisGrid
.selectAll(".axisLabel")
.data(d3.range(1, cfg.levels + 1).reverse())
.enter()
.append("text")
.attr("class", "axisLabel")
.attr("x", 4)
.attr("y", function(d) {
return (-d * radius) / cfg.levels;
})
.attr("dy", "10em")
.style("font-size", "100px")
.attr("fill", "#737373")
.text(function(d, i) {
return Format((maxValue * d) / cfg.levels);
});

/////////////////////////////////////////////////////////
//////////////////// Draw the axes //////////////////////
/////////////////////////////////////////////////////////

//Create the straight lines radiating outward from the center
var axis = axisGrid
.selectAll(".axis")
.data(allAxis)
.enter()
.append("g")
.attr("class", "axis");
//Append the lines
axis
.append("line")
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", function(d, i) {
return rScale(maxValue * 1.1) * Math.cos(angleSlice * i - Math.PI / 2);
})
.attr("y2", function(d, i) {
return rScale(maxValue * 1.1) * Math.sin(angleSlice * i - Math.PI / 2);
})
.attr("class", "line")
.style("stroke", "white")
.style("stroke-width", "2px");

//Append the labels at each axis
axis
.append("text")
.attr("class", "legend")
.style("font-size", "15p15x")
.attr("text-anchor", "middle")
.attr("dy", "0.35em")
.attr("x", function(d, i) {
return (
rScale(maxValue * cfg.labelFactor) *
Math.cos(angleSlice * i - Math.PI / 2)
);
})
.attr("y", function(d, i) {
return (
rScale(maxValue * cfg.labelFactor) *
Math.sin(angleSlice * i - Math.PI / 2)
);
})
.text(function(d) {
return d;
})
.call(wrap, cfg.wrapWidth);

/////////////////////////////////////////////////////////
///////////// Draw the radar chart blobs ////////////////
/////////////////////////////////////////////////////////

//The radial line function
var radarLine = d3
.lineRadial()
.curve(d3.curveBasisClosed)
.radius(function(d) {
return rScale(d.value);
})
.angle(function(d, i) {
return i * angleSlice;
});

if (cfg.roundStrokes) {
radarLine.curve(d3.curveCardinalClosed);
}

//Create a wrapper for the blobs
var blobWrapper = g
.selectAll(".radarWrapper")
.data(data)
.enter()
.append("g")
.attr("class", "radarWrapper");

//Append the backgrounds
blobWrapper
.append("path")
.attr("class", "radarArea")
.attr("d", function(d, i) {
return radarLine(d);
})
.style("fill", function(d, i) {
return cfg.color(i);
})
.style("fill-opacity", cfg.opacityArea)
.on("mouseover", function(d, i) {
//Dim all blobs
d3.selectAll(".radarArea")
.transition()
.duration(200)
.style("fill-opacity", 0.1);
//Bring back the hovered over blob
d3.select(this)
.transition()
.duration(200)
.style("fill-opacity", 0.7);
})
.on("mouseout", function() {
//Bring back all blobs
d3.selectAll(".radarArea")
.transition()
.duration(200)
.style("fill-opacity", cfg.opacityArea);
});

//Create the outlines
blobWrapper
.append("path")
.attr("class", "radarStroke")
.attr("d", function(d, i) {
return radarLine(d);
})
.style("stroke-width", cfg.strokeWidth + "px")
.style("stroke", function(d, i) {
return cfg.color(i);
})
.style("fill", "none")
.style("filter", "url(#glow)");

//Append the circles
blobWrapper
.selectAll(".radarCircle")
.data(function(d, i) {
return d;
})
.enter()
.append("circle")
.attr("class", "radarCircle")
.attr("r", cfg.dotRadius)
.attr("cx", function(d, i) {
return rScale(d.value) * Math.cos(angleSlice * i - Math.PI / 2);
})
.attr("cy", function(d, i) {
return rScale(d.value) * Math.sin(angleSlice * i - Math.PI / 2);
})
.style("fill", function(d) {
return "#737373";
})
.style("fill-opacity", 0.8);

/////////////////////////////////////////////////////////
//////// Append invisible circles for tooltip ///////////
/////////////////////////////////////////////////////////

//Wrapper for the invisible circles on top
var blobCircleWrapper = g
.selectAll(".radarCircleWrapper")
.data(data)
.enter()
.append("g")
.attr("class", "radarCircleWrapper");

//Append a set of invisible circles on top for the mouseover pop-up
blobCircleWrapper
.selectAll(".radarInvisibleCircle")
.data(function(d, i) {
return d;
})
.enter()
.append("circle")
.attr("class", "radarInvisibleCircle")
.attr("r", cfg.dotRadius * 1.5)
.attr("cx", function(d, i) {
return rScale(d.value) * Math.cos(angleSlice * i - Math.PI / 2);
})
.attr("cy", function(d, i) {
return rScale(d.value) * Math.sin(angleSlice * i - Math.PI / 2);
})
.style("fill", "none")
.style("pointer-events", "all")
.on("mouseover", function(d, i) {
var newX = parseFloat(d3.select(this).attr("cx")) - 10;
var newY = parseFloat(d3.select(this).attr("cy")) - 10;

tooltip
.attr("x", newX)
.attr("y", newY)
.text(Format(d.value))
.transition()
.duration(200)
.style("opacity", 1);
})
.on("mouseout", function() {
tooltip
.transition()
.duration(200)
.style("opacity", 0);
});

//Set up the small tooltip for when you hover over a circle
var tooltip = g
.append("text")
.attr("class", "tooltip")
.style("opacity", 0);
return svg.node();
} //RadarChart
Insert cell
Part C.csv
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
data = [
[
//E1
{ axis: "Valence", value: 76.35, type: "E1" },
{ axis: "Arousal", value: 79.83, type: "E1" },
{ axis: "Pleasure", value: 64.00, type: "E1" },
{ axis: "Familiarity", value: 21.15, type: "E1" }
],
[
//E4
{ axis: "Valence", value: 69.52, type: "E4" },
{ axis: "Arousal", value: 66.68, type: "E4" },
{ axis: "Pleasure", value: 62.57, type: "E4" },
{ axis: "Familiarity", value: 17.98, type: "E4" }
],
[
//E2
{ axis: "Valence", value: 76.02 },
{ axis: "Arousal", value: 60.27 },
{ axis: "Pleasure", value: 61.42 },
{ axis: "Familiarity", value: 13.35 }
],
[
//E3
{ axis: "Valence", value: 67.40 },
{ axis: "Arousal", value: 52.05 },
{ axis: "Pleasure", value: 57.97 },
{ axis: "Familiarity", value: 18.62 }
],
[
//E7
{ axis: "Valence", value: -41.05 },
{ axis: "Arousal", value: -46.97 },
{ axis: "Pleasure", value: -6.13 },
{ axis: "Familiarity", value: -23.83 }
],
[
//E14
{ axis: "Valence", value: -36.20 },
{ axis: "Arousal", value: -38.32 },
{ axis: "Pleasure", value: -12.57 },
{ axis: "Familiarity", value: -39.02 }
],
[
//E5
{ axis: "Valence", value: -32.08 },
{ axis: "Arousal", value: -40.05 },
{ axis: "Pleasure", value: 25.00 },
{ axis: "Familiarity", value: 0.63 }
],
[
//E6
{ axis: "Valence", value: -24.02 },
{ axis: "Arousal", value: -28.17 },
{ axis: "Pleasure", value: 45.10 },
{ axis: "Familiarity", value: 7.42 }
],
[
//E8
{ axis: "Valence", value: -24.78 },
{ axis: "Arousal", value: -27.43 },
{ axis: "Pleasure", value: 37.25 },
{ axis: "Familiarity", value: 1.30 }
],
[
//E9
{ axis: "Valence", value: 57.93 },
{ axis: "Arousal", value: 74.00 },
{ axis: "Pleasure", value: 39.53 },
{ axis: "Familiarity", value: 2.75 }
],
[
//E10
{ axis: "Valence", value: 53.43 },
{ axis: "Arousal", value: 41.17 },
{ axis: "Pleasure", value: 31.57 },
{ axis: "Familiarity", value: -10.00 }
],
[
//E11
{ axis: "Valence", value: 59.83 },
{ axis: "Arousal", value: 61.45 },
{ axis: "Pleasure", value: 44.68 },
{ axis: "Familiarity", value: -6.23 }
],
[
//E12
{ axis: "Valence", value: 45.37 },
{ axis: "Arousal", value: 53.73 },
{ axis: "Pleasure", value: 14.57 },
{ axis: "Familiarity", value: -20.77 }
],
[
//E13
{ axis: "Valence", value: -46.87 },
{ axis: "Arousal", value: -1.07 },
{ axis: "Pleasure", value: -33.58 },
{ axis: "Familiarity", value: -51.20 }
],
[
//E15
{ axis: "Valence", value: -6.78 },
{ axis: "Arousal", value: -27.77 },
{ axis: "Pleasure", value: -5.75 },
{ axis: "Familiarity", value: -49.72 }
],
[
//E16
{ axis: "Valence", value: -8.72 },
{ axis: "Arousal", value: -40.95 },
{ axis: "Pleasure", value: 30.13 },
{ axis: "Familiarity", value: -30.38 }
]
];
Insert cell
colorScaleFull = d3.scaleOrdinal(d3.schemeCategory10)
.domain(data.map(d => d.type)
.filter((value, index, self) => self.indexOf(value) === index))
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more