Advertisement
NTahmid

Extrema_v4_bar

Feb 21st, 2024 (edited)
511
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 8.48 KB | None | 0 0
  1. Here is the modified code:
  2.  
  3. ```html
  4. <!DOCTYPE html>
  5. <meta charset="utf-8">
  6.  
  7. <style>
  8. .axis line{
  9.   visibility:hidden;
  10. }
  11.  
  12. .axis .domain {
  13.   display: none;
  14. }
  15.  
  16. .axis {
  17.   font: 13px sans-serif;
  18. }
  19.  
  20. .yUnits {
  21.   font: 14px sans-serif;
  22. }
  23.  
  24. .caption {
  25.   font: 12px sans-serif;
  26. }
  27.  
  28. .chartDisplayTitle{
  29.   fill:#354B5F;
  30.   font-weight: bold;
  31.   font: 20px sans-serif;
  32. }
  33.  
  34. .annotation-line {
  35.   stroke: #c86984;
  36.   stroke-width: 1.5px;
  37. }
  38.  
  39. .annotation-circle {
  40.   fill: transparent;
  41.   stroke: #c86984;
  42.   stroke-width: 1.5px;
  43. }
  44.  
  45. .annotation-text {
  46.   fill: #c86984;
  47.   font-size: 13px;
  48. }
  49. </style>
  50.  
  51. <svg class="chart" width="960" height="590" aria-labelledby="graph-title" aria-describedby="graph-desc">
  52.   <title>GDP Growth Remains Broad Based</title>
  53.   <desc id="graph-desc">GDP Growth Remains Broad Based, with values for 2017 quarters 1-3.</desc>
  54.   <text transform="translate(10, 20)" class="chartDisplayTitle">Chart1</text>
  55.   <text id="graph-title" transform="translate(10, 45)" class="chartDisplayTitle">GDP Growth Remains Broad Based</text>
  56.   <text transform="translate(10, 70)" class="yUnits">Percentage points*</text>
  57.   <text transform="translate(10, 570)" class="caption">*Contribution to total gross domestic product (GDP) growth; seasonally adjusted annualized rate.</text>
  58.   <text transform="translate(10, 585)" class="caption">SOURCE: Bureau of Economic Analysis.</text>
  59. </svg>
  60.  
  61. <script src="https://d3js.org/d3.v4.min.js"></script>
  62.  
  63. <script>
  64. const regression = d3.regressionLinear()
  65.   .x(d => d.x)
  66.   .y(d => d.y)
  67.   .domain([0, 100]);
  68. </script>
  69.  
  70. <script>
  71. var econ2 = [
  72.   {
  73.     "Category": "GDP",
  74.     "2017 Q1": 1.2,
  75.     "2017 Q2": 3.1,
  76.     "2017 Q3 First Estimate": 3.0
  77.   },
  78.   {
  79.     "Category": "Consumption",
  80.     "2017 Q1": 1.3,
  81.     "2017 Q2": 2.2,
  82.     "2017 Q3 First Estimate": 1.6
  83.   },
  84.   {
  85.     "Category": "Nonresidential investment",
  86.     "2017 Q1": 0.9,
  87.     "2017 Q2": 0.8,
  88.     "2017 Q3 First Estimate": 0.5
  89.   },
  90.   {
  91.     "Category": "Residential investment",
  92.     "2017 Q1": 0.4,
  93.     "2017 Q2": -0.3,
  94.     "2017 Q3 First Estimate": -0.2
  95.   },
  96.   {
  97.     "Category": "Inventories",
  98.     "2017 Q1": -1.5,
  99.     "2017 Q2": 0.1,
  100.     "2017 Q3 First Estimate": 0.7
  101.   },
  102.   {
  103.     "Category": "Net exports",
  104.     "2017 Q1": 0.2,
  105.     "2017 Q2": 0.2,
  106.     "2017 Q3 First Estimate": 0.4
  107.   },
  108.   {
  109.     "Category": "Government",
  110.     "2017 Q1": -0.1,
  111.     "2017 Q2": 0.0,
  112.     "2017 Q3 First Estimate": 0.0
  113.   }
  114. ]
  115.  
  116. //chart setup
  117. var svg = d3.select("svg"),
  118.     margin = {top: 80, right: 10, bottom: 80, left: 25},
  119.     width = svg.attr("width") - margin.left - margin.right,
  120.     height = svg.attr("height") - margin.top - margin.bottom,
  121.     g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
  122.  
  123. //y position calculation function
  124. var y = d3.scaleLinear()
  125.       .domain([-2, 4])
  126.       .range([height, 0]);
  127.  
  128. var x0 = d3.scaleBand()  // domain defined below
  129.       .rangeRound([0, width])
  130.       .paddingInner(0.1)
  131.       .paddingOuter(0.1);
  132.  
  133. var x1 = d3.scaleBand()  // domain and range defined below
  134.     .paddingOuter(0.25)
  135.     .paddingInner(0.15);
  136.  
  137. //blue, tan, red colors
  138. var z = d3.scaleOrdinal()
  139.         .range(["#BC151E", "#D3B178", "#354B5F"]);
  140.  
  141. //reference to the y axis
  142. //axisLeft put labels on left side
  143. //ticks(n) refers to # of increment marks on the axis
  144. const yAxis = d3.axisLeft(y).ticks(7);
  145.  
  146. //examine first object, retrieve the keys, and discard the first key
  147. //return resulting array of keys
  148. // [ "2017 Q1", "2017 Q2", "2017 Q3 First Estimate"]
  149. var subCategories = Object.keys(econ2[0]).slice(1);
  150.  
  151. //use new array from just the Category values for the bottom x-axis
  152. x0.domain(econ2.map( d =>  d.Category ));
  153.  
  154. //array of quarterly value names, fitted in the available bottom categories (x0.bandwidth())
  155. x1.domain(subCategories).rangeRound([0, x0.bandwidth()])
  156.  
  157. // Add bar chart
  158. var selection = g.selectAll("g")
  159.   .data(econ2)
  160.   .enter().append("g")
  161.     .attr("transform", d => "translate(" + x0(d.Category) + ",0)" )
  162.   selection.selectAll("rect")
  163.   //Use map function with the subCategories array and the Econ2 array
  164.    .data(function(d) { return subCategories.map(function(key) { return {key: key, value: d[key]}; }); })
  165.     .enter().append("rect")
  166.     .attr("x", d => x1(d.key) )
  167.   //If the value is negative, put the top left corner of the rect bar on the zero line
  168.     .attr("y", d => (d.value<0 ? y(0) : y(d.value)) )
  169.    .attr("width", x1.bandwidth())
  170.    .attr("height", d => Math.abs(y(d.value) - y(0)) )
  171.     .attr("fill", d => z(d.key) )
  172.   //can not nest the text element inside the rect element !
  173.   selection.selectAll("text")
  174.      .data(function(d) { return subCategories.map(function(key) { return {key: key, value: d[key]}; }); })
  175.       .enter().append("text")
  176.       .attr("x", d => x1(d.key) )
  177.   //offset the position of the y value (positive / negative) to have the text over/under the rect bar
  178.       .attr("y", d => d.value<=0 ? y(0) - (y(4) - (Math.abs(y(d.value) - y(0)) + 20)) : y(d.value) - 10)
  179.      .style('fill', d => z(d.key))
  180.       .style('font-size', '1.25em')
  181.   //make sure one just decimal place is displayed
  182.       .text(d => Number.parseFloat(d.value).toFixed(1))
  183.  
  184. //add the x-axis
  185. g.append("g")
  186.   .attr("class", "axis")
  187.   .attr("transform", "translate(0," + height + ")")
  188.   .call(d3.axisBottom(x0))
  189.   .selectAll(".tick text")
  190.   //use wrap function to wrap long lines in labels
  191.   .call(wrap, x0.bandwidth());
  192.  
  193. //add the y-axis - notice it does not have css class 'axis'
  194. g.append('g')
  195. .call(yAxis)
  196.  
  197. //idenitfy zero line on the y axis.
  198. g.append("line")
  199.   .attr("y1", y(0))
  200.   .attr("y2", y(0))
  201.   .attr("x1", 0)
  202.   .attr("x2", width)
  203.   .attr("stroke", "black");
  204.  
  205. var legend = g.append("g")
  206.   .attr("font-family", "sans-serif")
  207.   .attr("font-size", 13)
  208.   .attr("text-anchor", "end")
  209. .selectAll("g")
  210. .data(subCategories)
  211. .enter().append("g")
  212.   .attr("transform", function(d, i) { return "translate(0," + i * 24 + ")"; });
  213. legend.append("rect")
  214.   .attr("x", width - 142)
  215.   .attr("width", 8)
  216.   .attr("height", 8)
  217.   .attr("fill", z);
  218. legend.append("text")
  219.       .attr("x", d => d.length > 7 ? (width + 5) : (width - 80))
  220.       .attr("y", 5.5)
  221.       .attr("dy", "0.22em")
  222.       .text(d => (d));
  223.  
  224. // Annotations
  225. var annotations = [
  226.   { category: "GDP", quarter: "2017 Q1", value: 1.2, text: "Min: 1.2" },
  227.   { category: "GDP", quarter: "2017 Q2", value: 3.1, text: "Max: 3.1" },
  228.   { category: "Inventories", quarter: "2017 Q1", value: -1.5, text: "Min: -1.5" },
  229.   { category: "Inventories", quarter: "2017 Q3 First Estimate", value: 0.7, text: "Max: 0.7" }
  230. ];
  231.  
  232. annotations.forEach(function(a) {
  233.   g.append("line")
  234.     .attr("class", "annotation-line")
  235.     .attr("x1", x0(a.category) + x1(a.quarter) + x1.bandwidth() / 2)
  236.     .attr("y1", y(a.value))
  237.     .attr("x2", x0(a.category) + x1(a.quarter) + x1.bandwidth() / 2)
  238.     .attr("y2", a.value < 0 ? y(0) - 30 : y(0) + 30);
  239.  
  240.  g.append("circle")
  241.    .attr("class", "annotation-circle")
  242.    .attr("cx", x0(a.category) + x1(a.quarter) + x1.bandwidth() / 2)
  243.    .attr("cy", y(a.value))
  244.    .attr("r", 15);
  245.  
  246.  g.append("text")
  247.    .attr("class", "annotation-text")
  248.    .attr("x", x0(a.category) + x1(a.quarter) + x1.bandwidth() / 2)
  249.    .attr("y", a.value < 0 ? y(0) - 40 : y(0) + 40)
  250.    .text(a.text);
  251. });
  252.  
  253. //https://bl.ocks.org/mbostock/7555321 - wrap long labels
  254. function wrap(text, width) {
  255.  text.each(function() {
  256.    var text = d3.select(this),
  257.        words = text.text().split(/\s+/).reverse(),
  258.        word,
  259.        line = [],
  260.        lineNumber = 0,
  261.        lineHeight = 1.1, // ems
  262.        y = text.attr("y"),
  263.        dy = parseFloat(text.attr("dy")),
  264.        tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em");
  265.    while (word = words.pop()) {
  266.      line.push(word);
  267.      tspan.text(line.join(" "));
  268.      if (tspan.node().getComputedTextLength() > width) {
  269.         line.pop();
  270.         tspan.text(line.join(" "));
  271.         line = [word];
  272.         tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
  273.       }
  274.     }
  275.   });
  276. }
  277. </script>
  278. ```
  279.  
  280. 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