如何使用“ d3.js”库在折线图中放置圆(点)?

时间:2019-03-26 12:40:42

标签: angular d3.js charts linechart

我想使用d3.js制作折线图,并在其中将圆圈放在数据位置。但是圆圈在折线图中放置在错误的位置。我该如何解决?

我在Angular工作。 基本数据集看起来像

{
          type: 'Advanced',
          wcpm: 40,
          date: '11-25-2019',
          comment: [
            'Lorem Ipsum Lorem Ipsum Lorem 1',
            'Ipsum Lorem Ipsum Lorem Ipsum Lorem Ipsum Lorem Ipsum 2'
          ]
 }

输出图像链接: https://ibb.co/pwRdXjx

第一个圆应放置在Jan25上,但位置错误。

class AppComponent implements OnInit {
 title = 'chart';
 margin = { top: 50, right: 50, bottom: 50, left: 50 };
 width = 1200 - this.margin.left - this.margin.right;
 height = 700 - this.margin.top - this.margin.bottom;
 svg: any;
 xScale: any;
 yScale: any;
 line: any;
 toolTipDiv: any;
ngOnInit() {

// XAXIS
this.xScale = d3.scaleBand()
  .domain(this.dataset[0].fluencyData.map((data) => {
    return new Date(data.date);
  }))
  .range([0, this.width]);

// YAXIS
this.yScale = d3.scaleLinear()
  .domain([0, 110])
  .range([this.height, 0]);

// Line Generator
this.line = d3.line()
  .x((d) => this.xScale(new Date(d.date)))
  .y((d) => this.yScale(d.wcpm));
// .curve(d3.curveMonotoneX);

// Add SVG to Div
this.svg = d3.select('#displayChart').append('svg')
  .attr('width', this.width + this.margin.left + this.margin.right)
  .attr('height', this.height + this.margin.top + this.margin.bottom)
  .append('g')
  .attr('transform', 'translate(' + this.margin.left + ',' + this.margin.top + ')');

// Define the div for the tooltip
this.toolTipDiv = d3.select('#displayChart').append('div')
  .attr('class', 'tooltip')
  .style('opacity', 0);

// Append XAXIS to the SVG
this.svg.append('g')
  .attr('class', 'xAxis')
  .attr('transform', 'translate(0,' + this.height + ')')
  .call(d3.axisBottom(this.xScale).tickSizeOuter(0).tickFormat(d3.timeFormat('%b %d')));

// Append YAXIS to SVG
this.svg.append('g')
  .attr('class', 'yAxis')
  .call(d3.axisLeft(this.yScale).tickSize(-this.width)
  );

// Make a Path for Dataset
this.svg.append('path')
  .datum(this.dataset[0].fluencyData)
  .attr('class', 'line')
  .attr('d', this.line);

// Text Heading of DATE in chart
this.svg.append('text')
  .attr('transform', 'translate(' + (-20) + ',' + (this.height + 13) + ')')
  .attr('dy', '.35em')
  .attr('class', ' xAxis')
  .text('Date');

// Append Circles in chart with different Colors
this.appendCircles();
}

appendCircles() {
  this.svg.selectAll('.developing')
  .data(this.dataset[0].fluencyData)
  .enter().append('circle')
  .attr('class', (d) => d.type)
  .attr('cx', (d) => this.xScale(new Date(d.date)))
  .attr('cy', (d) => this.yScale(d.wcpm))
  .attr('r', 5)
  .on('mouseover', (d) => {
    this.toolTipDiv.transition()
      .duration(200)
      .style('opacity', .9);
    this.toolTipDiv.html(d.wcpm + '<br/>' + d.type + '<br/>' + d.date)
      .style('left', (d3.event.pageX - 50) + 'px')
      .style('top', (d3.event.pageY - 50) + 'px');
  })
  .on('mouseout', () => {
    this.toolTipDiv.transition()
      .duration(500)
      .style('opacity', 0);
  });
}
}

2 个答案:

答案 0 :(得分:1)

带状标尺预期每个数据项都用具有一定宽度的东西表示,例如条形图中的条形图。该元素的缩放空间(带)的宽度从xBandScale(value)xBandScale(value) + xBandScale.bandwidth()。这很方便,因为它可以将矩形的x值设置为xBandScale(value),而宽度则设置为xBandScale.bandwidth()

但是,如果要定位圆,则希望它们位于此空间的中心。您正在使用xScale(value)来定位点,.attr("cx", function(d) { return xScale(d.someProperty) + xScale.bandwidth()/2 }) 是波段的左侧:

enter image description here

轴刻度线是偏移的,因为它们可以预测波段的宽度,毕竟我们将波段比例传递给了轴生成器。

是的,您可以使用以下方式定位圈子:

d3.scalePoint

这会将圆放置在带的中间-使圆与轴刻度对齐。但是,您的线不会从垂直轴开始,即使能奏效,这实际上也不是带刻度的预期目的。

相反,我们可以尝试xScale.step()-这也是一个序数标尺,类似于乐队标尺。文档指出:“点标度通常用于按序或分类维的散点图。”当您有没有宽度的对象(或更准确地说,位于带的中间)时,它们是理想的选择。

有了这个,我们得到了一个看起来像的图形(使用与上面相同的数据和结构):

enter image description here

请注意,点之间的间距为<?php // Check if the form was submitted if($_SERVER["REQUEST_METHOD"] == "POST") { // Check if file was uploaded without errors if(isset($_FILES["file"]) && $_FILES["file"]["error"] == 0){ $allowed = array("pdf" => "application/pdf", "xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "xls" => "application/vnd.ms-excel", "docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document"); $name = $_FILES["file"]["name"]; $type = $_FILES["file"]["type"]; $size = $_FILES["file"]["size"]; // Verify file extension $ext = pathinfo($name, PATHINFO_EXTENSION); if(!array_key_exists($ext, $allowed)) die("Error: Please select a valid file format."); // Verify file size - 50MB maximum $maxsize = 50 * 1024 * 1024; if($size > $maxsize) die("Error: File size is larger than the allowed limit."); // Verify MYME type of the file if(in_array($type, $allowed)){ // Check whether file exists before uploading it if(file_exists("upload/" . $name)){ echo $name . " is already exists."; } else{ move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $name); echo "Your file was uploaded successfully."; } } else{ echo "Error: There was a problem uploading your file. Please try again."; } } else{ echo "Error: " . $_FILES["file"]["error"]; } } ?> ,轴刻度已经移动(此外,最后一步超出了轴线-仅用于说明,轴在d处结束)。

最后,如果我们有一个表示时间或其他连续量的坐标轴,则可以使用d3中的任何连续刻度,而不必使用序数刻度,这通常是更好的选择。

为简单起见,我假设没有填充以使图像更易于阅读

答案 1 :(得分:0)

SVG中的左边距为50,但是xScale范围从0开始。这就是为什么所有内容都向左移动的原因。您的xScale范围应从边缘开始,到svg宽度结束。

this.xScale = d3.scaleBand()
  .domain(this.dataset[0].fluencyData.map((data) => {
    return new Date(data.date);
  }))
  .range([this.margin.left, this.width]);