xxxxxxxxxx
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
h1, h2 {
font-family: "Liberation Mono", "Lato", "Open Sans", "sans-serif";
color: #fff;
margin: 0px;
padding: 3px;
}
body {background: #1a1a1a; -webkit-text-size-adjust: none;}
.counties {
fill: none;
stroke: rgb(44, 44, 44);
}
.counties path:hover {
fill:red;
transition-delay: 0ms;}
.states {
fill: none;
stroke: #1a1a1a;
stroke-linejoin: round;
stroke-width: 1.5;
}
.axis path {stroke: none; fill: none;}
.axis line {stroke: #fff; fill: none;}
.tick text {
stroke: #fff;
fill: #fff;
font-family: "Liberation Mono", "Lato", "Open Sans", "sans-serif";
font-size: 1.7em;
text-shadow: none;
}
.d3-tip {
font-family: "Liberation Mono", "monospace";
position: absolute;
line-height: 1.2;
padding: 12px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 3px;
}
</style>
<div class="text-things">
<h1>US Weekly Oil and Gas Rig Count</h1>
<h2>June 25, 2021</h2>
</div>
<svg height="700" width="1000"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v0.3.min.js"></script>
<script src="https://d3js.org/topojson.v2.min.js"></script>
<script src="d3-tip.js"></script>
<script>
// Template: https://bl.ocks.org/mbostock/4060606
// Legend 1: https://www.visualcinnamon.com/2016/05/smooth-color-legend-d3-svg-gradient.html
// Legend 2: https://bl.ocks.org/nbremer/5cd07f2cb4ad202a9facfbd5d2bc842e
// The drawing board and its dimensions
var svg = d3.select("svg"),
margin = { top: 0, bottom: 0, right: 0, left: 0},
width = +svg.attr("width"),
height = +svg.attr("height");
//Append a defs (for definition) element to your SVG
var defs = svg.append("defs"),
legend = svg.append("g")
.attr("class", "legendWrapper")
.attr("transform", "translate(" + width / 3 + ",0)")
//Append a linearGradient element to the defs and give it a unique id
var linearGradient = defs.append("linearGradient")
.attr("id", "linear-gradient");
// Maps to hold data
var total = d3.map(),
oil = d3.map(),
gas = d3.map();
// Tool-tip
var tip = d3.tip()
.attr("class", "d3-tip")
.offset(function() {
return [0 , 0]
})
.html(function(d) {
return "Location: " + d.properties.display_name +
"<br>Rigs: " + (total.get(d.properties.location) == null ? 0 : total.get(d.properties.location)) +
"<br>Oil: \xa0" + (oil.get(d.properties.location) == null ? 0 : oil.get(d.properties.location)) +
"<br>Gas: \xa0" + (gas.get(d.properties.location) == null ? 0 : gas.get(d.properties.location));
});
svg.call(tip);
// Set a queue awaiting on function ready()
// This contains data and pre-processing instructions (i.e. adding data to the Maps)
d3.queue()
.defer(d3.json, "us.json")
.defer(d3.csv, "rig_counts.csv", function(d) {
total.set(d.location, +d.Total);
oil.set(d.location, +d.Oil);
gas.set(d.location, +d.Gas);
})
.await(ready);
// Here is where it all happens: the ready() function
function ready(error, us) {
if (error) throw error;
// Create a path generator whose projection
// is an Albers Equal Area and whose drawable
// area is defined by the width and margins
// of the SVG.
var path = d3.geoPath()
.projection(d3.geoAlbers()
.fitExtent([[margin.left, margin.top], [width - margin.right, height - margin.bottom]],
topojson.feature(us, us.objects.states))
);
var timeout;
// Color map.
// Sequential viridis whose domain is the extent (min/max) of the total rig count values.
var colScale = d3.scaleSequential(d3.interpolateViridis)
.domain(d3.extent(total.values()));
//Draw the rectangle and fill with gradient
var legendBar = legend.append("rect")
.attr("width", 350)
.attr("height", 20)
.style("fill", "url(#linear-gradient)");
//Append multiple color stops by using D3's data/enter step
/* linearGradient.selectAll("stop")
.data(topojson.feature(us, us.objects.counties).features)
.enter().append("stop")
.attr("offset", function(d,i) { return i / (69 - 1); })
.attr("stop-color", function(d) { return colScale(total.get(d.properties.location)); });
*/
linearGradient
.attr("x1", "0%")
.attr("y1", "0%")
.attr("x2", "100%")
.attr("y2", "0%");
linearGradient.selectAll("stop")
.data([
{offset: "0%", color: "#440154FF"},
{offset: "12.5%", color: "#472D7BFF"},
{offset: "25%", color: "#3B528BFF"},
{offset: "37.5%", color: "#2C728EFF"},
{offset: "50%", color: "#21908CFF"},
{offset: "62.5%", color: "#27AD81FF"},
{offset: "75%", color: "#5DC863FF"},
{offset: "87.5%", color: "#AADC32FF"},
{offset: "100%", color: "#FDE725FF"}
])
.enter().append("stop")
.attr("offset", function(d) { return d.offset; })
.attr("stop-color", function(d) { return d.color; });
//Set scale for x-axis
var xScale = d3.scaleLinear()
.range([0, 350])
.domain(d3.extent(total.values()));
//Define x-axis
var xAxis = d3.axisBottom()
.ticks(5) //Set rough # of ticks
//.tickFormat(formatPercent)
.scale(xScale);
//Set up X axis
legend.append("g")
.attr("class", "axis") //Assign "axis" class
.attr("transform", "translate(0,20)")
.call(xAxis);
svg.append("g")
.attr("class", "counties")
.selectAll("path")
.data(topojson.feature(us, us.objects.counties).features)
.enter().append("path")
.attr("fill", function(d) {
if (total.get(d.properties.location) == null) {
return "#4d4d4d";
} else {
return colScale(total.get(d.properties.location));
}})
.attr("d", path)
// tooltip mouseover behavior
.on("mouseover", function(d) {
var context = this;
var args = [].slice.call(arguments);
args.push(this);
clearTimeout(timeout);
timeout = setTimeout(function() {
tip.show.apply(context, args);
}, 100);
})
// tooltip mouseout behavior
.on("mouseout", function(d) {
clearTimeout(timeout);
tip.hide(d);
});
svg.append("path")
.attr("class", "states")
// .attr("d", path(topojson.mesh(us, us.objects.states, function(a, b) { return a !== b; })));
.datum(topojson.mesh(us, us.objects.states, function(a, b) { return a !== b; }))
.attr("d", path);
}
</script>
https://d3js.org/d3.v4.min.js
https://d3js.org/d3-scale-chromatic.v0.3.min.js
https://d3js.org/topojson.v2.min.js