D3.js折线图带有负值

时间:2018-09-19 07:36:39

标签: javascript d3.js

制作d3.js折线图。工作示例:http://jsfiddle.net/13y8ea7n/

代码:

const width = 1140

var svgWidth = width-30, svgHeight = 300

var svg = d3.select('.svg')
            .attr("width", svgWidth)
            .attr("height", svgHeight)
          .append('g')
            .attr("width", svgWidth)
            .attr("height", svgHeight)

var x = d3.scaleTime()
          .range([0, svgWidth-57]);

var y = d3.scaleLinear()
          .range([svgHeight-50, 0]);

var valueline = d3.line()
    .x((d) => {return x(d.moment)})
    .y((d) => {return y(d.val_prc)})

var x_axis = d3.axisBottom(x)
                .ticks(0)

var y_axis = d3.axisRight(y)
                .tickSize(-width, 0)
                .tickFormat((d) => {
                  let label = d + '%'
                  if (d > 0) {
                    label = '+' + label
                  }
                  return label
                  })
                .tickPadding(9)
                .ticks(3)

var xAxisTranslate = svgHeight - 20;

var parseTime = d3.timeParse("%Y-%m-%d");


    dataset.forEach((d) => {
      d.moment = parseTime(d.moment);
      d.val_prc = +d.val_prc;
    });

    x.domain(d3.extent(dataset, function(d) { return d.moment; }));
    y.domain(d3.extent(dataset, function(d) { return d.val_prc; }));

    svg.append("g")
      .attr('class', 'y-axis')
      .attr("transform", `translate(${svgWidth-57}, 10)`)
      .call(y_axis)

    svg.append("g")
      .attr('class', 'x-axis')
      .attr("transform", `translate(0, ${xAxisTranslate})`)
      .call(x_axis)

    svg.append("path")
        .datum(dataset)
        .attr("class", "line")
        .attr("d", valueline);

面对两个问题。

  1. 尽管数据集中存在负值,但图表显示为高于0%的刻度。我是d3的新手,所以找不到问题,我建议是因为y.domain。
  2. 是否可以使用tickValues = [-50,0,50,100]根据y轴呈现图表?尝试过,但是从svg-container中渲染了-50刻度。

因为代码集太长,所以未在代码段中包含数据集。它包含在小提琴中。

2 个答案:

答案 0 :(得分:1)

1。。太多的幻数值转换了图形的不同部分。看看margin conventions上的这篇文章。

采用上述约定的目的是在按照这种方式进行设置后:

  

所有后续代码都可以忽略边距。


