csv 获取分组条形图y域的d3.max值

kuhbmx9i  于 2024-01-03  发布在  其他
关注(0)|答案(2)|浏览(168)

我已经创建了一个分组条形图,并试图将y域设置为最大的条形值。这样做而不是根据数据而改变的静态数字。我对如何在CSV文件中使用d3.max()多列感到困惑。我试图使它不必使用特定的列名,因为这在其他CSV文件中可能不同。现在列名是cat1、cat2和cat3。我使用的是D3 v7
数据

  1. name,cat1,cat2,cat3
  2. Item 1,50,102,302
  3. Item 2,79,140,330
  4. Item 3,200,180,120
  5. Item 4,104,80,83
  6. Item 5,90,320,130
  7. Item 6,85,114,130

字符串
我有点明白如何使用d3.max(),但绝对不是在这样的情况下。
下面是我目前使用它的方式。你会看到我在y域中设置了一个350。现在我只是尝试控制台日志的最大值。我意识到我没有正确地这样做,但不知道如何。
D3

  1. const data = await d3.csv(src);
  2. console.log(d3.max(data, d => {
  3. return d;
  4. }));
  5. // returns {name: 'Item 1', cat1: '50', cat2: '102', cat3: '302'}
  6. // Would like to use the max value
  7. // rather than 350
  8. y.domain([350, 0])
  9. .range([0, height]);


感谢你的帮助.

xv8emn3q

