Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make a scatterplot based upon certain criteria using d3.js

For learning how to use d3.js, I was trying to use titanic dataset for learning available on kaggle.

I am trying to achieve the objective:

  1. Make a scatterplot of age vs fare with age in x axis and fare in y axis

  2. Use the sex column to have male as square and female as circles in the scatterplot

  3. Have opacity to indicate the condition - survived or not survived.

I have used the following code:

// set the dimensions and margins of the graph
var margin = {
    top: 10,
    right: 30,
    bottom: 30,
    left: 60
  },
  width = 460 - margin.left - margin.right,
  height = 400 - margin.top - margin.bottom;

// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
  .append("svg")
  .attr("width", width + margin.left + margin.right)
  .attr("height", height + margin.top + margin.bottom)
  .append("g")
  .attr("transform",
    "translate(" + margin.left + "," + margin.top + ")");

//Read the data
d3.csv("https://gist.githubusercontent.com/michhar/2dfd2de0d4f8727f873422c5d959fff5/raw/fa71405126017e6a37bea592440b4bee94bf7b9e/titanic.csv", function(data) {

  // Add X axis
  var x = d3.scaleLinear()
    .domain([0, 80])
    .range([0, width]);
  svg.append("g")
    .attr("transform", "translate(0," + height + ")")
    .call(d3.axisBottom(x));

  // Add Y axis
  var y = d3.scaleLinear()
    .domain([0, 600])
    .range([height, 0]);
  svg.append("g")
    .call(d3.axisLeft(y));

  // Add dots
  svg.append('g')
    .selectAll("dot")
    .data(data)
    .enter()
    .append("circle")
    .attr("cx", function(d) {
      return x(d.age);
    })
    .attr("cy", function(d) {
      return y(d.fare);
    })
    .attr("r", 1.5)
    .style("fill", "#69b3a2")

})
<script src="https://d3js.org/d3.v4.js"></script>

<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>

The condition I want to implement is:

if(d.sex == "female"){
    return d3.symbolCircle;
} else if (d.sex == "male"){
    return d3.symbolSquare;
}

But, being absolute new to the syntax, I am not understanding how. Also, How to have two colors for the 3rd objective of indicating survivor vs dead.

Can anyone help me please. I really thank you in advance.

In case you do not have the dataset, it can also be found here.

like image 390
K C Avatar asked Jul 23 '26 13:07

K C


1 Answers

Firstly, you need to look at your data. Your properties are all uppercase, and reading a CSV file always means that you need to parse your rows: numbers and dates are still strings, you need to cast them as such:

// set the dimensions and margins of the graph
var margin = {
    top: 10,
    right: 30,
    bottom: 30,
    left: 60
  },
  width = 460 - margin.left - margin.right,
  height = 400 - margin.top - margin.bottom;

// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
  .append("svg")
  .attr("width", width + margin.left + margin.right)
  .attr("height", height + margin.top + margin.bottom)
  .append("g")
  .attr("transform",
    "translate(" + margin.left + "," + margin.top + ")");

//Read the data
d3.csv("https://gist.githubusercontent.com/michhar/2dfd2de0d4f8727f873422c5d959fff5/raw/fa71405126017e6a37bea592440b4bee94bf7b9e/titanic.csv", function(rawData) {
  // All values are strings here, so we need to parse some of them.
  // You can do that using `+x` or `Number(x)`, where `x = "123"`
  const data = rawData.map(function(d) {
    return {
      age: Number(d.Age),
      // cabin: d.Cabin,
      // embarked: e.Embarked,
      fare: Number(d.Fare),
      // name: d.Name,
      // parch: Number(d.Parch),
      // passengerId: Number(d.PassengerId)
      // pclass: Number(Pclass),
      sex: d.Sex,
      // sibSp: Number(d.SibSp),
      survived: d.Survived === "1"
      // ticket: d.Ticket,
    };
  });

  // Add X axis
  var x = d3.scaleLinear()
    .domain([0, 80])
    .range([0, width]);
  svg.append("g")
    .attr("transform", "translate(0," + height + ")")
    .call(d3.axisBottom(x));

  // Add Y axis
  var y = d3.scaleLinear()
    .domain([0, 600])
    .range([height, 0]);
  svg.append("g")
    .call(d3.axisLeft(y));

  // Add dots
  svg.append('g')
    .selectAll("dot")
    .data(data)
    .enter()
    .append("circle")
    .attr("cx", function(d) {
      return x(d.age);
    })
    .attr("cy", function(d) {
      return y(d.fare);
    })
    .attr("r", 1.5)
    .style("fill", "#69b3a2")

})
<script src="https://d3js.org/d3.v4.js"></script>

<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>

Secondly, circles can only be circles. To draw both squares and circles, you'll need to use <path>. Your d3.symbol* were correct, but you need to access their .draw() function. d3.path is a generator to easily draw the d attribute of a path:

