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

kuhbmx9i  于 12个月前  发布在  其他
关注(0)|答案(2)|浏览(157)

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

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

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

const data = await d3.csv(src); 

  console.log(d3.max(data, d => {
    return d;
  }));
  // returns {name: 'Item 1', cat1: '50', cat2: '102', cat3: '302'}
  
  // Would like to use the max value
  // rather than 350
  y.domain([350, 0])
   .range([0, height]);


感谢你的帮助.

xv8emn3q

xv8emn3q1#

const margin = { top: 20, right: 50, bottom: 50, left: 70 };
const wrap = d3.select('#chart-wrap');
let wrapWidth = parseInt(wrap.style('width'));
let width = wrapWidth - margin.left - margin.right;
const wrapHeight = parseInt(wrap.style('height'));
const height = wrapHeight - margin.top - margin.bottom;
let subgroup;
const y = d3.scaleLinear();
const x0 = d3.scaleBand();
const x1 = d3.scaleBand();
const src = 'https://assets.codepen.io/1329727/data-multi-demo.csv';
const colors = d3.scaleOrdinal()
  .range(['#5626C4', '#E60576', '#2CCCC3', '#FACD3D', '#181818']);
let tooltipChart;

// Tooltip
const tooltipMouseMove = (key, value, loc) => {

  tooltipChart
    .html(() => {
      return (
        `<div class="chart-tooltip-wrap">
          <p><strong>${key}</strong></p>
          <p>${value}</p>
         </div>
        `
       );
    })
    .style('visibility', 'visible')
    .style('left', `${d3.pointer(event)[0] + loc}px`)
    .style('top', `${d3.pointer(event)[1] + 20}px`)
}

const tooltipMouseOut = () => {
  tooltipChart
    .style('visibility', 'hidden');
}

const svg = wrap.append('svg')
  .attr('width', width + margin.left + margin.right)
  .attr('height', height + margin.top + margin.bottom);
  
// SVG aria tags
svg.append('title')
  .attr('id','chart-title')
  .html('Group, verical bar chart');

svg.append('desc')
  .attr('id','chart-desc')
  .html('Displays grouped bar charts for different items.');

svg.attr('aria-labelledby','chart-title chart-desc');

tooltipChart = wrap.append('div')
    .attr('class','chart-tooltip')
    .style('visibility', 'hidden');

const group = svg.append('g')
    .attr('class', 'group')
    .attr('transform', `translate(${margin.left}, ${margin.top})`);
      
async function createGroupBars() {
  const data = await d3.csv(src); 
  
  // Keys and group keys
  const keys = data.columns.slice(1);
  const groupKey = data.columns[0];
  
  const values = [];
  data.forEach((el)=> {
    for(let i = 0; i < keys.length; i++) {
        values.push(+el[keys[i]])
    }
  })
  
  // Bar width
  const barWidth = (width / groupKey.length);
  
  const isSame = (data,keys) => {
       let output = false;
       for(let i=0; i<keys.length;i++) {
         if(data[keys[i]] == max){
           output = true;
           break;
         }
       }
    return output;
  }
  
 // Getting the maximum value from the keys
 let max = d3.max(values);
 let result = data.find((d) => {
   return isSame(d,keys);
 });
  
  // Scales
  y.domain([max, 0])
    .range([0, height]);

  x0.domain(data.map(d => { return d[groupKey]; }))
    .range([0, width])
    .paddingInner(0.3);
  
  if (width < 400) {
    x0.paddingInner(0.15);
  }

   x1.domain(keys)
    .range([0, x0.bandwidth()]);
 
  // X Axis
  const xAxis = group.append('g')
    .attr('class', 'x-axis')
    .attr('transform', `translate(0, ${height})`)
    .call(
      d3.axisBottom(x0)
      .tickSize(7)
    );

  xAxis.call(g => g.select('.domain').remove());
  
  // X axis labels 
  xAxis.selectAll('text')
      .attr('transform', 'translate(-10, 0) rotate(-45)')
      .style('text-anchor', 'end');
  
  // Y Axis
  group.append('g')
    .attr('class', 'y-axis')
    .call(
      d3.axisLeft(y)
        .tickSizeOuter(0)
        .tickSize(-width)
     );
  
    d3.selectAll('.y-axis text')
      .attr('x', -10)
  
   // Subgroups of rectangles
  subgroup = group.selectAll('.subgroup')
    .data(data)
    .join('g')
    .attr('class', 'subgroup')
    .attr('transform', (d) => {
      return `translate(${x0(d[groupKey])}, 0)`;
    })
    .attr('aria-label', d => {
      return `Values for ${d.name}`
    })

  // Rectangles
  subgroup
    .selectAll('rect')
    .data(d => {
      return keys.map(key => {
        return { key: key, value: d[key] }
      });
    })
    .join('rect')
    .attr('class', 'rect')
    .attr('y', d => y(d.value))
    .attr('x', d => { return x1(d.key); })
    .attr('height', (d) => { return height - y(d.value); })
    .attr('width', x1.bandwidth())
    .attr('fill', (d, i) => { return colors(d.key); })
    .attr('aria-label', d => {
      return `${d.key} bar`;
    })
    .on('mousemove', function (event, d, i) {
    
      // Get parent's translate x value
      const parent = d3.select(this.parentNode).attr('transform').slice(10);
      const loc = parseFloat(parent);
    
      // call tooltip function
      tooltipMouseMove(d.key, d.value, loc);
    })
    .on('mouseout', () => {
      tooltipMouseOut();
    });

  // Rectangle labels
  subgroup.selectAll('.bar-labels')
    .data(d => {
      return keys.map(key => {
        return { key: key, value: d[key] }
      });
    })
    .join('text')
    .attr('class', 'bar-labels')
    .attr('y', d => { return y(d.value) - 3 })
    .attr('x', d => { return x1(d.key) + 12; })
    .attr('text-anchor', 'middle')
    .style('fill', '#181818')
    .text(d => { return d.value });
  
   // Legend
  const createLegend = (parent, cat) => {
      parent.append('div')
        .attr('class', 'legend')
        .selectAll('div')
        .data(data.columns.slice(1))
        .enter()
        .append('div')
        .attr('class', 'legend-group')
        .html((d, i) => {
          return(`
            <div class="legend-box" style="background-color: ${colors(cat[i])};"></div>
            <p class="legend-label">${cat[i]}</p>
          `);
        });
      }
    createLegend(wrap, Object.keys(data[0]).slice(1));

    // Resize
    const resize = () => {
      wrapWidth = parseInt(wrap.style('width'));
      width = wrapWidth - margin.left - margin.right;

      x0.range([0, width])
        .paddingInner(0.3);
      
      if (width < 400) {
        x0.paddingInner(0.15);
      }

      x1.range([0, x0.bandwidth()]);
      
      svg.attr('width', width + margin.left + margin.right);
      
      subgroup.selectAll('.rect')
        .attr('x', d => { return x1(d.key); })
        .attr('width', x1.bandwidth());
      
      subgroup.selectAll('.bar-labels')
        .attr('x', d => { return x1(d.key) + 12; })
      
      group.select('.x-axis')
        .attr('transform', `translate(0, ${height})`)
        .call(
          d3.axisBottom(x0)
        );
      
      group.select('.y-axis')
        .call(
          d3.axisLeft(y)
            .tickSizeOuter(0)
            .tickSize(-width)
         );
      
      subgroup.attr('transform', (d) => {
        return `translate(${x0(d[groupKey])}, 0)`;
      });
    }
    
    d3.select(window).on('resize', resize);
  
}
createGroupBars();
body {
  background-color: #f7f4e9;
  font-family: sans-serif;
}