xv8emn3q1#

  1. const margin = { top: 20, right: 50, bottom: 50, left: 70 };
  2. const wrap = d3.select('#chart-wrap');
  3. let wrapWidth = parseInt(wrap.style('width'));
  4. let width = wrapWidth - margin.left - margin.right;
  5. const wrapHeight = parseInt(wrap.style('height'));
  6. const height = wrapHeight - margin.top - margin.bottom;
  7. let subgroup;
  8. const y = d3.scaleLinear();
  9. const x0 = d3.scaleBand();
  10. const x1 = d3.scaleBand();
  11. const src = 'https://assets.codepen.io/1329727/data-multi-demo.csv';
  12. const colors = d3.scaleOrdinal()
  13. .range(['#5626C4', '#E60576', '#2CCCC3', '#FACD3D', '#181818']);
  14. let tooltipChart;
  15. // Tooltip
  16. const tooltipMouseMove = (key, value, loc) => {
  17. tooltipChart
  18. .html(() => {
  19. return (
  20. `<div class="chart-tooltip-wrap">
  21. <p><strong>${key}</strong></p>
  22. <p>${value}</p>
  23. </div>
  24. `
  25. );
  26. })
  27. .style('visibility', 'visible')
  28. .style('left', `${d3.pointer(event)[0] + loc}px`)
  29. .style('top', `${d3.pointer(event)[1] + 20}px`)
  30. }
  31. const tooltipMouseOut = () => {
  32. tooltipChart
  33. .style('visibility', 'hidden');
  34. }
  35. const svg = wrap.append('svg')
  36. .attr('width', width + margin.left + margin.right)
  37. .attr('height', height + margin.top + margin.bottom);
  38. // SVG aria tags
  39. svg.append('title')
  40. .attr('id','chart-title')
  41. .html('Group, verical bar chart');
  42. svg.append('desc')
  43. .attr('id','chart-desc')
  44. .html('Displays grouped bar charts for different items.');
  45. svg.attr('aria-labelledby','chart-title chart-desc');
  46. tooltipChart = wrap.append('div')
  47. .attr('class','chart-tooltip')
  48. .style('visibility', 'hidden');
  49. const group = svg.append('g')
  50. .attr('class', 'group')
  51. .attr('transform', `translate(${margin.left}, ${margin.top})`);
  52. async function createGroupBars() {
  53. const data = await d3.csv(src);
  54. // Keys and group keys
  55. const keys = data.columns.slice(1);
  56. const groupKey = data.columns[0];
  57. const values = [];
  58. data.forEach((el)=> {
  59. for(let i = 0; i < keys.length; i++) {
  60. values.push(+el[keys[i]])
  61. }
  62. })
  63. // Bar width
  64. const barWidth = (width / groupKey.length);
  65. const isSame = (data,keys) => {
  66. let output = false;
  67. for(let i=0; i<keys.length;i++) {
  68. if(data[keys[i]] == max){
  69. output = true;
  70. break;
  71. }
  72. }
  73. return output;
  74. }
  75. // Getting the maximum value from the keys
  76. let max = d3.max(values);
  77. let result = data.find((d) => {
  78. return isSame(d,keys);
  79. });
  80. // Scales
  81. y.domain([max, 0])
  82. .range([0, height]);
  83. x0.domain(data.map(d => { return d[groupKey]; }))
  84. .range([0, width])
  85. .paddingInner(0.3);
  86. if (width < 400) {
  87. x0.paddingInner(0.15);
  88. }
  89. x1.domain(keys)
  90. .range([0, x0.bandwidth()]);
  91. // X Axis
  92. const xAxis = group.append('g')
  93. .attr('class', 'x-axis')
  94. .attr('transform', `translate(0, ${height})`)
  95. .call(
  96. d3.axisBottom(x0)
  97. .tickSize(7)
  98. );
  99. xAxis.call(g => g.select('.domain').remove());
  100. // X axis labels
  101. xAxis.selectAll('text')
  102. .attr('transform', 'translate(-10, 0) rotate(-45)')
  103. .style('text-anchor', 'end');
  104. // Y Axis
  105. group.append('g')
  106. .attr('class', 'y-axis')
  107. .call(
  108. d3.axisLeft(y)
  109. .tickSizeOuter(0)
  110. .tickSize(-width)
  111. );
  112. d3.selectAll('.y-axis text')
  113. .attr('x', -10)
  114. // Subgroups of rectangles
  115. subgroup = group.selectAll('.subgroup')
  116. .data(data)
  117. .join('g')
  118. .attr('class', 'subgroup')
  119. .attr('transform', (d) => {
  120. return `translate(${x0(d[groupKey])}, 0)`;
  121. })
  122. .attr('aria-label', d => {
  123. return `Values for ${d.name}`
  124. })
  125. // Rectangles
  126. subgroup
  127. .selectAll('rect')
  128. .data(d => {
  129. return keys.map(key => {
  130. return { key: key, value: d[key] }
  131. });
  132. })
  133. .join('rect')
  134. .attr('class', 'rect')
  135. .attr('y', d => y(d.value))
  136. .attr('x', d => { return x1(d.key); })
  137. .attr('height', (d) => { return height - y(d.value); })
  138. .attr('width', x1.bandwidth())
  139. .attr('fill', (d, i) => { return colors(d.key); })
  140. .attr('aria-label', d => {
  141. return `${d.key} bar`;
  142. })
  143. .on('mousemove', function (event, d, i) {
  144. // Get parent's translate x value
  145. const parent = d3.select(this.parentNode).attr('transform').slice(10);
  146. const loc = parseFloat(parent);
  147. // call tooltip function
  148. tooltipMouseMove(d.key, d.value, loc);
  149. })
  150. .on('mouseout', () => {
  151. tooltipMouseOut();
  152. });
  153. // Rectangle labels
  154. subgroup.selectAll('.bar-labels')
  155. .data(d => {
  156. return keys.map(key => {
  157. return { key: key, value: d[key] }
  158. });
  159. })
  160. .join('text')
  161. .attr('class', 'bar-labels')
  162. .attr('y', d => { return y(d.value) - 3 })
  163. .attr('x', d => { return x1(d.key) + 12; })
  164. .attr('text-anchor', 'middle')
  165. .style('fill', '#181818')
  166. .text(d => { return d.value });
  167. // Legend
  168. const createLegend = (parent, cat) => {
  169. parent.append('div')
  170. .attr('class', 'legend')
  171. .selectAll('div')
  172. .data(data.columns.slice(1))
  173. .enter()
  174. .append('div')
  175. .attr('class', 'legend-group')
  176. .html((d, i) => {
  177. return(`
  178. <div class="legend-box" style="background-color: ${colors(cat[i])};"></div>
  179. <p class="legend-label">${cat[i]}</p>
  180. `);
  181. });
  182. }
  183. createLegend(wrap, Object.keys(data[0]).slice(1));
  184. // Resize
  185. const resize = () => {
  186. wrapWidth = parseInt(wrap.style('width'));
  187. width = wrapWidth - margin.left - margin.right;
  188. x0.range([0, width])
  189. .paddingInner(0.3);
  190. if (width < 400) {
  191. x0.paddingInner(0.15);
  192. }
  193. x1.range([0, x0.bandwidth()]);
  194. svg.attr('width', width + margin.left + margin.right);
  195. subgroup.selectAll('.rect')
  196. .attr('x', d => { return x1(d.key); })
  197. .attr('width', x1.bandwidth());
  198. subgroup.selectAll('.bar-labels')
  199. .attr('x', d => { return x1(d.key) + 12; })
  200. group.select('.x-axis')
  201. .attr('transform', `translate(0, ${height})`)
  202. .call(
  203. d3.axisBottom(x0)
  204. );
  205. group.select('.y-axis')
  206. .call(
  207. d3.axisLeft(y)
  208. .tickSizeOuter(0)
  209. .tickSize(-width)
  210. );
  211. subgroup.attr('transform', (d) => {
  212. return `translate(${x0(d[groupKey])}, 0)`;
  213. });
  214. }
  215. d3.select(window).on('resize', resize);
  216. }
  217. createGroupBars();
  1. body {
  2. background-color: #f7f4e9;
  3. font-family: sans-serif;
  4. }
  5. .chart-section {
  6. margin: 2rem auto;
  7. padding: 1rem;
  8. width: calc(100% - 2rem);
  9. max-width: 700px;
  10. }
  11. .chart-section #chart-wrap {
  12. height: 400px;
  13. width: 100%;
  14. position: relative;
  15. }
  16. .chart-section #chart-wrap .chart-tooltip {
  17. margin-left: 10px;
  18. position: absolute;
  19. z-index: 10;
  20. }
  21. .chart-section #chart-wrap .chart-tooltip .chart-tooltip-wrap {
  22. background-color: #181818;
  23. border-radius: 10px;
  24. box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3);
  25. display: block;
  26. padding: 0.875rem;
  27. }
  28. .chart-section #chart-wrap .chart-tooltip .chart-tooltip-wrap p {
  29. color: #fff;
  30. font-size: 0.875rem;
  31. line-height: 1.75;
  32. margin: 0;
  33. }
  34. .chart-section #chart-wrap svg {
  35. margin: auto;
  36. }
  37. .chart-section #chart-wrap svg .y-axis .domain {
  38. display: none;
  39. }
  40. .chart-section #chart-wrap svg .y-axis .tick line {
  41. stroke: #aaa;
  42. stroke-dasharray: 3, 3;
  43. }
  44. .chart-section #chart-wrap svg .y-axis .tick:last-child line {
  45. stroke: #555;
  46. stroke-dasharray: 0;
  47. }
  48. .chart-section #chart-wrap svg .bar-labels {
  49. font-size: 0.875rem;
  50. display: block;
  51. }
  52. @media (max-width: 700px) {
  53. .chart-section #chart-wrap svg .bar-labels {
  54. display: none;
  55. }
  56. }
  57. .chart-section #chart-wrap svg .tick line {
  58. stroke: #555;
  59. }
  60. .chart-section #chart-wrap svg .tick text {
  61. font-size: 0.875rem;
  62. }
  63. .chart-section #chart-wrap .legend {
  64. display: flex;
  65. flex-direction: row;
  66. flex-wrap: wrap;
  67. gap: 10px;
  68. justify-content: center;
  69. margin: 2rem auto;
  70. width: 100%;
  71. }
  72. .chart-section #chart-wrap .legend .legend-group {
  73. align-items: center;
  74. display: flex;
  75. flex-basis: 100px;
  76. flex-direction: row;
  77. gap: 8px;
  78. justify-content: flex-start;
  79. }
  80. .chart-section #chart-wrap .legend .legend-group .legend-box {
  81. height: 20px;
  82. margin: 0;
  83. width: 20px;
  84. }
  85. .chart-section #chart-wrap .legend .legend-group .legend-label {
  86. margin: 0;
  87. }
  1. <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3.min.js"></script>
  2. <section class="chart-section">
  3. <div id="chart-wrap"></div>
  4. </section>

