Skip to content

Instantly share code, notes, and snippets.

@starcalibre
Last active February 29, 2016 08:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save starcalibre/a0a0449817b71eddc7f3 to your computer and use it in GitHub Desktop.
Save starcalibre/a0a0449817b71eddc7f3 to your computer and use it in GitHub Desktop.
Radar Plot of Fermion Properties
.idea/
*.iml

The properties of Fermions drawn as a radar plot. The radar plot is achieved by mapping the angle and value along the axis to by converting polar co-ordinates to svg (x, y) co-ordinates.

var fermions = [
{
name: 'Up Quark',
mass: 2.4,
charge: 0.666,
spin: 0.5
},
{
name: 'Down Quark',
mass: 4.8,
charge: -0.333,
spin: 0.5
},
{
name: 'e Nutrino',
mass: 2.2,
charge: 0,
spin: 0.5
},
{
name: 'Electron',
mass: 0.511,
charge: -1,
spin: 0.5
}
];
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<style>
circle, polygon {
fill: none;
stroke-width: 1px;
stroke: black;
}
.axis path,
.axis line {
fill: none;
stroke: #000000;
stroke-width: 1px;
shape-rendering: optimizeQuality;
}
.axis text {
font-family: monospace;
font-size: 12px;
}
.label {
font-family: monospace;
}
</style>
</head>
<body>
</body>
<script src="./fermions.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.14/d3.min.js"></script>
<script>
var width = 500;
var height = 500;
var axisLength = 275;
var axisOffset = (height/2 - axisLength);
var massScale = d3.scale.linear()
.domain([0, 5])
.range([0, axisLength]);
var chargeScale = d3.scale.linear()
.domain([-1.2, 0.8])
.range([0, axisLength]);
var spinScale = d3.scale.linear()
.domain([0, 0.5])
.range([0, axisLength]);
var svg = d3.select('body').append('svg')
.attr('width', width)
.attr('height', height)
.append("g")
.attr("transform", translateString(0, 50));
var colourScale = ['#66c2a5', '#fc8d62', '#8da0cb', '#e78ac3'];
// create polygon for each datapoint
var delta = (2 * Math.PI) / 3;
fermions.forEach(function(d) {
var polygon = [];
var mass = polarToCartestian(massScale(d.mass), -Math.PI / 2);
polygon.push([width/2 + mass[0], height/2 + mass[1]]);
var charge = polarToCartestian(chargeScale(d.charge), -Math.PI / 2 + delta);
polygon.push([width/2 + charge[0], height/2 + charge[1]]);
var spin = polarToCartestian(spinScale(d.spin), -Math.PI / 2 + 2 * delta);
polygon.push([width/2 + spin[0], height/2 + spin[1]]);
d.polygon = polygon.map(function(d) {
return d.join(",");
}).join(" ")
});
// attach the polygons to the svg with a data-bind
svg.selectAll('polygon')
.data(fermions)
.enter()
.append('polygon')
.attr("id", function(d, i) {
return "polygon-" + i;
})
.attr("points", function(d) {
return d.polygon;
})
.style("fill", function(d, i) {
return colourScale[i];
})
.style("opacity", 0.4)
.on("mouseover", function(d, i) {
onMouseOver(i);
})
.on("mouseout", function() {
onMouseOut();
});
// create and attach the axes
var massAxis = d3.svg.axis()
.scale(massScale)
.orient("left")
.ticks(3)
.tickFormat(function(d) { return d.toPrecision(2) });
svg.append("g")
.attr("class", "mass axis")
.attr("transform", translateString(width/2, axisOffset + axisLength) +
rotateString(Math.PI))
.call(massAxis)
.selectAll("text")
.attr("transform", translateString(-40, 0) + rotateString(Math.PI));
var chargeAxis = d3.svg.axis()
.scale(chargeScale)
.orient("left")
.ticks(3);
svg.append("g")
.attr("class", "axis")
.attr("transform", translateString(width/2, axisOffset + axisLength) +
rotateString(-Math.PI / 3))
.call(chargeAxis);
var spinAxis = d3.svg.axis()
.scale(spinScale)
.orient("left")
.ticks(3);
svg.append("g")
.attr("class", "axis")
.attr("transform", translateString(width/2, axisOffset + axisLength) +
rotateString(Math.PI / 3))
.call(spinAxis);
// add axis labels
svg.append("text")
.attr("class", "label")
.attr("x", 279)
.attr("y", 0)
.text("Mass (MeV)");
svg.append("text")
.attr("class", "label")
.attr("x", 398)
.attr("y", 413)
.text("Charge");
svg.append("text")
.attr("class", "label")
.attr("x", 30)
.attr("y", 413)
.text("Spin");
// add plot legend
var legendX = 370;
var legendY = 50;
var legendDy = 30;
var names = fermions.map(function(d) { return d.name });
names.forEach(function(d, i) {
svg.append("rect")
.attr("id", "legend-rect-" + i)
.attr("class", "legend-rect")
.attr("x", 370)
.attr("y", legendY + legendDy * i)
.attr("width", 25)
.attr("height", 25)
.attr("fill", colourScale[i])
.style("opacity", 0.4)
.on("mouseover", function() {
onMouseOver(i);
})
.on("mouseout", function() {
onMouseOut();
});
svg.append("text")
.attr("id", "legend-text-" + i)
.text(d)
.attr("class", "label legend-text")
.attr("x", 402)
.attr("y", legendY + legendDy * i + 17)
.on("mouseover", function() {
onMouseOver(i);
})
.on("mouseout", function() {
onMouseOut();
});
});
function onMouseOver(i) {
d3.select("#legend-rect-" + i)
.style("opacity", 1);
d3.select("#legend-text-" + i)
.style("font-weight", "bold");
d3.select("#polygon-" + i)
.style("opacity", 1);
}
function onMouseOut() {
d3.selectAll(".legend-rect")
.style("opacity", 0.4);
d3.selectAll(".legend-text")
.style("font-weight", "normal");
d3.selectAll("polygon")
.style("opacity", 0.4)
}
function rotateString(r, cx, cy) {
if(!cx || !cy) {
cx = 0;
cy = 0;
}
var deg = r * (180 / Math.PI);
var out = ["rotate("];
out.push(deg);
out.push(" ");
out.push(cx);
out.push(" ");
out.push(cy);
out.push(")");
return out.join("");
}
function translateString(x, y) {
var out = ["translate("];
out.push(x);
out.push(" ");
out.push(y);
out.push(")");
return out.join("")
}
function polarToCartestian(r, theta) {
var x = r * Math.cos(theta);
var y = r * Math.sin(theta);
return [x, y];
}
</script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment