在d3中使轴刻度线字符串

时间:2018-08-03 13:56:01

标签: d3.js

我正在更新由以前的开发人员编写的d3图形。作为非专家ind d3,我很难找到解决问题的答案。我想做的一件事是更改x轴刻度以从状态中拾取字符串值,但是,我尝试的所有操作都会破坏图表。

数据:

let extractedData = [
  { label: '2018-7-3', wage: 7.5 },
  { label: '2018-5-3', wage: 6.1 },
  { label: '2018-1-3', wage: 5.3 },
  { label: '2018-11-3', wage: 6.1 }
];

标签应成为x轴刻度线。

    const x_scale = d3
      .scaleLinear()
      .domain([0, 4])
      .range([padding, chart_width - 3 * padding]);

    const x_axis = d3
      .axisBottom(x_scale)
      .ticks(4)
      .tickSize(1)

构建此图表的整个代码块为:

const x_scale = d3
          .scaleLinear()
          .domain(data.map(function (d) { return d.label; }))
          .range([padding, chart_width - 3 * padding]);

        const y_scale = d3
          .scaleLinear()
          .domain([0, wages])
          .range([chart_height - 2 * padding, padding]);

        const svg = d3
          .select('#lineChart')
          .append('svg')
          .attr('width', chart_width)
          .attr('height', chart_height)
          .attr('viewBox', '0 0 700 700');
        //create axes
        const x_axis = d3
          .axisBottom(x_scale)
          .ticks(4)
          .tickSize(0)
          .tickFormat(function (d) {
            return d;
          });

        const y_axis = d3
          .axisLeft(y_scale)
          .ticks(10)
          .tickSize(0)
          .tickFormat(function (d) {
            return '£' + d;
          });
        //draw axes
        svg
          .append('g')
          .attr('class', 'xAxis')
          .attr(
            'transform',
            'translate(' + padding + ', ' + (chart_height - 2 * padding) + ')'
          )
          .call(x_axis);
        svg
          .append('g')
          .attr('class', 'yAxis')
          .attr('transform', 'translate(' + 2 * padding + ',0)')
          .call(y_axis);

        svg
          .select('.xAxis')
          .selectAll('text')
          .attr('transform', 'translate(0,10)')
          .attr('font-size', '1.5rem');

        svg
          .select('.yAxis')
          .selectAll('text')
          .attr('transform', 'translate(-10,0)')
          .attr('font-size', '1.5rem');
        //create circles
        svg
          .selectAll('circle') // selecting the cicles that dont yet exist. sending the data to the waiting room to wait for circles to be created
          .data(data)
          .enter()
          .append('circle')
          .attr('cx', function (d) {
            return x_scale(d.label); // d3 can work out which number to use on the axis to plot correctly
          })
          .attr('cy', function (d) {
            return y_scale(d.wage);
          })
          .attr('r', 10)
          .attr('fill', '#FFD254');

        //create labels for circles
        svg
          .append('g') // first create, append and select a group
          .selectAll('text') // then when you do 'select all text' you know that no text exists in this group because it has just been created
          .data(data)
          .enter()
          .append('text')
          .text(function (d) {
            return '£' + d.wage;
          })
          .attr('x', function (d) {
            return x_scale(d.label) + padding / 3;
          })
          .attr('y', function (d) {
            return y_scale(d.wage);
          })
          .attr('font-size', '1.5rem');
        //create horizontal line
        svg
          .append('line')
          .attr('x1', padding * 2)
          .attr('x2', chart_width - 2 * padding)
          .attr('y1', y_scale(min_wage))
          .attr('y2', y_scale(min_wage))
          .style('stroke', 'red')
          .style('stroke-width', '2px');
        svg
          .append('text')
          .attr(
            'transform',
            'translate(' +
            (chart_width - 2 * padding) +
            ' ,' +
            (chart_height - padding / 2) +
            ')'
          )
          .style('text-anchor', 'middle')
          .style('font-size', '1.5rem')
          .text('Month');
      })
  };

1 个答案:

答案 0 :(得分:1)

  1. 使用边距始终是一个好习惯

    margin = {top: 20, right: 20, bottom: 30, left: 70},
    
  2. 基于这些边距,我为所有元素创建了一个组

    var g = svg.append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); 
    
  3. 问题中最重要的要求:字符串作为轴刻度线

    正如@ rioV8也在评论中提到的,最好使用序数标度。

    const x_scale = d3
      .scaleBand()
      .domain(data.map(function (d) { return d.label; }))
      .rangeRound([0, chart_width]).padding(0.1);
    
  4. yScale域设置为工资的程度,并使用d3 nice舍入值:

    const y_scale = d3
      .scaleLinear()
      .domain(d3.extent(data, function (d) { return +d.wage; })).nice()
      .rangeRound([chart_height, 0]);
    
  5. 将所有圈子/文字移动到组内

    var circlesGroup = g.append('g').classed('circles', true);
    //create circles
    circlesGroup.selectAll('circle') ....
    
  6. 将'text-anchor'更改为X轴文本(月份)为'end'以对齐它

    .style('text-anchor', 'end')
    
  7. 您没有设置min_wage-因此我将其设置为7

