Denis L.
Denis L.

Reputation: 424

How to access the data in an array

How I can access to data in multi-dimensional array in d3.js?

I have created this sparkline using one dimensional array. But what about when I want to create more sparklines using multi-dimensional array.

I have this effect

    var canvasWidth  = 200,
    canvasHeight = 150;

var pathData = [
  { "x": 0,   "y": 50}, 
  { "x": 20,  "y": 20},
  { "x": 60,  "y": 40}, 
  { "x": 80,  "y": 30}, 
  { "x": 120, "y": 90},
  { "x": 150, "y": 70}, 
  { "x": 180, "y": 30},
  { "x": 190, "y": 90},
];

var widthScale = d3.scaleLinear()
  .domain([0, 190])
  .range([0, canvasWidth - 30]);

var heightScale = d3.scaleLinear()
  .domain([0, 90])
  .range([0, canvasHeight - 10]);

// Canvas
var canvas = d3.select("body")
  .append("svg")
  .attr("width", canvasWidth)
  .attr("height", canvasHeight)
    .append("g")
    .attr("transform","translate(20)");

// _+_+_+_+_+_+_+_+ Basic of Data --> SVG Path _+_+_+_+_+_+_+_+ //

// Create accessor function
var pathFunction = d3.line()
  .x(function(d) { return widthScale(d.x); })
  .y(function(d) { return heightScale(d.y); })
  .curve(d3.curveCatmullRom);

// Create <path> and append accessor function
var path = canvas.append("path")
  .attr("d", pathFunction(pathData))
  .attr("stroke", "red")
  .attr("stroke-width", 2)
  .attr("fill", "none");

// Add data points 
var circles = canvas.selectAll("circle")
  .data(pathData)
  .enter()
  .append("circle")
    .attr("cx", function(d) { return widthScale(d.x) })
    .attr("cy", function(d) { return heightScale(d.y) })
    .attr("fill", "black")
    .attr("r", 4);

This where I'm stuck because I cant add circles to each sparkline - `

var canvasWidth  = 200,
    canvasHeight = 150;

    var pathData = [
        [
            { "x": 0,   "y": 50}, { "x": 20,  "y": 20}, 
            { "x": 60,  "y": 40}, { "x": 80,  "y": 30},
            { "x": 120, "y": 90}, { "x": 150, "y": 70}, 
            { "x": 180, "y": 30}, { "x": 190, "y": 90},
        ],
        [    
            { "x": 0,   "y": 90}, { "x": 20,  "y": 20}, 
            { "x": 30,  "y": 80}, { "x": 80,  "y": 30},
            { "x": 120, "y": 90}, { "x": 150, "y": 70}, 
            { "x": 180, "y": 30}, { "x": 190, "y": 90},
        ],
        [    
            { "x": 0,   "y": 40}, { "x": 20,  "y": 20}, 
            { "x": 30,  "y": 80}, { "x": 80,  "y": 30},
            { "x": 120, "y": 90}, { "x": 150, "y": 70}, 
            { "x": 180, "y": 30}, { "x": 190, "y": 90},
        ]
    ];

    var widthScale = d3.scaleLinear()
      .domain([0, 190])
      .range([0, canvasWidth - 30]);

    var heightScale = d3.scaleLinear()
      .domain([0, 90])
      .range([0, canvasHeight - 10]);

    // Canvas
    var container = d3.select(".main-container")


    // Create accessor function
    var pathFunction = d3.line()
      .x(function(d) { return widthScale(d.x); })
      .y(function(d) { return heightScale(d.y); })
      .curve(d3.curveCatmullRom);


    var canvas = container.selectAll("svg")
        .data(pathData)
        .enter()
            .append("svg")
            .attr("width", canvasWidth)
            .attr("height", canvasHeight)
            .append("g")
            .attr("transform","translate(20)");

    var sparklines = canvas.append("path")
        .attr("d", pathFunction)
        .attr("stroke", "#19ff9f")
        .attr("stroke-width", 2)
        .attr("fill","none");


    var circles = canvas.selectAll("circle")
        .data(pathData)
        .enter()        
            .append("circle")
            .attr("cx", function(d,i) { return widthScale(d.x); })
            .attr("cy", function(d,i) { return widthScale(d.y); })
            .attr("fill", "black")
            .attr("r", 3);

`

CX and CY position are NaN. And also there are just 3 circles, not 8 as array length (http://prntscr.com/edp7hq)

Upvotes: 0

Views: 161

Answers (2)

Gerardo Furtado
Gerardo Furtado

Reputation: 102219

You need just one modification:

Since you have 3 inner arrays, each SVG has one of such arrays bound as data. So, when it comes to append the circles, instead of...

var circles = canvas.selectAll("circle")
    .data(pathData)
    .enter()        
    .append("circle")

..., which points to the whole data array, it should be...

var circles = canvas.selectAll("circle")
    .data(d => d)
    .enter()        
    .append("circle")

... which makes the inner arrays (that is, the data bound to each SVG) as the data array for each group of circles.

Here is your working code with that modification only (also, you had a typo on heightScale):

var canvasWidth  = 200,
    canvasHeight = 150;

    var pathData = [
        [
            { "x": 0,   "y": 50}, { "x": 20,  "y": 20}, 
            { "x": 60,  "y": 40}, { "x": 80,  "y": 30},
            { "x": 120, "y": 90}, { "x": 150, "y": 70}, 
            { "x": 180, "y": 30}, { "x": 190, "y": 90},
        ],
        [    
            { "x": 0,   "y": 90}, { "x": 20,  "y": 20}, 
            { "x": 30,  "y": 80}, { "x": 80,  "y": 30},
            { "x": 120, "y": 90}, { "x": 150, "y": 70}, 
            { "x": 180, "y": 30}, { "x": 190, "y": 90},
        ],
        [    
            { "x": 0,   "y": 40}, { "x": 20,  "y": 20}, 
            { "x": 30,  "y": 80}, { "x": 80,  "y": 30},
            { "x": 120, "y": 90}, { "x": 150, "y": 70}, 
            { "x": 180, "y": 30}, { "x": 190, "y": 90},
        ]
    ];

    var widthScale = d3.scaleLinear()
      .domain([0, 190])
      .range([0, canvasWidth - 30]);

    var heightScale = d3.scaleLinear()
      .domain([0, 90])
      .range([0, canvasHeight - 10]);

    // Canvas
    var container = d3.select("body")


    // Create accessor function
    var pathFunction = d3.line()
      .x(function(d) { return widthScale(d.x); })
      .y(function(d) { return heightScale(d.y); })
      .curve(d3.curveCatmullRom);


    var canvas = container.selectAll("svg")
        .data(pathData)
        .enter()
            .append("svg")
            .attr("width", canvasWidth)
            .attr("height", canvasHeight)
            .append("g")
            .attr("transform","translate(20)");

    var sparklines = canvas.append("path")
        .attr("d", pathFunction)
        .attr("stroke", "#19ff9f")
        .attr("stroke-width", 2)
        .attr("fill","none");


    var circles = canvas.selectAll("circle")
        .data(d=>d)
        .enter()        
            .append("circle")
            .attr("cx", function(d,i) { return widthScale(d.x); })
            .attr("cy", function(d,i) { return heightScale(d.y); })
            .attr("fill", "black")
            .attr("r", 3);
<script src="https://d3js.org/d3.v4.min.js"></script>

Upvotes: 1

GMeister
GMeister

Reputation: 341

One useful way I've found to inspect a problem like this is to log your "d" value to the console:

.attr("cx", function(d,i) { console.log(d); return widthScale(d.x) })

That will probably highlight that, because you are now using a multidimensional array, the data bound to your circle elements doesn't provide you with immediate access to the data points anymore. Something like the following will probably work:

.attr("cx", function(d,i) { return widthScale(d[i].x) })

Upvotes: 0

Related Questions