A wind rose is a graphic tool used by meteorologists to give a succinct view of how wind speed and direction are typically distributed at a particular location (https://en.wikipedia.org/wiki/Wind_rose). The chart is built with inspiration and code from two examples created by Mike Bostock (https://bl.ocks.org/mbostock/6fead6d1378d6df5ae77bb6a719afcb2. Tags: windrose, wind rose, rose plot
Last active
October 10, 2023 03:34
-
-
Save ssmaroju/96af159c1872c2928a972c441bccaf50 to your computer and use it in GitHub Desktop.
Wind Rose Plot
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This code is from Mike Bostock's Radial stacked Charts | |
//https://bl.ocks.org/mbostock/3048740 | |
//https://bl.ocks.org/mbostock/6fead6d1378d6df5ae77bb6a719afcb2 | |
(function(global, factory) { | |
typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("d3-scale")) : | |
typeof define === "function" && define.amd ? define(["exports", "d3-scale"], factory) : | |
(factory(global.d3 = global.d3 || {}, global.d3)); | |
}(this, function(exports, d3Scale) { | |
'use strict'; | |
function square(x) { | |
return x * x; | |
} | |
function radial() { | |
var linear = d3Scale.scaleLinear(); | |
function scale(x) { | |
return Math.sqrt(linear(x)); | |
} | |
scale.domain = function(_) { | |
return arguments.length ? (linear.domain(_), scale) : linear.domain(); | |
}; | |
scale.nice = function(count) { | |
return (linear.nice(count), scale); | |
}; | |
scale.range = function(_) { | |
return arguments.length ? (linear.range(_.map(square)), scale) : linear.range().map(Math.sqrt); | |
}; | |
scale.ticks = linear.ticks; | |
scale.tickFormat = linear.tickFormat; | |
return scale; | |
} | |
exports.scaleRadial = radial; | |
Object.defineProperty(exports, '__esModule', {value: true}); | |
})); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
angle | 0-1 | 1-2 | 2-3 | 3-4 | 4-4 | 4-5 | 5-6 | 6+ | |
---|---|---|---|---|---|---|---|---|---|
N | 0.5 | 1.6 | 0.9 | 0.9 | 0.4 | 0.3 | 0.2 | 0.1 | |
NNE | 0.6 | 1.8 | 1.3 | 0.8 | 0.5 | 0.3 | 0.1 | 0.1 | |
NE | 0.5 | 1.5 | 1.6 | 1.2 | 1.2 | 0.6 | 0.1 | 0.1 | |
ENE | 0.4 | 1.6 | 0.9 | 1 | 0.5 | 0.2 | 0.1 | 0.1 | |
E | 0.4 | 1.6 | 1 | 0.8 | 0.4 | 0.1 | 0.1 | 0.1 | |
ESE | 0.3 | 1.2 | 0.6 | 0.4 | 0.2 | 0.1 | 0.1 | 0.05 | |
SE | 0.4 | 1.5 | 0.6 | 0.5 | 0.4 | 0.05 | 0.05 | 0.05 | |
SSE | 0.4 | 1.7 | 0.9 | 0.5 | 0.4 | 0.1 | 0.05 | 0.05 | |
S | 0.6 | 2.2 | 1.4 | 0.8 | 0.7 | 0.1 | 0.1 | 0.05 | |
SSW | 0.4 | 2 | 1.7 | 0.9 | 0.6 | 0.2 | 0.05 | 0.1 | |
SW | 0.5 | 2.3 | 1.9 | 1.3 | 0.7 | 0.3 | 0.2 | 0.1 | |
WSW | 0.6 | 2.4 | 2.2 | 1.1 | 0.8 | 0.4 | 0.2 | 0.1 | |
W | 0.6 | 2.3 | 1.8 | 1.2 | 0.9 | 0.9 | 0.4 | 0.9 | |
WNW | 0.5 | 2.6 | 1.7 | 1.2 | 1 | 0.9 | 0.7 | 2.2 | |
NW | 0.4 | 2.3 | 1.8 | 1.3 | 1 | 0.9 | 0.7 | 1.5 | |
NNW | 0.1 | 0.8 | 0.8 | 1 | 0.7 | 0.3 | 0.4 | 0.2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<svg width="960" height="960" font-family="sans-serif" font-size="10"></svg> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<script src="d3-scale-radial.js"></script> | |
<style> | |
.axis { | |
stroke: gray | |
} | |
</style> | |
<script> | |
var svg = d3.select("svg"), | |
width = +svg.attr("width"), | |
height = +svg.attr("height"), | |
margin = {top: 40, right: 80, bottom: 40, left: 40}, | |
innerRadius = 20, | |
chartWidth = width - margin.left - margin.right, | |
chartHeight= height - margin.top - margin.bottom, | |
outerRadius = (Math.min(chartWidth, chartHeight) / 2), | |
g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"); | |
var angle = d3.scaleLinear() | |
.range([0, 2 * Math.PI]); | |
var radius = d3.scaleLinear() | |
.range([innerRadius, outerRadius]); | |
var x = d3.scaleBand() | |
.range([0, 2 * Math.PI]) | |
.align(0); | |
var y = d3.scaleLinear() //you can try scaleRadial but it scales differently | |
.range([innerRadius, outerRadius]); | |
var z = d3.scaleOrdinal() | |
.range(["#4242f4", "#42c5f4", "#42f4ce", "#42f456", "#adf442", "#f4e242", "#f4a142", "#f44242"]); | |
d3.csv("data.csv", function(d, i, columns) { | |
for (i = 1, t = 0; i < columns.length; ++i) t += d[columns[i]] = +d[columns[i]]; | |
d.total = t; | |
return d; | |
}, function(error, data) { | |
if (error) throw error; | |
x.domain(data.map(function(d) { return d.angle; })); | |
y.domain([0, d3.max(data, function(d) { return d.total; })]); | |
z.domain(data.columns.slice(1)); | |
// Extend the domain slightly to match the range of [0, 2π]. | |
angle.domain([0, d3.max(data, function(d,i) { return i + 1; })]); | |
radius.domain([0, d3.max(data, function(d) { return d.y0 + d.y; })]); | |
angleOffset = -360.0/data.length/2.0; | |
g.append("g") | |
.selectAll("g") | |
.data(d3.stack().keys(data.columns.slice(1))(data)) | |
.enter().append("g") | |
.attr("fill", function(d) { return z(d.key); }) | |
.selectAll("path") | |
.data(function(d) { return d; }) | |
.enter().append("path") | |
.attr("d", d3.arc() | |
.innerRadius(function(d) { return y(d[0]); }) | |
.outerRadius(function(d) { return y(d[1]); }) | |
.startAngle(function(d) { return x(d.data.angle); }) | |
.endAngle(function(d) { return x(d.data.angle) + x.bandwidth(); }) | |
.padAngle(0.01) | |
.padRadius(innerRadius)) | |
.attr("transform", function() {return "rotate("+ angleOffset + ")"}); | |
var label = g.append("g") | |
.selectAll("g") | |
.data(data) | |
.enter().append("g") | |
.attr("text-anchor", "middle") | |
.attr("transform", function(d) { return "rotate(" + ((x(d.angle) + x.bandwidth() / 2) * 180 / Math.PI - (90-angleOffset)) + ")translate(" + (outerRadius+30) + ",0)"; }); | |
label.append("text") | |
.attr("transform", function(d) { return (x(d.angle) + x.bandwidth() / 2 + Math.PI / 2) % (2 * Math.PI) < Math.PI ? "rotate(90)translate(0,16)" : "rotate(-90)translate(0,-9)"; }) | |
.text(function(d) { return d.angle; }) | |
.style("font-size",14); | |
g.selectAll(".axis") | |
.data(d3.range(angle.domain()[1])) | |
.enter().append("g") | |
.attr("class", "axis") | |
.attr("transform", function(d) { return "rotate(" + angle(d) * 180 / Math.PI + ")"; }) | |
.call(d3.axisLeft() | |
.scale(radius.copy().range([-innerRadius, -(outerRadius+10)]))); | |
var yAxis = g.append("g") | |
.attr("text-anchor", "middle"); | |
var yTick = yAxis | |
.selectAll("g") | |
.data(y.ticks(5).slice(1)) | |
.enter().append("g"); | |
yTick.append("circle") | |
.attr("fill", "none") | |
.attr("stroke", "gray") | |
.attr("stroke-dasharray", "4,4") | |
.attr("r", y); | |
yTick.append("text") | |
.attr("y", function(d) { return -y(d); }) | |
.attr("dy", "-0.35em") | |
.attr("x", function() { return -10; }) | |
.text(y.tickFormat(5, "s")) | |
.style("font-size",14); | |
var legend = g.append("g") | |
.selectAll("g") | |
.data(data.columns.slice(1).reverse()) | |
.enter().append("g") | |
// .attr("transform", function(d, i) { return "translate(-40," + (i - (data.columns.length - 1) / 2) * 20 + ")"; }); | |
.attr("transform", function(d, i) { return "translate(" + (outerRadius+0) + "," + (-outerRadius + 40 +(i - (data.columns.length - 1) / 2) * 20) + ")"; }); | |
legend.append("rect") | |
.attr("width", 18) | |
.attr("height", 18) | |
.attr("fill", z); | |
legend.append("text") | |
.attr("x", 24) | |
.attr("y", 9) | |
.attr("dy", "0.35em") | |
.text(function(d) { return d; }) | |
.style("font-size",12); | |
}); | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
All is well, but does not work with version 5 D3.
if you include: d3.v5.min.js