Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Here is the modified code:
- ```html
- <!DOCTYPE html>
- <meta charset="utf-8">
- <style>
- .axis line{
- visibility:hidden;
- }
- .axis .domain {
- display: none;
- }
- .axis {
- font: 13px sans-serif;
- }
- .yUnits {
- font: 14px sans-serif;
- }
- .caption {
- font: 12px sans-serif;
- }
- .chartDisplayTitle{
- fill:#354B5F;
- font-weight: bold;
- font: 20px sans-serif;
- }
- .annotation-line {
- stroke: #c86984;
- stroke-width: 1.5px;
- }
- .annotation-circle {
- fill: transparent;
- stroke: #c86984;
- stroke-width: 1.5px;
- }
- .annotation-text {
- fill: #c86984;
- font-size: 13px;
- }
- </style>
- <svg class="chart" width="960" height="590" aria-labelledby="graph-title" aria-describedby="graph-desc">
- <title>GDP Growth Remains Broad Based</title>
- <desc id="graph-desc">GDP Growth Remains Broad Based, with values for 2017 quarters 1-3.</desc>
- <text transform="translate(10, 20)" class="chartDisplayTitle">Chart1</text>
- <text id="graph-title" transform="translate(10, 45)" class="chartDisplayTitle">GDP Growth Remains Broad Based</text>
- <text transform="translate(10, 70)" class="yUnits">Percentage points*</text>
- <text transform="translate(10, 570)" class="caption">*Contribution to total gross domestic product (GDP) growth; seasonally adjusted annualized rate.</text>
- <text transform="translate(10, 585)" class="caption">SOURCE: Bureau of Economic Analysis.</text>
- </svg>
- <script src="https://d3js.org/d3.v4.min.js"></script>
- <script>
- const regression = d3.regressionLinear()
- .x(d => d.x)
- .y(d => d.y)
- .domain([0, 100]);
- </script>
- <script>
- var econ2 = [
- {
- "Category": "GDP",
- "2017 Q1": 1.2,
- "2017 Q2": 3.1,
- "2017 Q3 First Estimate": 3.0
- },
- {
- "Category": "Consumption",
- "2017 Q1": 1.3,
- "2017 Q2": 2.2,
- "2017 Q3 First Estimate": 1.6
- },
- {
- "Category": "Nonresidential investment",
- "2017 Q1": 0.9,
- "2017 Q2": 0.8,
- "2017 Q3 First Estimate": 0.5
- },
- {
- "Category": "Residential investment",
- "2017 Q1": 0.4,
- "2017 Q2": -0.3,
- "2017 Q3 First Estimate": -0.2
- },
- {
- "Category": "Inventories",
- "2017 Q1": -1.5,
- "2017 Q2": 0.1,
- "2017 Q3 First Estimate": 0.7
- },
- {
- "Category": "Net exports",
- "2017 Q1": 0.2,
- "2017 Q2": 0.2,
- "2017 Q3 First Estimate": 0.4
- },
- {
- "Category": "Government",
- "2017 Q1": -0.1,
- "2017 Q2": 0.0,
- "2017 Q3 First Estimate": 0.0
- }
- ]
- //chart setup
- var svg = d3.select("svg"),
- margin = {top: 80, right: 10, bottom: 80, left: 25},
- width = svg.attr("width") - margin.left - margin.right,
- height = svg.attr("height") - margin.top - margin.bottom,
- g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
- //y position calculation function
- var y = d3.scaleLinear()
- .domain([-2, 4])
- .range([height, 0]);
- var x0 = d3.scaleBand() // domain defined below
- .rangeRound([0, width])
- .paddingInner(0.1)
- .paddingOuter(0.1);
- var x1 = d3.scaleBand() // domain and range defined below
- .paddingOuter(0.25)
- .paddingInner(0.15);
- //blue, tan, red colors
- var z = d3.scaleOrdinal()
- .range(["#BC151E", "#D3B178", "#354B5F"]);
- //reference to the y axis
- //axisLeft put labels on left side
- //ticks(n) refers to # of increment marks on the axis
- const yAxis = d3.axisLeft(y).ticks(7);
- //examine first object, retrieve the keys, and discard the first key
- //return resulting array of keys
- // [ "2017 Q1", "2017 Q2", "2017 Q3 First Estimate"]
- var subCategories = Object.keys(econ2[0]).slice(1);
- //use new array from just the Category values for the bottom x-axis
- x0.domain(econ2.map( d => d.Category ));
- //array of quarterly value names, fitted in the available bottom categories (x0.bandwidth())
- x1.domain(subCategories).rangeRound([0, x0.bandwidth()])
- // Add bar chart
- var selection = g.selectAll("g")
- .data(econ2)
- .enter().append("g")
- .attr("transform", d => "translate(" + x0(d.Category) + ",0)" )
- selection.selectAll("rect")
- //Use map function with the subCategories array and the Econ2 array
- .data(function(d) { return subCategories.map(function(key) { return {key: key, value: d[key]}; }); })
- .enter().append("rect")
- .attr("x", d => x1(d.key) )
- //If the value is negative, put the top left corner of the rect bar on the zero line
- .attr("y", d => (d.value<0 ? y(0) : y(d.value)) )
- .attr("width", x1.bandwidth())
- .attr("height", d => Math.abs(y(d.value) - y(0)) )
- .attr("fill", d => z(d.key) )
- //can not nest the text element inside the rect element !
- selection.selectAll("text")
- .data(function(d) { return subCategories.map(function(key) { return {key: key, value: d[key]}; }); })
- .enter().append("text")
- .attr("x", d => x1(d.key) )
- //offset the position of the y value (positive / negative) to have the text over/under the rect bar
- .attr("y", d => d.value<=0 ? y(0) - (y(4) - (Math.abs(y(d.value) - y(0)) + 20)) : y(d.value) - 10)
- .style('fill', d => z(d.key))
- .style('font-size', '1.25em')
- //make sure one just decimal place is displayed
- .text(d => Number.parseFloat(d.value).toFixed(1))
- //add the x-axis
- g.append("g")
- .attr("class", "axis")
- .attr("transform", "translate(0," + height + ")")
- .call(d3.axisBottom(x0))
- .selectAll(".tick text")
- //use wrap function to wrap long lines in labels
- .call(wrap, x0.bandwidth());
- //add the y-axis - notice it does not have css class 'axis'
- g.append('g')
- .call(yAxis)
- //idenitfy zero line on the y axis.
- g.append("line")
- .attr("y1", y(0))
- .attr("y2", y(0))
- .attr("x1", 0)
- .attr("x2", width)
- .attr("stroke", "black");
- var legend = g.append("g")
- .attr("font-family", "sans-serif")
- .attr("font-size", 13)
- .attr("text-anchor", "end")
- .selectAll("g")
- .data(subCategories)
- .enter().append("g")
- .attr("transform", function(d, i) { return "translate(0," + i * 24 + ")"; });
- legend.append("rect")
- .attr("x", width - 142)
- .attr("width", 8)
- .attr("height", 8)
- .attr("fill", z);
- legend.append("text")
- .attr("x", d => d.length > 7 ? (width + 5) : (width - 80))
- .attr("y", 5.5)
- .attr("dy", "0.22em")
- .text(d => (d));
- // Annotations
- var annotations = [
- { category: "GDP", quarter: "2017 Q1", value: 1.2, text: "Min: 1.2" },
- { category: "GDP", quarter: "2017 Q2", value: 3.1, text: "Max: 3.1" },
- { category: "Inventories", quarter: "2017 Q1", value: -1.5, text: "Min: -1.5" },
- { category: "Inventories", quarter: "2017 Q3 First Estimate", value: 0.7, text: "Max: 0.7" }
- ];
- annotations.forEach(function(a) {
- g.append("line")
- .attr("class", "annotation-line")
- .attr("x1", x0(a.category) + x1(a.quarter) + x1.bandwidth() / 2)
- .attr("y1", y(a.value))
- .attr("x2", x0(a.category) + x1(a.quarter) + x1.bandwidth() / 2)
- .attr("y2", a.value < 0 ? y(0) - 30 : y(0) + 30);
- g.append("circle")
- .attr("class", "annotation-circle")
- .attr("cx", x0(a.category) + x1(a.quarter) + x1.bandwidth() / 2)
- .attr("cy", y(a.value))
- .attr("r", 15);
- g.append("text")
- .attr("class", "annotation-text")
- .attr("x", x0(a.category) + x1(a.quarter) + x1.bandwidth() / 2)
- .attr("y", a.value < 0 ? y(0) - 40 : y(0) + 40)
- .text(a.text);
- });
- //https://bl.ocks.org/mbostock/7555321 - wrap long labels
- function wrap(text, width) {
- text.each(function() {
- var text = d3.select(this),
- words = text.text().split(/\s+/).reverse(),
- word,
- line = [],
- lineNumber = 0,
- lineHeight = 1.1, // ems
- y = text.attr("y"),
- dy = parseFloat(text.attr("dy")),
- tspan = text.text(null).append("tspan").attr("x", 0).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", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
- }
- }
- });
- }
- </script>
- ```
- This code adds annotations to the chart to highlight the extrema in the 'GDP' and 'Inventories' categories. The annotations consist of lines, circles, and text elements that are styled with a specific color (#c86984). The lines point from the data points to the text annotations, the circles highlight the data points, and the text annotations provide information about the extrema.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement