Accepted answer

Actually @rioV8 is right, you need to create each line by accessing the datapoint by key, and the keys need to be strings in this case.

Here is a running example with the following main changes:

  1. Changed the datapoints for more effect
  2. Renamed values to the more expressive name topics
  3. Added a margin to the chart
  4. Corrected date matching pattern
  5. The axes need only be drawn once, the max y value is calculated by checking both topics. If you have more topics the logic needs little tweaking.
  6. During the actual rendering of the lines per topic the data needs to be scaled to the coordinate system.

File index.html

<!doctype html>
      <title>nested bars</title>
      <meta charset="utf-8">
          svg.graphchart {
              border: 1px solid gray;
              background-color: lightyellow;
          svg.graphchart text {
              font-style: normal;
              font-weight: normal;
              font-family: monospace;
              font-size: 10px;
              stroke: none;
        <svg class="graphchart" width="600" height="300"></svg>
    <script src="node_modules/d3/dist/d3.js"></script>
    <script src="./graphchart.js"></script>

File graphchart.js

/** Variables **/

// changed data for more effect
var data = [
       "date": "23-10-2018 13:14:55",
       "temperature": 8,
       "humidity": 14
   }, {
        "date": "23-10-2018 13:15:25",
        "temperature": 29,
        "humidity": 2
    }, {
        "date": "23-10-2018 13:16:55",
        "temperature": 10,
        "humidity": 20

// which topics do we want to see
var topics = ['temperature', 'humidity'];

// svg specifics
var svg ='svg.graphchart');

// little margin
var margin = 40;
var width = svg.attr('width') - 2 * margin;
var height = svg.attr('height') - 2 * margin;

// the chart group
var chart = svg.append('g')
    .attr('transform', `translate(${margin}, ${margin})`);

// some colors for the lines
var colors = d3.schemeAccent;

/** Helpers **/

// needed to adjust date pattern
var parseDate = d3.timeParse("%d-%m-%Y %H:%M:%S");

/** Axes: need only be drawn once **/

// x axis
var xScale = d3.scaleTime()
    .domain(d3.extent(data, function(d){
        var date = parseDate(;
        return date;
    .range([0, width]);
var xAxis = d3.axisBottom(xScale)
    .attr('stroke', 'gray')
    .attr('stroke-width', 1)
    .attr('transform', `translate(0,${height})`)

// y axis
var yScale = d3.scaleLinear()
    .domain([ 0, d3.max(data, function(d){
        return Math.max(d.temperature, d.humidity);
    .range([height, 0]);
var yAxis = d3.axisLeft(yScale)
    .attr('stroke', 'gray')
    .attr('stroke-width', 1)

/** render lines **/

// render one line
function renderLine(topic, color) {
    var line = d3.line()
        .x(function(d) { return xScale(parseDate(; })
        .y(function(d) { return yScale(d[topic]); });
        .attr('stroke', color)
        .attr('fill', 'none')
        .attr('stroke-width', 2)
        .attr('d', line);
// render each line
topics.forEach(function(topic, i) {
    renderLine(topic, colors[i % colors.length]);

Anyway this is only one way to handle the task. The recommended way to getting acquainted with d3 is to check out the sound documentation and many examples at and play with it.


Use object indexing by string

var values = ["temperature","humidity"];

var y = d3.scaleLinear()
          .domain([0,d3.max(data, d => d[value] )])
var line = d3.line()
             .x(d => x(parseDate( )
             .y(d => y(d[value]) );

Related Query

More Query from same tag