代码说明

我修改了容器中SVG的代码

  1. // increase bottom value
  2. const margin = { top: 20, right: 50, bottom: 20, left: 70 };
  3. // change zero translate y value to ${margin.top}
  4. const group = svg.append('g')
  5. .attr('class', 'group')
  6. .attr('transform', `translate(${margin.left}, ${margin.top})`)


并从CSV文件中动态获取最大值

  1. const values = [];
  2. data.forEach((el)=> {
  3. for(let i = 0; i < keys.length; i++) {
  4. values.push(+el[keys[i]])
  5. }
  6. })
  7. // Bar width
  8. const barWidth = (width / groupKey.length);
  9. const isSame = (data,keys) => {
  10. let output = false;
  11. for(let i=0; i<keys.length;i++) {
  12. if(data[keys[i]] == max){
  13. output = true;
  14. break;
  15. }
  16. }
  17. return output;
  18. }
  19. // Getting the maximum value from the keys
  20. let max = d3.max(values);
  21. let result = data.find((d) => {
  22. return isSame(d,keys);
  23. });

**注意:我并不关注代码的时间复杂度;我只是想解决问题。

展开查看全部
k4ymrczo

k4ymrczo2#

  1. let data = [{
  2. name: 'Item 1',
  3. cat1: 50,
  4. cat2: 102,
  5. cat3: 302
  6. },
  7. {
  8. name: 'Item 2',
  9. cat1: 79,
  10. cat2: 140,
  11. cat3: 330
  12. },
  13. {
  14. name: 'Item 3',
  15. cat1: 200,
  16. cat2: 180,
  17. cat3: 120
  18. },
  19. {
  20. name: 'Item 4',
  21. cat1: 104,
  22. cat2: 80,
  23. cat3: 83
  24. },
  25. {
  26. name: 'Item 5',
  27. cat1: 90,
  28. cat2: 320,
  29. cat3: 130
  30. },
  31. {
  32. name: 'Item 6',
  33. cat1: 85,
  34. cat2: 114,
  35. cat3: 130
  36. }
  37. ]
  38. let max = d3.max(data, ((d)=> (d.cat1,d.cat2,d.cat3)));
  39. let result = data.find((d) => d.cat1 == max || d.cat2 == max || d.cat3 == max);
  40. console.log(result)

个字符

展开查看全部

相关问题