// set the dimensions and margins of the graph
var margin = {
    top: 10,
    right: 30,
    bottom: 30,
    left: 60
  },
  width = 460 - margin.left - margin.right,
  height = 400 - margin.top - margin.bottom;

// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
  .append("svg")
  .attr("width", width + margin.left + margin.right)
  .attr("height", height + margin.top + margin.bottom)
  .append("g")
  .attr("transform",
    "translate(" + margin.left + "," + margin.top + ")");

//Read the data
d3.csv("https://gist.githubusercontent.com/michhar/2dfd2de0d4f8727f873422c5d959fff5/raw/fa71405126017e6a37bea592440b4bee94bf7b9e/titanic.csv", function(rawData) {
  // All values are strings here, so we need to parse some of them.
  // You can do that using `+x` or `Number(x)`, where `x = "123"`
  const data = rawData.map(function(d) {
    return {
      age: Number(d.Age),
      // cabin: d.Cabin,
      // embarked: e.Embarked,
      fare: Number(d.Fare),
      // name: d.Name,
      // parch: Number(d.Parch),
      // passengerId: Number(d.PassengerId)
      // pclass: Number(Pclass),
      sex: d.Sex,
      // sibSp: Number(d.SibSp),
      survived: d.Survived === "1"
      // ticket: d.Ticket,
    };
  });

  // Add X axis
  var x = d3.scaleLinear()
    .domain([0, 80])
    .range([0, width]);
  svg.append("g")
    .attr("transform", "translate(0," + height + ")")
    .call(d3.axisBottom(x));

  // Add Y axis
  var y = d3.scaleLinear()
    .domain([0, 600])
    .range([height, 0]);
  svg.append("g")
    .call(d3.axisLeft(y));

  // Add dots
  svg.append('g')
    .selectAll("path")
    .data(data)
    .enter()
    .append("path")
    .attr("transform", function(d) {
      return "translate(" + [x(d.age), y(d.fare)] + ")";
    })
    .attr("d", function(d) {
      const path = d3.path();
      const shape = d.sex == "female" ? d3.symbolCircle : d3.symbolSquare;
      shape.draw(path, 8);
      return path.toString();
    })
    .style("fill", "#69b3a2")

})
<script src="https://d3js.org/d3.v4.js"></script>

<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>

(As an aside, you also could have drawn rects for both, but given the female ones rounded corners with the rx attribute).

Finally, you can use a colour scale for fill, with d3.scaleOrdinal, but if you have only two colours and don't use it to colour multiple things (like a line chart and a legend), just use an if statement:

// set the dimensions and margins of the graph
var margin = {
    top: 10,
    right: 30,
    bottom: 30,
    left: 60
  },
  width = 460 - margin.left - margin.right,
  height = 400 - margin.top - margin.bottom;

// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
  .append("svg")
  .attr("width", width + margin.left + margin.right)
  .attr("height", height + margin.top + margin.bottom)
  .append("g")
  .attr("transform",
    "translate(" + margin.left + "," + margin.top + ")");

//Read the data
d3.csv("https://gist.githubusercontent.com/michhar/2dfd2de0d4f8727f873422c5d959fff5/raw/fa71405126017e6a37bea592440b4bee94bf7b9e/titanic.csv", function(rawData) {
  // All values are strings here, so we need to parse some of them.
  // You can do that using `+x` or `Number(x)`, where `x = "123"`
  const data = rawData.map(function(d) {
    return {
      age: Number(d.Age),
      // cabin: d.Cabin,
      // embarked: e.Embarked,
      fare: Number(d.Fare),
      // name: d.Name,
      // parch: Number(d.Parch),
      // passengerId: Number(d.PassengerId)
      // pclass: Number(Pclass),
      sex: d.Sex,
      // sibSp: Number(d.SibSp),
      survived: d.Survived === "1"
      // ticket: d.Ticket,
    };
  });

  // Add X axis
  var x = d3.scaleLinear()
    .domain([0, 80])
    .range([0, width]);
  svg.append("g")
    .attr("transform", "translate(0," + height + ")")
    .call(d3.axisBottom(x));

  // Add Y axis
  var y = d3.scaleLinear()
    .domain([0, 600])
    .range([height, 0]);
  svg.append("g")
    .call(d3.axisLeft(y));

  // Add dots
  svg.append('g')
    .selectAll("path")
    .data(data)
    .enter()
    .append("path")
    .attr("transform", function(d) {
      return "translate(" + [x(d.age), y(d.fare)] + ")";
    })
    .attr("d", function(d) {
      const path = d3.path();
      const shape = d.sex == "female" ? d3.symbolCircle : d3.symbolSquare;
      shape.draw(path, 8);
      return path.toString();
    })
    .style("fill", function(d) {
      return d.survived ? "#69b3a2" : "#ddd";
    })

})
<script src="https://d3js.org/d3.v4.js"></script>

<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
like image 65
Ruben Helsloot Avatar answered Jul 26 '26 08:07

Ruben Helsloot



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!