.chart-section {
  margin: 2rem auto;
  padding: 1rem;
  width: calc(100% - 2rem);
  max-width: 700px;
}
.chart-section #chart-wrap {
  height: 400px;
  width: 100%;
  position: relative;
}
.chart-section #chart-wrap .chart-tooltip {
  margin-left: 10px;
  position: absolute;
  z-index: 10;
}
.chart-section #chart-wrap .chart-tooltip .chart-tooltip-wrap {
  background-color: #181818;
  border-radius: 10px;
  box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3);
  display: block;
  padding: 0.875rem;
}
.chart-section #chart-wrap .chart-tooltip .chart-tooltip-wrap p {
  color: #fff;
  font-size: 0.875rem;
  line-height: 1.75;
  margin: 0;
}
.chart-section #chart-wrap svg {
  margin: auto;
}
.chart-section #chart-wrap svg .y-axis .domain {
  display: none;
}
.chart-section #chart-wrap svg .y-axis .tick line {
  stroke: #aaa;
  stroke-dasharray: 3, 3;
}
.chart-section #chart-wrap svg .y-axis .tick:last-child line {
  stroke: #555;
  stroke-dasharray: 0;
}
.chart-section #chart-wrap svg .bar-labels {
  font-size: 0.875rem;
  display: block;
}
@media (max-width: 700px) {
  .chart-section #chart-wrap svg .bar-labels {
    display: none;
  }
}
.chart-section #chart-wrap svg .tick line {
  stroke: #555;
}
.chart-section #chart-wrap svg .tick text {
  font-size: 0.875rem;
}
.chart-section #chart-wrap .legend {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: center;
  margin: 2rem auto;
  width: 100%;
}
.chart-section #chart-wrap .legend .legend-group {
  align-items: center;
  display: flex;
  flex-basis: 100px;
  flex-direction: row;
  gap: 8px;
  justify-content: flex-start;
}
.chart-section #chart-wrap .legend .legend-group .legend-box {
  height: 20px;
  margin: 0;
  width: 20px;
}
.chart-section #chart-wrap .legend .legend-group .legend-label {
  margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3.min.js"></script>
<section class="chart-section">
  <div id="chart-wrap"></div>
</section>

代码说明

我修改了容器中SVG的代码

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


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

const values = [];
  data.forEach((el)=> {
    for(let i = 0; i < keys.length; i++) {
        values.push(+el[keys[i]])
    }
  })
  
  // Bar width
  const barWidth = (width / groupKey.length);
  
  const isSame = (data,keys) => {
       let output = false;
       for(let i=0; i<keys.length;i++) {
         if(data[keys[i]] == max){
           output = true;
           break;
         }
       }
    return output;
  }
  
 // Getting the maximum value from the keys
 let max = d3.max(values);
 let result = data.find((d) => {
   return isSame(d,keys);
 });

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

k4ymrczo

k4ymrczo2#

let data = [{
    name: 'Item 1',
    cat1: 50,
    cat2: 102,
    cat3: 302
},
{
    name: 'Item 2',
    cat1: 79,
    cat2: 140,
    cat3: 330
},
{
    name: 'Item 3',
    cat1: 200,
    cat2: 180,
    cat3: 120      
},
{
    name: 'Item 4',
    cat1: 104,
    cat2: 80,
    cat3: 83    
},
{
    name: 'Item 5',
    cat1: 90,
    cat2: 320,
    cat3: 130       
},
{
    name: 'Item 6',
    cat1: 85,
    cat2: 114,
    cat3: 130   
}
]

let max = d3.max(data, ((d)=> (d.cat1,d.cat2,d.cat3)));
let result = data.find((d) => d.cat1 == max || d.cat2 == max || d.cat3 == max);
console.log(result)

个字符

相关问题