Advertisement
Guest User

Untitled

a guest
Apr 3rd, 2024
74
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.67 KB | None | 0 0
  1. <!doctype html>
  2. <html>
  3.  
  4. <head>
  5. <style>
  6. </style>
  7. <script src="https://d3js.org/d3.v7.min.js"></script>
  8. <script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/2.25.6/d3-legend.min.js"></script>
  9. </head>
  10.  
  11. <body id="svg_wrapper">
  12. <div id="sample"></div>
  13. <script>
  14.  
  15. const data = [
  16. { name: 'Jan-Feb', sunshine: 0.74 },
  17. { name: 'Feb-Mar', sunshine: 37.5 },
  18. { name: 'Mar-Apr', sunshine: 14.97 },
  19. { name: 'Apr-May', sunshine: 30.6977 },
  20. { name: 'May-Jun', sunshine: 10.6762 },
  21. { name: 'Jun-Jul', sunshine: 2.2508 },
  22. { name: 'Jul-Aug', sunshine: 11.0063 },
  23. { name: 'Aug-Sept', sunshine: 20.1413 },
  24. { name: 'Sept-Oct', sunshine: 14.6018 },
  25. { name: 'Oct-Nov', sunshine: 41.4508 },
  26. { name: 'Nov-Dec', sunshine: 6.19 },
  27. ];
  28.  
  29. function ramp(color, n = 256) {
  30. const canvas = document.createElement("canvas");
  31. canvas.width = n;
  32. canvas.height = 1;
  33. const context = canvas.getContext("2d");
  34. for (let i = 0; i < n; ++i) {
  35. context.fillStyle = color(i / (n - 1));
  36. context.fillRect(i, 0, 1, 1);
  37. }
  38. return canvas;
  39. }
  40.  
  41. //Mike Bostock's Legend class implementation from https://observablehq.com/@d3/color-legend
  42. function Legend(color, {
  43. title,
  44. tickSize = 6,
  45. width = 320,
  46. height = 44 + tickSize,
  47. marginTop = 18,
  48. marginRight = 0,
  49. marginBottom = 16 + tickSize,
  50. marginLeft = 0,
  51. ticks = width / 64,
  52. tickFormat,
  53. tickValues
  54. } = {}) {
  55.  
  56. function ramp(color, n = 256) {
  57. const canvas = document.createElement("canvas");
  58. canvas.width = n;
  59. canvas.height = 1;
  60. const context = canvas.getContext("2d");
  61. for (let i = 0; i < n; ++i) {
  62. context.fillStyle = color(i / (n - 1));
  63. context.fillRect(i, 0, 1, 1);
  64. }
  65. return canvas;
  66. }
  67.  
  68. const svg = d3.create("svg")
  69. .attr("width", width)
  70. .attr("height", height)
  71. .attr("viewBox", [0, 0, width, height])
  72. .style("overflow", "visible")
  73. .style("display", "block");
  74.  
  75. let tickAdjust = g => g.selectAll(".tick line").attr("y1", marginTop + marginBottom - height);
  76. let x;
  77.  
  78. // Continuous
  79. if (color.interpolate) {
  80. const n = Math.min(color.domain().length, color.range().length);
  81.  
  82. x = color.copy().rangeRound(d3.quantize(d3.interpolate(marginLeft, width - marginRight), n));
  83.  
  84. svg.append("image")
  85. .attr("x", marginLeft)
  86. .attr("y", marginTop)
  87. .attr("width", width - marginLeft - marginRight)
  88. .attr("height", height - marginTop - marginBottom)
  89. .attr("preserveAspectRatio", "none")
  90. .attr("xlink:href", ramp(color.copy().domain(d3.quantize(d3.interpolate(0, 1), n))).toDataURL());
  91. }
  92.  
  93. // Sequential
  94. else if (color.interpolator) {
  95. x = Object.assign(color.copy()
  96. .interpolator(d3.interpolateRound(marginLeft, width - marginRight)),
  97. { range() { return [marginLeft, width - marginRight]; } });
  98.  
  99. svg.append("image")
  100. .attr("x", marginLeft)
  101. .attr("y", marginTop)
  102. .attr("width", width - marginLeft - marginRight)
  103. .attr("height", height - marginTop - marginBottom)
  104. .attr("preserveAspectRatio", "none")
  105. .attr("xlink:href", ramp(color.interpolator()).toDataURL());
  106.  
  107. // scaleSequentialQuantile doesnโ€™t implement ticks or tickFormat.
  108. if (!x.ticks) {
  109. if (tickValues === undefined) {
  110. const n = Math.round(ticks + 1);
  111. tickValues = d3.range(n).map(i => d3.quantile(color.domain(), i / (n - 1)));
  112. }
  113. if (typeof tickFormat !== "function") {
  114. tickFormat = d3.format(tickFormat === undefined ? ",f" : tickFormat);
  115. }
  116. }
  117. }
  118.  
  119. // Threshold
  120. else if (color.invertExtent) {
  121. const thresholds
  122. = color.thresholds ? color.thresholds() // scaleQuantize
  123. : color.quantiles ? color.quantiles() // scaleQuantile
  124. : color.domain(); // scaleThreshold
  125.  
  126. const thresholdFormat
  127. = tickFormat === undefined ? d => d
  128. : typeof tickFormat === "string" ? d3.format(tickFormat)
  129. : tickFormat;
  130.  
  131. x = d3.scaleLinear()
  132. .domain([-1, color.range().length - 1])
  133. .rangeRound([marginLeft, width - marginRight]);
  134.  
  135. svg.append("g")
  136. .selectAll("rect")
  137. .data(color.range())
  138. .join("rect")
  139. .attr("x", (d, i) => x(i - 1))
  140. .attr("y", marginTop)
  141. .attr("width", (d, i) => x(i) - x(i - 1))
  142. .attr("height", height - marginTop - marginBottom)
  143. .attr("fill", d => d);
  144.  
  145. tickValues = d3.range(thresholds.length);
  146. tickFormat = i => thresholdFormat(thresholds[i], i);
  147. }
  148.  
  149. // Ordinal
  150. else {
  151. x = d3.scaleBand()
  152. .domain(color.domain())
  153. .rangeRound([marginLeft, width - marginRight]);
  154.  
  155. svg.append("g")
  156. .selectAll("rect")
  157. .data(color.domain())
  158. .join("rect")
  159. .attr("x", x)
  160. .attr("y", marginTop)
  161. .attr("width", Math.max(0, x.bandwidth() - 1))
  162. .attr("height", height - marginTop - marginBottom)
  163. .attr("fill", color);
  164.  
  165. tickAdjust = () => { };
  166. }
  167.  
  168. svg.append("g")
  169. .attr("transform", `translate(0,${height - marginBottom})`)
  170. .call(d3.axisBottom(x)
  171. .ticks(ticks, typeof tickFormat === "string" ? tickFormat : undefined)
  172. .tickFormat(typeof tickFormat === "function" ? tickFormat : undefined)
  173. .tickSize(tickSize)
  174. .tickValues(tickValues))
  175. .call(tickAdjust)
  176. .call(g => g.select(".domain").remove())
  177. .call(g => g.append("text")
  178. .attr("x", marginLeft)
  179. .attr("y", marginTop + marginBottom - height - 6)
  180. .attr("fill", "currentColor")
  181. .attr("text-anchor", "start")
  182. .attr("font-weight", "bold")
  183. .attr("class", "title")
  184. .text(title));
  185.  
  186. return svg.node();
  187. }
  188.  
  189. const width = 1200;
  190. const height = 450;
  191. const margin = { top: 50, bottom: 50, left: 50, right: 50 };
  192.  
  193. const svg = d3.select("#sample")
  194. .append('svg')
  195. .attr('width', width - margin.left - margin.right)
  196. .attr('height', height - margin.top - margin.bottom)
  197. .attr("viewBox", [0, 0, width, height]);
  198.  
  199. const x = d3.scaleBand()
  200. .domain(data.map(d => d.name))
  201. .range([margin.left, width - margin.right])
  202. .padding(0.1)
  203.  
  204. const y = d3.scaleLinear()
  205. .domain([0, 50])
  206. .range([height - margin.bottom, margin.top])
  207.  
  208. //var colorScale = d3.scaleLinear()
  209. //.domain([0, 100])
  210. //.range(["steelblue", "blue"]);
  211. //const legend = d3.legendColor().scale(colorScale)
  212.  
  213.  
  214. //Mike Bostock's continuous legend call
  215. const legend = Legend(d3.scaleQuantize([0, 50], d3.schemePurples[8]), {
  216. title: "Absolute value percentage change of sunshine (%)"
  217. })
  218.  
  219. svg
  220. .append("g")
  221. .selectAll("rect")
  222. .data(data)
  223. .join("rect")
  224. .attr("fill", function (d) {
  225. d = d.sunshine
  226. if (d < 6.25) {
  227. return d3.schemePurples[8][1];
  228. } else if (d < 12.5) {
  229. return d3.schemePurples[8][1];
  230. }
  231. else if (d < 18.75) {
  232. return d3.schemePurples[8][2];
  233. }
  234. else if (d < 25) {
  235. return d3.schemePurples[8][3];
  236. }
  237. else if (d < 31.25) {
  238. return d3.schemePurples[8][4];
  239. }
  240. else if (d < 37.5) {
  241. return d3.schemePurples[8][5];
  242. }
  243. else if (d < 43.75) {
  244. return d3.schemePurples[8][6];
  245. }
  246. else {
  247. return d3.schemePurples[8][7];
  248. }
  249. })
  250. .attr("x", (d, i) => x(d.name))
  251. .attr("y", d => y(d.sunshine))
  252. .attr('title', (d) => d.sunshine)
  253. .attr("class", "rect")
  254. .attr("height", d => y(0) - y(d.sunshine))
  255. .attr("width", x.bandwidth())
  256.  
  257.  
  258.  
  259. //Adding data values on the bar
  260. svg
  261. .selectAll("rect")
  262. .data(data)
  263. .enter()
  264. .append("text")
  265. .text((function (data) { return data.sunshine }))
  266. .attr("class", "text2")
  267.  
  268. function yAxis(g) {
  269. g.attr("transform", `translate(${margin.left}, 0)`)
  270. .call(d3.axisLeft(y))
  271. .attr("font-size", '15px')
  272. svg.append("text")
  273. .attr("text-anchor", "end")
  274. .attr("transform", "rotate(-90)")
  275. .attr("y", -margin.left + 20)
  276. .attr("x", -margin.top)
  277. .text("Percentage Changes of Sunshine for 2 Consecutive Months")
  278. }
  279.  
  280. function xAxis(g) {
  281. g.attr("transform", `translate(0,${height - margin.bottom})`)
  282. .call(d3.axisBottom(x))
  283. .attr("font-size", '20px')
  284. g.append("text")
  285. .attr("text-anchor", "end")
  286. .attr("y", height + margin.top + 100)
  287. .attr("x", width)
  288. .text("Months");
  289. }
  290.  
  291. //(Attempt to) Add data to the top of rectangles
  292. svg.selectAll("rect")
  293. .data(data)
  294. .enter().append("rect")
  295.  
  296. .attr("height", function (d, i) { return (d.sunshine * 10) })
  297. .attr("width", "40")
  298. .attr("x", function (d, i) { return (i * 60) + 25 })
  299. .attr("y", function (d, i) { return 400 - (d.sunshine * 10) });
  300.  
  301.  
  302. svg.append("g").call(xAxis);
  303. svg.append("g").call(yAxis);
  304. svg.append(() => legend)
  305. .attr("x", -margin.top + 100)
  306.  
  307. //Attempt to add x-axis label but its not centered
  308. let textnode = document.createTextNode("Months in a Year");
  309. document.getElementById("sample").appendChild(textnode);
  310. svg.node();
  311. </script>
  312. </body>
  313.  
  314. </html>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement