Lakshay Khandelwal
Lakshay Khandelwal

Reputation: 81

How can I add markers in my d3 line chart having two datasets

Here is my JS code to make a line chart for two datasets and I am using d3 library and Vue framework.

The HTML code contains two buttons for showing two charts for two datasets. The buttons call updateData function to show the line chart of two datasets.

Can anyone tell me how to add dot markers at the coordinates of the chart.

var app = new Vue({
  el: "#app",
  data: () => {
    return {
      data1: [{
          ser1: 0.3,
          ser2: 4
        },
        {
          ser1: 2,
          ser2: 16
        },
        {
          ser1: 3,
          ser2: 8
        }
      ],
      data2: [{
          ser1: 1,
          ser2: 7
        },
        {
          ser1: 4,
          ser2: 1
        },
        {
          ser1: 6,
          ser2: 8
        }
      ],
      margin: {
        top: 10,
        right: 30,
        bottom: 30,
        left: 50
      },
      width: null,
      height: null
    }
  },
  mounted() {
    this.width = 460 - this.margin.left - this.margin.right;
    this.height = 400 - this.margin.top - this.margin.bottom;
    
    this.createSvg();
  },
  methods: {
    createSvg() {
      var svg = d3.select("#my_dataviz")
        .append("svg")
        .attr("width", this.width + this.margin.left + this.margin.right)
        .attr("height", this.height + this.margin.top + this.margin.bottom)
        .attr("fill", "blue")
        .append("g")
        .attr("transform",
          "translate(" + this.margin.left + "," + this.margin.top + ")");

      var x = d3.scaleLinear().range([0, this.width]);
      var xAxis = d3.axisBottom().scale(x);
      svg.append("g")
        .attr("transform", "translate(0," + this.height + ")")
        .attr("class", "myXaxis")

      var y = d3.scaleLinear().range([this.height, 0]);
      var yAxis = d3.axisLeft().scale(y);
      svg.append("g")
        .attr("class", "myYaxis");

      this.update(svg, x, y, xAxis, yAxis, this.data1)
    },
    updateData(data) {
      var svg = d3.select("#my_dataviz");

      var x = d3.scaleLinear().range([0, this.width]);
      var xAxis = d3.axisBottom().scale(x);

      var y = d3.scaleLinear().range([this.height, 0]);
      var yAxis = d3.axisLeft().scale(y);

      this.update(svg, x, y, xAxis, yAxis, data);
    },
    update(svg, x, y, xAxis, yAxis, data) {
      // Create the X axis:
      x.domain([0, d3.max(data, function(d) {
        return d.ser1
      })]);
      svg.selectAll(".myXaxis").transition()
        .duration(3000)
        .call(xAxis);

      // create the Y axis
      y.domain([0, d3.max(data, function(d) {
        return d.ser2
      })]);
      svg.selectAll(".myYaxis")
        .transition()
        .duration(3000)
        .call(yAxis);

      // Create a update selection: bind to the new data
      var u = svg.selectAll(".lineTest")
        .data([data], function(d) {
          return d.ser1
        });

      // Updata the line
      u
        .enter()
        .append("path")
        .attr("class", "lineTest")
        .merge(u)
        .transition()
        .duration(3000)
        .attr("d", d3.line()
          .x(function(d) {
            return x(d.ser1);
          })
          .y(function(d) {
            return y(d.ser2);
          }))
        .attr("fill", "none")
        .attr("stroke", "steelblue")
        .attr("stroke-width", 2.5)
    }
  }
});
<!DOCTYPE html>
<meta charset="utf-8">

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://d3js.org/d3.v4.js"></script>



<div id="app">
  <button @click="updateData(data1)">Dataset 1</button>
  <button @click="updateData(data2)">Dataset 2</button>

  <div id="my_dataviz"></div>
</div>
 

The above snippet is the HTML code including Vue and d3.js library.

Upvotes: 0

Views: 905

Answers (1)

Shoejep
Shoejep

Reputation: 4839

After learning from D3 myself, I took code from this example and this example and modified it so that it worked with Vue.

I've included a snippet below, you don't have to pass as many variables with this code and you can style the line and markers with css.

new Vue({
  el: "#app",
  data: () => {
    return {
      data1: [{
          ser1: 0.3,
          ser2: 4
        },
        {
          ser1: 2,
          ser2: 16
        },
        {
          ser1: 3,
          ser2: 8
        }
      ],
      data2: [{
          ser1: 1,
          ser2: 7
        },
        {
          ser1: 4,
          ser2: 1
        },
        {
          ser1: 6,
          ser2: 8
        }
      ],
      xAxis: null,
      yAxis: null,
      margin: {
        top: 50,
        right: 50,
        bottom: 50,
        left: 50
      }
    }
  },
  methods: {
    updateData(data) {

      var width = 460 - this.margin.left - this.margin.right;
      var height = 400 - this.margin.top - this.margin.bottom;


      var xScale = d3.scaleLinear()
        .domain([0, Math.max.apply(Math, data.map(x => x.ser1))])
        .range([0, width]);

      var yScale = d3.scaleLinear()
        .domain([0, Math.max.apply(Math, data.map(x => x.ser2))])
        .range([height, 0]);


      // Select the section we want to apply our changes to


      var line = d3.line()
        .x(function(d) {
          return xScale(d.ser1);
        }) // set the x values for the line generator
        .y(function(d) {
          return yScale(d.ser2);
        }) // set the y values for the line generator 

      let svg = d3.select("#graph").transition().duration(750);

      // Make the changes
      svg.select(".line") // change the line
        .duration(750)
        .attr("d", line(data));

      svg.select(".x.axis") // change the x axis
        .duration(750)
        .call(d3.axisBottom(xScale));

      svg.select(".y.axis") // change the y axis
        .duration(750)
        .call(d3.axisLeft(yScale));

      d3.select("svg").selectAll(".dot")
        .data(data)
        .transition()
        .duration(750)
        .attr("cx", function(d) {
          return xScale(d.ser1)
        })
        .attr("cy", function(d) {
          return yScale(d.ser2)
        })

    },
    createSvg(data) {
      var width = 460 - this.margin.left - this.margin.right;
      var height = 400 - this.margin.top - this.margin.bottom;

      var xScale = d3.scaleLinear()
        .domain([0, Math.max.apply(Math, data.map(x => x.ser1))])
        .range([0, width]);

      var yScale = d3.scaleLinear()
        .domain([0, Math.max.apply(Math, data.map(x => x.ser2))])
        .range([height, 0]);

      // 7. d3's line generator
      var line = d3.line()
        .x(function(d) {
          return xScale(d.ser1);
        }) // set the x values for the line generator
        .y(function(d) {
          return yScale(d.ser2);
        }) // set the y values for the line generator 

      // 1. Add the SVG to the page and employ #2
      var svg = d3.select("#graph").append("svg")
        .attr("width", width + this.margin.left + this.margin.right)
        .attr("height", height + this.margin.top + this.margin.bottom)
        .attr("fill", "blue")
        .append("g")
        .attr("transform", "translate(" + this.margin.left + "," + this.margin.top + ")");


      // 3. Call the x axis in a group tag
      this.xAxis = svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(d3.axisBottom(xScale)); // Create an axis component with d3.axisBottom

      this.yAxis = svg.append("g")
        .attr("class", "y axis")
        .call(d3.axisLeft(yScale));

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

      svg.selectAll(".dot")
        .data(data)
        .enter().append("circle")
        .attr("class", "dot")
        .attr("cx", function(d, i) {
          return xScale(d.ser1)
        })
        .attr("cy", function(d) {
          return yScale(d.ser2)
        })
        .attr("r", 5);
    }
  },
  mounted() {
    this.createSvg(this.data1);
  }
});
.line {
  fill: none;
  stroke: steelblue;
  stroke-width: 3;
}

.dot {
  fill: steelblue;
  stroke: #fff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>

<div id="app">
  <button type="button" @click="updateData(data1)">Data 1</button>
  <button type="button" @click="updateData(data2)">Data 2</button>
  <div id="graph"></div>
</div>

Upvotes: 1

Related Questions