2。。您可以使用数组对tickValues进行硬编码,但是随后还必须对yDomain进行硬编码,以使其在视图中像y.domain([-50, 100])(相对使用d3.extent从数据值计算域。


const dataset = [{
    "moment": "2018-03-14",
    "val_prc": 0,
    "val_rub": 651573.83
  },
  {
    "moment": "2018-03-15",
    "val_prc": -0.18,
    "val_rub": 650378.16
  },
  {
    "moment": "2018-03-16",
    "val_prc": 0.93,
    "val_rub": 657633.22
  },
  {
    "moment": "2018-03-19",
    "val_prc": -0.24,
    "val_rub": 650012.09
  },
  {
    "moment": "2018-03-20",
    "val_prc": -0.91,
    "val_rub": 645619.39
  },
  {
    "moment": "2018-03-21",
    "val_prc": -0.59,
    "val_rub": 647702.98
  },
  {
    "moment": "2018-03-22",
    "val_prc": -0.39,
    "val_rub": 649028.2
  },
  {
    "moment": "2018-03-23",
    "val_prc": -0.66,
    "val_rub": 647251.33
  },
  {
    "moment": "2018-03-26",
    "val_prc": -1,
    "val_rub": 645037.53
  },
  {
    "moment": "2018-03-27",
    "val_prc": -1.74,
    "val_rub": 640242.97
  },
  {
    "moment": "2018-03-28",
    "val_prc": -0.97,
    "val_rub": 645237.98
  },
  {
    "moment": "2018-03-29",
    "val_prc": -0.7,
    "val_rub": 647028.82
  },
  {
    "moment": "2018-03-30",
    "val_prc": -0.44,
    "val_rub": 648697.05
  },
  {
    "moment": "2018-04-02",
    "val_prc": -0.96,
    "val_rub": 645328.79
  },
  {
    "moment": "2018-04-03",
    "val_prc": -1.61,
    "val_rub": 641075.02
  },
  {
    "moment": "2018-04-04",
    "val_prc": -2.65,
    "val_rub": 634322.06
  },
  {
    "moment": "2018-04-05",
    "val_prc": -3.01,
    "val_rub": 631949.94
  },
  {
    "moment": "2018-04-06",
    "val_prc": -1.71,
    "val_rub": 640405.6
  },
  {
    "moment": "2018-04-09",
    "val_prc": 21.22,
    "val_rub": 789860.31
  },
  {
    "moment": "2018-04-10",
    "val_prc": 37.84,
    "val_rub": 898161.44
  },
  {
    "moment": "2018-04-11",
    "val_prc": 45.28,
    "val_rub": 946624.12
  },
  {
    "moment": "2018-04-12",
    "val_prc": 35.01,
    "val_rub": 879713.53
  },
  {
    "moment": "2018-04-13",
    "val_prc": 35.2,
    "val_rub": 880939.55
  },
  {
    "moment": "2018-04-16",
    "val_prc": 35.39,
    "val_rub": 882187.37
  },
  {
    "moment": "2018-04-17",
    "val_prc": 32.97,
    "val_rub": 866413.03
  },
  {
    "moment": "2018-04-18",
    "val_prc": 32.68,
    "val_rub": 864526.16
  },
  {
    "moment": "2018-04-19",
    "val_prc": 32.62,
    "val_rub": 864112.82
  },
  {
    "moment": "2018-04-20",
    "val_prc": 32.13,
    "val_rub": 862427.04
  },
  {
    "moment": "2018-04-23",
    "val_prc": 32.34,
    "val_rub": 863806.29
  },
  {
    "moment": "2018-04-24",
    "val_prc": 30.87,
    "val_rub": 854187
  },
  {
    "moment": "2018-04-25",
    "val_prc": 31.72,
    "val_rub": 859709.46
  },
  {
    "moment": "2018-04-26",
    "val_prc": 32.54,
    "val_rub": 865102.62
  },
  {
    "moment": "2018-04-27",
    "val_prc": 31.89,
    "val_rub": 860868.98
  },
  {
    "moment": "2018-04-28",
    "val_prc": 31.78,
    "val_rub": 860107.7
  },
  {
    "moment": "2018-04-30",
    "val_prc": 30.45,
    "val_rub": 851444.35
  },
  {
    "moment": "2018-05-02",
    "val_prc": 37.21,
    "val_rub": 895592.11
  },
  {
    "moment": "2018-05-03",
    "val_prc": 33.04,
    "val_rub": 868336.14
  },
  {
    "moment": "2018-05-04",
    "val_prc": 33.58,
    "val_rub": 871888.06
  },
  {
    "moment": "2018-05-07",
    "val_prc": 33.31,
    "val_rub": 870101.52
  },
  {
    "moment": "2018-05-08",
    "val_prc": 33.43,
    "val_rub": 870868.5
  },
  {
    "moment": "2018-05-10",
    "val_prc": 33.86,
    "val_rub": 873673.59
  },
  {
    "moment": "2018-05-11",
    "val_prc": 33.96,
    "val_rub": 874332.19
  },
  {
    "moment": "2018-05-14",
    "val_prc": 33.66,
    "val_rub": 872423.33
  },
  {
    "moment": "2018-05-15",
    "val_prc": 35.21,
    "val_rub": 882485
  },
  {
    "moment": "2018-05-16",
    "val_prc": 34.82,
    "val_rub": 879932.88
  },
  {
    "moment": "2018-05-17",
    "val_prc": 34.67,
    "val_rub": 878996.99
  },
  {
    "moment": "2018-05-18",
    "val_prc": 34.44,
    "val_rub": 877477.19
  },
  {
    "moment": "2018-05-21",
    "val_prc": 34.37,
    "val_rub": 877036.83
  },
  {
    "moment": "2018-05-22",
    "val_prc": 34.89,
    "val_rub": 880399.25
  },
  {
    "moment": "2018-05-23",
    "val_prc": 34.23,
    "val_rub": 876134.51
  },
  {
    "moment": "2018-05-24",
    "val_prc": 33.73,
    "val_rub": 872870.04
  },
  {
    "moment": "2018-05-25",
    "val_prc": 34.89,
    "val_rub": 880450.96
  },
  {
    "moment": "2018-05-28",
    "val_prc": 35.34,
    "val_rub": 883328.84
  },
  {
    "moment": "2018-05-29",
    "val_prc": 34,
    "val_rub": 874593.61
  },
  {
    "moment": "2018-05-30",
    "val_prc": 33.72,
    "val_rub": 872813.35
  },
  {
    "moment": "2018-05-31",
    "val_prc": 33.51,
    "val_rub": 876391.77
  },
  {
    "moment": "2018-06-01",
    "val_prc": 32.8,
    "val_rub": 871773.21
  },
  {
    "moment": "2018-06-04",
    "val_prc": 32.36,
    "val_rub": 868882.57
  },
  {
    "moment": "2018-06-05",
    "val_prc": 31.86,
    "val_rub": 865603.14
  },
  {
    "moment": "2018-06-06",
    "val_prc": 31.38,
    "val_rub": 862410.15
  },
  {
    "moment": "2018-06-07",
    "val_prc": 31.01,
    "val_rub": 860001.79
  },
  {
    "moment": "2018-06-08",
    "val_prc": 32.1,
    "val_rub": 867119.14
  },
  {
    "moment": "2018-06-09",
    "val_prc": 32.11,
    "val_rub": 867210.65
  },
  {
    "moment": "2018-06-11",
    "val_prc": 29.44,
    "val_rub": 849674.04
  },
  {
    "moment": "2018-06-13",
    "val_prc": 28.87,
    "val_rub": 845932.98
  },
  {
    "moment": "2018-06-14",
    "val_prc": 29.74,
    "val_rub": 851677.78
  },
  {
    "moment": "2018-06-15",
    "val_prc": 31.87,
    "val_rub": 865629.03
  },
  {
    "moment": "2018-06-18",
    "val_prc": 33.21,
    "val_rub": 874410.67
  },
  {
    "moment": "2018-06-19",
    "val_prc": 33.64,
    "val_rub": 877287.69
  },
  {
    "moment": "2018-06-20",
    "val_prc": 32.91,
    "val_rub": 872466.43
  },
  {
    "moment": "2018-06-21",
    "val_prc": 32.85,
    "val_rub": 872068.35
  },
  {
    "moment": "2018-06-22",
    "val_prc": 33.4,
    "val_rub": 875676.13
  },
  {
    "moment": "2018-06-25",
    "val_prc": 32.31,
    "val_rub": 868547.41
  },
  {
    "moment": "2018-06-26",
    "val_prc": 32.22,
    "val_rub": 867963.93
  },
  {
    "moment": "2018-06-27",
    "val_prc": 30.72,
    "val_rub": 858061.68
  },
  {
    "moment": "2018-06-28",
    "val_prc": 30.57,
    "val_rub": 857086.33
  },
  {
    "moment": "2018-06-29",
    "val_prc": 30.22,
    "val_rub": 854793.98
  },
  {
    "moment": "2018-07-02",
    "val_prc": 31.58,
    "val_rub": 863757.63
  },
  {
    "moment": "2018-07-03",
    "val_prc": 30.17,
    "val_rub": 854498.09
  },
  {
    "moment": "2018-07-04",
    "val_prc": 29.8,
    "val_rub": 852030.65
  },
  {
    "moment": "2018-07-05",
    "val_prc": 31.94,
    "val_rub": 866084.21
  },
  {
    "moment": "2018-07-06",
    "val_prc": 30.15,
    "val_rub": 854347.97
  },
  {
    "moment": "2018-07-09",
    "val_prc": 32.03,
    "val_rub": 866658.09
  },
  {
    "moment": "2018-07-10",
    "val_prc": 35.24,
    "val_rub": 887733.54
  },
  {
    "moment": "2018-07-11",
    "val_prc": 34.8,
    "val_rub": 884858.56
  },
  {
    "moment": "2018-07-12",
    "val_prc": 32.98,
    "val_rub": 906062.03
  },
  {
    "moment": "2018-07-13",
    "val_prc": 33.34,
    "val_rub": 908492.48
  },
  {
    "moment": "2018-07-16",
    "val_prc": 29.89,
    "val_rub": 885030.28
  },
  {
    "moment": "2018-07-17",
    "val_prc": 30.47,
    "val_rub": 888979.1
  },
  {
    "moment": "2018-07-18",
    "val_prc": 33.17,
    "val_rub": 907381.08
  },
  {
    "moment": "2018-07-19",
    "val_prc": 35.41,
    "val_rub": 922629.27
  },
  {
    "moment": "2018-07-20",
    "val_prc": 32.8,
    "val_rub": 904840.69
  },
  {
    "moment": "2018-07-23",
    "val_prc": 30.98,
    "val_rub": 892420.38
  },
  {
    "moment": "2018-07-24",
    "val_prc": 32.05,
    "val_rub": 899748.46
  },
  {
    "moment": "2018-07-25",
    "val_prc": 30.42,
    "val_rub": 888651.05
  },
  {
    "moment": "2018-07-26",
    "val_prc": 28.85,
    "val_rub": 877920.79
  },
  {
    "moment": "2018-07-27",
    "val_prc": 27.8,
    "val_rub": 870776.46
  },
  {
    "moment": "2018-07-30",
    "val_prc": 28.52,
    "val_rub": 875688.2
  },
  {
    "moment": "2018-07-31",
    "val_prc": 33.52,
    "val_rub": 909739.19
  },
  {
    "moment": "2018-08-01",
    "val_prc": 30.4,
    "val_rub": 888473.88
  },
  {
    "moment": "2018-08-02",
    "val_prc": 33.64,
    "val_rub": 910571.7
  },
  {
    "moment": "2018-08-03",
    "val_prc": 31.85,
    "val_rub": 898341.67
  },
  {
    "moment": "2018-08-06",
    "val_prc": 32.87,
    "val_rub": 905304.31
  },
  {
    "moment": "2018-08-07",
    "val_prc": 33.05,
    "val_rub": 906551.73
  },
  {
    "moment": "2018-08-08",
    "val_prc": 47.33,
    "val_rub": 1003854.58
  },
  {
    "moment": "2018-08-09",
    "val_prc": 62.09,
    "val_rub": 1104377.06
  },
  {
    "moment": "2018-08-10",
    "val_prc": 75.34,
    "val_rub": 1194698.92
  },
  {
    "moment": "2018-08-13",
    "val_prc": 76,
    "val_rub": 1349718.79
  },
  {
    "moment": "2018-08-14",
    "val_prc": 75.18,
    "val_rub": 1492738.39
  },
  {
    "moment": "2018-08-15",
    "val_prc": 76.98,
    "val_rub": 1659601.6
  },
  {
    "moment": "2018-08-16",
    "val_prc": 75.56,
    "val_rub": 1749486.9
  },
  {
    "moment": "2018-08-17",
    "val_prc": 75.99,
    "val_rub": 1753777.09
  },
  {
    "moment": "2018-08-20",
    "val_prc": 74.99,
    "val_rub": 1743844.78
  },
  {
    "moment": "2018-08-21",
    "val_prc": 72.08,
    "val_rub": 1714799.41
  },
  {
    "moment": "2018-08-22",
    "val_prc": 71.95,
    "val_rub": 1713480.52
  },
  {
    "moment": "2018-08-23",
    "val_prc": 70.39,
    "val_rub": 1697945.78
  },
  {
    "moment": "2018-08-24",
    "val_prc": 70.91,
    "val_rub": 1703157.92
  },
  {
    "moment": "2018-08-27",
    "val_prc": 70.9,
    "val_rub": 1703035.57
  },
  {
    "moment": "2018-08-28",
    "val_prc": 67.12,
    "val_rub": 1665359
  },
  {
    "moment": "2018-08-29",
    "val_prc": 69.21,
    "val_rub": 1686236.97
  },
  {
    "moment": "2018-08-30",
    "val_prc": 66.53,
    "val_rub": 1659517.35
  },
  {
    "moment": "2018-08-31",
    "val_prc": 64.7,
    "val_rub": 1641262.34
  },
  {
    "moment": "2018-09-03",
    "val_prc": 64.48,
    "val_rub": 1639032.05
  },
  {
    "moment": "2018-09-04",
    "val_prc": 63.87,
    "val_rub": 1633016.85
  },
  {
    "moment": "2018-09-05",
    "val_prc": 63.11,
    "val_rub": 1625390.21
  },
  {
    "moment": "2018-09-06",
    "val_prc": 69.13,
    "val_rub": 1685415.5
  },
  {
    "moment": "2018-09-07",
    "val_prc": 66.37,
    "val_rub": 1657876.09
  },
  {
    "moment": "2018-09-10",
    "val_prc": 70.6,
    "val_rub": 1700074.16
  },
  {
    "moment": "2018-09-11",
    "val_prc": 67.14,
    "val_rub": 1665624.56
  },
  {
    "moment": "2018-09-12",
    "val_prc": 72.01,
    "val_rub": 1714120.37
  },
  {
    "moment": "2018-09-13",
    "val_prc": 72.1,
    "val_rub": 1715038.65
  },
  {
    "moment": "2018-09-14",
    "val_prc": 72.11,
    "val_rub": 1715078.29
  },
  {
    "moment": "2018-09-17",
    "val_prc": 71.62,
    "val_rub": 1710266.45
  }
]

const width = 1140
const height = 500
const margin = {
  top: 30,
  right: 50,
  bottom: 20,
  left: 10
}

const svgWidth = width - margin.left - margin.right
const svgHeight = height - margin.top - margin.bottom

const svg = d3.select('.svg')
  .attr("width", width)
  .attr("height", height)
  .append('g')
  .attr('transform', `translate(${margin.left}, ${margin.top})`)


const x = d3.scaleTime()
  .range([0, svgWidth]);

const y = d3.scaleLinear()
  .range([svgHeight, 0]);

const valueline = d3.line()
  .x((d) => {
    return x(d.moment)
  })
  .y((d) => {
    return y(d.val_prc)
  })

const x_axis = d3.axisBottom(x)
  .ticks(0)

const y_axis = d3.axisRight(y)
  .tickSize(-svgWidth, 0)
  .tickFormat((d) => {
    let label = d + '%'
    if (d > 0) {
      label = '+' + label
    }
    return label
  })
  .tickPadding(9)
  .tickValues([-50, 0, 50, 100])

const xAxisTranslate = svgHeight - 20;

const parseTime = d3.timeParse("%Y-%m-%d");


dataset.forEach((d) => {
  d.moment = parseTime(d.moment);
  d.val_prc = +d.val_prc;
});

x.domain(d3.extent(dataset, function(d) {
  return d.moment;
}));
y.domain([-50, 100]);

svg.append("g")
  .attr('class', 'y-axis')
  .attr("transform", `translate(${svgWidth}, 0)`)
  .call(y_axis)

svg.append("g")
  .attr('class', 'x-axis')
  .attr("transform", `translate(0, ${xAxisTranslate})`)
  .call(x_axis)

svg.append("path")
  .datum(dataset)
  .attr("class", "line")
  .attr("d", valueline);
text {
  fill: rgba(0, 0, 0, 0.47);
  font-size: 14px;
  line-height: 1;
  text-anchor: start;
}

.line {
  fill: none;
  stroke: #c8102e;
  stroke-width: 1px;
}

.y-axis path {
  display: none;
}

.y-axis .tick line {
  stroke: #c1c1c1;
  stroke-width: 1px;
}


}
.x-axis .domain {
  stroke: #c1c1c1;
  stroke-width: 1px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>

<body>
  <svg class="svg"></svg>
</body>

</html>

Fiddle

答案 1 :(得分:0)

如果将x轴绘制在正确的位置(图表的边缘),则会看到图形触摸x轴。

var xAxisTranslate = svgHeight - 50;

如果您随后将y域调整为(仅用于测试)

y.domain([-5, 5]);

您会看到图形很好地位于0%线以下。

在完整图形中,-3%在0%线下方不可见。

如果只是将图表的高度增加到>=500,则会看到想要的结果。这可能是一个舍入问题。