将以上所有内容放在一起,下面是一个代码段:

var width = 900,
	height = 550,
  padding = 0,
  margin = {top: 20, right: 20, bottom: 30, left: 70},
  min_wage = 7;
  
  var chart_height = height-margin.top-margin.bottom,
  	chart_width = width-margin.left-margin.right;

let data = [
  { label: '2018-7-3', wage: 7.5 },
  { label: '2018-5-3', wage: 6.1 },
  { label: '2018-1-3', wage: 5.3 },
  { label: '2018-11-3', wage: 6.1 }
];

const x_scale = d3.scaleBand()
          .domain(data.map(function (d) { return d.label; }))
          .rangeRound([0, chart_width]).padding(0.1);

        const y_scale = d3
          .scaleLinear()
          .domain(d3.extent(data, function (d) { return +d.wage; })).nice()
          .rangeRound([chart_height, 0]);

        const svg = d3
          .select('#lineChart')
          .append('svg')
          .attr('width', width)
          .attr('height', height);
          
			var g = svg.append("g")
	    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");          
        //create axes
        const x_axis = d3
          .axisBottom(x_scale)
          .ticks(4)
          .tickFormat(function (d) {
            return d;
          });

        const y_axis = d3
          .axisLeft(y_scale)
          .ticks(10)
          .tickSize(0)
          .tickFormat(function (d) {
            return '£' + d;
          });
        //draw axes
        g
          .append('g')
          .attr('class', 'xAxis')
          .attr(
            'transform',
            'translate(0, ' + (chart_height) + ')'
          )
          .call(x_axis);
        g
          .append('g')
          .attr('class', 'yAxis')
          .call(y_axis);

        g
          .select('.xAxis')
          .selectAll('text')
          .attr('transform', 'translate(0,10)')
          .attr('font-size', '1.5rem');

        g
          .select('.yAxis')
          .selectAll('text')
          .attr('transform', 'translate(-10,0)')
          .attr('font-size', '1.5rem');
          
       	var circlesGroup = g.append('g').classed('circles', true);
        //create circles
        circlesGroup
          .selectAll('circle') // selecting the cicles that dont yet exist. sending the data to the waiting room to wait for circles to be created
          .data(data)
          .enter()
          .append('circle')
          .attr('cx', function (d) {
            return x_scale(d.label)+x_scale.bandwidth()/2; // d3 can work out which number to use on the axis to plot correctly
          })
          .attr('cy', function (d) {
            return y_scale(d.wage);
          })
          .attr('r', 10)
          .attr('fill', '#FFD254');

				var textsGroup = g.append('g').classed('texts', true);
        //create labels for circles
        textsGroup
          .append('g') // first create, append and select a group
          .selectAll('text') // then when you do 'select all text' you know that no text exists in this group because it has just been created
          .data(data)
          .enter()
          .append('text')
          .text(function (d) {
            return '£' + d.wage;
          })
          .attr('x', function (d) {
            return x_scale(d.label) + x_scale.bandwidth()/2;
          })
          .attr('y', function (d) {
            return y_scale(d.wage);
          })
          .attr('font-size', '1.5rem');
        //create horizontal line
        g
          .append('line')
          .attr('x1', 0)
          .attr('x2', chart_width)
          .attr('y1', y_scale(min_wage))
          .attr('y2', y_scale(min_wage))
          .style('stroke', 'red')
          .style('stroke-width', '2px');
        g
          .append('text')
          .attr(
            'transform',
            'translate(' +
            (chart_width - 2 * padding) +
            ' ,' +
            (chart_height - padding / 2) +
            ')'
          )
          .style('text-anchor', 'end')
          .style('font-size', '1.5rem')
          .text('Month');
text {
  font-size: 12px;
}
<script src="https://d3js.org/d3.v4.min.js"></script>

<div id="lineChart">

</div>

编辑: 使用比例带宽更改了圆圈和标签的位置:

      .attr('x', function (d) {
        return x_scale(d.label) + x_scale.bandwidth()/2;
      })

(将tickSize更改为6以确保上面的编辑有效)

希望这会有所帮助。