basedian
basedian

Reputation: 317

D3.js csv Filter for Interactivity

I'm new to d3.js & html and I could not find an answer to my problem yet.

I have this Array I want to plot on a time graph. This is the CSV with marked countries i want to filter

This is an example of my plot right now

As you may see you can't recognize which circles belong to which country. I wanted to integrate some mousevents etc. to distinguish the circles.

  1. But I don't know how to filter the origin country from the .csv how can I do that?
  2. I want to get the entries from "Origin" so i can group the circles into the countries. Will this be the right way if I want to attribute opacity/color?)

body,
html {
  margin: 0;
  padding: 0;
  font-family: "Arial", sans-serif;
  font-size: 0.95em;
  text-align: center;
}
#chart {
  background-color: #F5F2EB;
  border: 1px solid #CCC;
}
.bar {
  fill: purple;
  shape-rendering: crispEdges;
}
.bar-label {
  fill: black;
  text-anchor: middle;
  font-size: 18px;
}
.axis path,
.axis line {
  fill: none;
  stroke: #000;
  shape-rendering: crispEdges;
}
.gridline path,
.gridline line {
  fill: none;
  stroke: #ccc;
  shape-rendering: crispEdges;
}

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Learning D3</title>
  <link rel="stylesheet" href="main.css">
  <script type="text/javascript" src="d3.min.js"></script>
</head>

<body>
  <!--Place all DOM elements here -->
  <script>
    d3.csv("refugee_data.csv", function(d) {

      return {
        date: d.Year + "/" + d.Month,
        origin: d.Origin,
        asylum: d.Asylum,
        value: +d.Value
      };
    }, function(error, rows) {
      console.log(rows);
      render(rows)
    });



    function render(data) {
      var w = 800;
      var h = 450;
      var margin = {
        top: 100,
        bottom: 0,
        left: 80,
        right: 40
      };
      var width = w - margin.left - margin.right;
      var height = h - margin.top - margin.bottom;

      var svg = d3.select("body").append("svg")
        .attr("id", "chart")
        .attr("width", w)
        .attr("height", h)
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
      var dateParser = d3.time.format("%Y/%B").parse;
      var x = d3.time.scale()
        .domain(d3.extent(data, function(d) {
          var date = dateParser(d.date);
          return date;
        }))
        .range([0 + margin.left, width]);

      var y = d3.scale.linear()
        .domain([0, d3.max(data, function(d) {
          return d.value;
        })])
        .range([height, 0 + margin.top]);
      //range([0, height]);

      //enter()
      svg.selectAll(".point")
        .data(data)
        .enter()
        .append("circle")
        .classed("point", true)
        .attr("r", 2);
      //Update
      svg.selectAll(".point")
        .attr("cx", function(d) {
          var date = dateParser(d.date);
          return x(date);
        })
        .attr("cy", function(d) {
          return y(d.value);
        })

      //Exit()
      svg.selectAll(".point")
        .data(data)
        .exit()
        .remove();
    }
  </script>
</body>

</html>

Basically I want to achieve this kind of plot

var data = [{
  glazed: 3.14,
  jelly: 4.43,
  powdered: 2.43,
  sprinkles: 3.86,
  age: 18,
  responses: 7
}, {
  glazed: 3.00,
  jelly: 3.67,
  powdered: 2.67,
  sprinkles: 4.00,
  age: 19,
  responses: 3
}, {
  glazed: 2.00,
  jelly: 4.00,
  powdered: 2.33,
  sprinkles: 4.33,
  age: 20,
  responses: 3
}, {
  glazed: 3.50,
  jelly: 4.50,
  powdered: 1.00,
  sprinkles: 3.50,
  age: 21,
  responses: 2
}, {
  glazed: 2.83,
  jelly: 3.50,
  powdered: 1.83,
  sprinkles: 4.50,
  age: 22,
  responses: 6
}, {
  glazed: 3.25,
  jelly: 4.75,
  powdered: 2.25,
  sprinkles: 3.50,
  age: 23,
  responses: 4
}, {
  glazed: 1.50,
  jelly: 4.00,
  powdered: 2.50,
  sprinkles: 4.00,
  age: 25,
  responses: 2
}, {
  glazed: 1.67,
  jelly: 3.00,
  powdered: 1.33,
  sprinkles: 4.00,
  age: 26,
  responses: 3
}, {
  glazed: 2.50,
  jelly: 4.00,
  powdered: 1.00,
  sprinkles: 4.50,
  age: 27,
  responses: 2
}, {
  glazed: 3.00,
  jelly: 4.33,
  powdered: 1.33,
  sprinkles: 4.33,
  age: 28,
  responses: 3
}, {
  glazed: 5.00,
  jelly: 4.00,
  powdered: 1.00,
  sprinkles: 4.00,
  age: 29,
  responses: 1
}, {
  glazed: 5.00,
  jelly: 5.00,
  powdered: 2.00,
  sprinkles: 5.00,
  age: 30,
  responses: 1
}, {
  glazed: 1.50,
  jelly: 4.50,
  powdered: 3.00,
  sprinkles: 4.75,
  age: 31,
  responses: 4
}, {
  glazed: 3.67,
  jelly: 3.33,
  powdered: 1.67,
  sprinkles: 4.67,
  age: 32,
  responses: 3
}, {
  glazed: 2.00,
  jelly: 4.50,
  powdered: 1.00,
  sprinkles: 5.00,
  age: 33,
  responses: 2
}, {
  glazed: 2.75,
  jelly: 3.75,
  powdered: 2.50,
  sprinkles: 4.50,
  age: 34,
  responses: 4
}, {
  glazed: 4.00,
  jelly: 3.00,
  powdered: 2.75,
  sprinkles: 4.25,
  age: 35,
  responses: 4
}, {
  glazed: 1.50,
  jelly: 3.00,
  powdered: 4.00,
  sprinkles: 4.00,
  age: 36,
  responses: 2
}, {
  glazed: 3.00,
  jelly: 3.00,
  powdered: 3.50,
  sprinkles: 4.00,
  age: 37,
  responses: 2
}, {
  glazed: 4.00,
  jelly: 2.00,
  powdered: 3.33,
  sprinkles: 4.67,
  age: 39,
  responses: 3
}, {
  glazed: 3.50,
  jelly: 3.00,
  powdered: 4.00,
  sprinkles: 4.50,
  age: 40,
  responses: 2
}, {
  glazed: 2.75,
  jelly: 2.75,
  powdered: 4.00,
  sprinkles: 4.25,
  age: 41,
  responses: 4
}, {
  glazed: 2.25,
  jelly: 2.50,
  powdered: 1.75,
  sprinkles: 4.25,
  age: 42,
  responses: 4
}, {
  glazed: 1.00,
  jelly: 2.00,
  powdered: 1.00,
  sprinkles: 5.00,
  age: 43,
  responses: 1
}, {
  glazed: 2.00,
  jelly: 3.00,
  powdered: 3.67,
  sprinkles: 3.33,
  age: 44,
  responses: 3
}, {
  glazed: 3.33,
  jelly: 2.33,
  powdered: 3.33,
  sprinkles: 3.33,
  age: 46,
  responses: 3
}, {
  glazed: 2.25,
  jelly: 4.00,
  powdered: 2.75,
  sprinkles: 3.00,
  age: 47,
  responses: 4
}, {
  glazed: 3.75,
  jelly: 2.00,
  powdered: 3.00,
  sprinkles: 2.75,
  age: 48,
  responses: 4
}, {
  glazed: 2.75,
  jelly: 2.00,
  powdered: 3.75,
  sprinkles: 3.25,
  age: 49,
  responses: 4
}, {
  glazed: 2.67,
  jelly: 2.67,
  powdered: 1.67,
  sprinkles: 3.67,
  age: 51,
  responses: 3
}, {
  glazed: 2.50,
  jelly: 2.50,
  powdered: 4.00,
  sprinkles: 3.00,
  age: 52,
  responses: 2
}, {
  glazed: 3.00,
  jelly: 3.67,
  powdered: 4.67,
  sprinkles: 2.67,
  age: 53,
  responses: 3
}, {
  glazed: 5.00,
  jelly: 5.00,
  powdered: 5.00,
  sprinkles: 3.50,
  age: 54,
  responses: 2
}, {
  glazed: 2.33,
  jelly: 1.67,
  powdered: 2.33,
  sprinkles: 3.33,
  age: 55,
  responses: 3
}, {
  glazed: 3.00,
  jelly: 2.00,
  powdered: 3.00,
  sprinkles: 3.00,
  age: 56,
  responses: 1
}, {
  glazed: 2.00,
  jelly: 2.00,
  powdered: 2.00,
  sprinkles: 4.00,
  age: 57,
  responses: 1
}, {
  glazed: 1.25,
  jelly: 2.00,
  powdered: 3.00,
  sprinkles: 1.75,
  age: 59,
  responses: 4
}, {
  glazed: 2.50,
  jelly: 2.50,
  powdered: 4.00,
  sprinkles: 2.50,
  age: 60,
  responses: 2
}, {
  glazed: 2.33,
  jelly: 2.33,
  powdered: 2.67,
  sprinkles: 3.00,
  age: 61,
  responses: 3
}, {
  glazed: 2.25,
  jelly: 2.50,
  powdered: 3.75,
  sprinkles: 3.00,
  age: 62,
  responses: 4
}, {
  glazed: 1.50,
  jelly: 3.00,
  powdered: 3.00,
  sprinkles: 2.00,
  age: 63,
  responses: 2
}, {
  glazed: 2.00,
  jelly: 3.00,
  powdered: 3.40,
  sprinkles: 2.40,
  age: 64,
  responses: 5
}, {
  glazed: 2.00,
  jelly: 1.00,
  powdered: 4.50,
  sprinkles: 2.00,
  age: 65,
  responses: 2
}, {
  glazed: 2.00,
  jelly: 1.67,
  powdered: 4.00,
  sprinkles: 1.67,
  age: 66,
  responses: 3
}, {
  glazed: 1.50,
  jelly: 1.75,
  powdered: 3.75,
  sprinkles: 2.25,
  age: 67,
  responses: 4
}, {
  glazed: 2.00,
  jelly: 2.50,
  powdered: 4.25,
  sprinkles: 2.00,
  age: 68,
  responses: 4
}, {
  glazed: 3.00,
  jelly: 2.00,
  powdered: 3.00,
  sprinkles: 3.00,
  age: 70,
  responses: 1
}, {
  glazed: 2.33,
  jelly: 2.67,
  powdered: 4.33,
  sprinkles: 2.33,
  age: 71,
  responses: 3
}, {
  glazed: 3.00,
  jelly: 2.50,
  powdered: 3.75,
  sprinkles: 2.00,
  age: 72,
  responses: 4
}, {
  glazed: 2.00,
  jelly: 2.50,
  powdered: 4.50,
  sprinkles: 2.50,
  age: 73,
  responses: 2
}, {
  glazed: 3.00,
  jelly: 2.00,
  powdered: 4.00,
  sprinkles: 1.50,
  age: 74,
  responses: 2
}];
body,
html {
  margin: 0;
  padding: 0;
  font-family: "Arial", sans-serif;
  font-size: 0.95em;
  text-align: center;
}
#chart {
  background-color: #F5F2EB;
  border: 1px solid #CCC;
}
.bar {
  fill: purple;
  shape-rendering: crispEdges;
}
.bar-label {
  fill: black;
  text-anchor: middle;
  font-size: 18px;
}
.axis path,
.axis line {
  fill: none;
  stroke: #000;
  shape-rendering: crispEdges;
}
.gridline path,
.gridline line {
  fill: none;
  stroke: #ccc;
  shape-rendering: crispEdges;
}
.trendline {
  fill: none;
  stroke: #ccc;
  stroke-width: 4px;
}
.area {
  opacity: 0.25;
  fill: #ccc;
  stroke: #ccc;
  stroke-width: 1px;
}
.donut {
  opacity: 0.1;
}
.highlight {
  opacity: 1;
  cursor: hand;
}
.axis-label {
  text-anchor: middle;
}
.chart-header {
  text-transform: capitalize;
  font-size: 125%;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Learning D3</title>
  <link rel="stylesheet" href="main.css">
  <script type="text/javascript" src="d3.min.js"></script>
</head>

<body>
  <!--Place all DOM elements here -->
  <script type="text/javascript" src="survey_data.js"></script>
  <script>
    var w = 800;
    var h = 450;
    var margin = {
      top: 60,
      bottom: 80,
      left: 100,
      right: 80
    };
    var width = w - margin.left - margin.right;
    var height = h - margin.top - margin.bottom;
    var svg = d3.select("body").append("svg")
      .attr("id", "chart")
      .attr("width", w)
      .attr("height", h);
    var chart = svg.append("g")
      .classed("display", true)
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    var tickValues = [18, 25, 32, 39, 46, 53, 60, 67, 74];
    var colorScale = d3.scale.category10();
    var x = d3.scale.linear()
      .domain(d3.extent(data, function(d) {
        return d.age;
      }))
      .range([0, width]);
    var y = d3.scale.linear()
      .domain([1, 5])
      .range([height, 0]);
    var xAxis = d3.svg.axis()
      .scale(x)
      .tickValues(tickValues)
      .orient("bottom");
    var yAxis = d3.svg.axis()
      .scale(y)
      .ticks(5)
      .tickSize(20)
      .tickFormat(function(d) {
        return d.toFixed(1);
      })
      .orient("left");
    var xGridlines = d3.svg.axis()
      .scale(x)
      .tickValues(tickValues)
      .tickSize(height, height)
      .tickFormat("")
      .orient("bottom");
    var yGridlines = d3.svg.axis()
      .scale(y)
      .tickSize(-width, 0, 0)
      .tickFormat("")
      .orient("left");
    var responseScale = d3.scale.linear()
      .domain(d3.extent(data, function(d) {
        return d.responses;
      }))
      .range([2, 15]);
    var initialize = 1;

    function drawAxis(params) {
      if (initialize) {
        this.append("g")
          .call(params.gridlines.x)
          .classed("gridline x", true)
          .attr("transform", "translate(" + 0 + "," + 0 + ")");
        this.append("g")
          .call(params.gridlines.y)
          .classed("gridline y", true)
          .attr("transform", "translate(" + 0 + "," + 0 + ")");
        this.append("g")
          .call(params.axis.x)
          .classed("axis x", true)
          .attr("transform", "translate(" + 0 + "," + height + ")");
        this.append("g")
          .call(params.axis.y)
          .classed("axis y", true)
          .attr("transform", "translate(" + 0 + "," + 0 + ")");
        this.select(".y.axis")
          .append("text")
          .classed("y axis-label", true)
          .attr("transform", "translate(" + -56 + "," + height / 2 + ") rotate(-90)")
          .text("Rating (1=Low, 5=High)");
        this.select(".x.axis")
          .append("text")
          .classed("x axis-label", true)
          .attr("transform", "translate(" + width / 2 + "," + 48 + ")")
          .text("Customer age");
        this.append("g")
          .append("text")
          .classed("chart-header", true)
          .text("")
          .attr("transform", "translate(0," + -24 + ")")
        initialize = 0;
      }
    }

    function plot(params) {
      var self = this;
      //Get each of the donut types
      var donuts = d3.keys(params.data[0]).filter(function(d) {
        return d !== "age" && d !== "responses";
      });
      drawAxis.call(this, params);
      //Create a group for each type of donut
      this.selectAll(".donut")
        .data(donuts)
        .enter()
        .append("g")
        .attr("class", function(d) {
          return d;
        })
        .classed("donut", true);

      this.selectAll(".donut")
        .style("fill", function(d, i) {
          return colorScale(i);
        })
        .on("mouseover", function(d, i) {
          d3.select(this)
            //.classed("highlight", true)
            .transition()
            .style("opacity", 1);
        })
        .on("mouseout", function(d, i) {
          d3.select(this)
            //.classed("highlight", false)
            .transition()
            .style("opacity", 0.1);
        });

      donuts.forEach(function(donut) {
        var g = self.selectAll("g." + donut);
        var arr = params.data.map(function(d) {
          return {
            key: donut,
            value: d[donut],
            age: d.age,
            responses: d.responses
          };
        });
        //Setup circles
        g.selectAll(".response")
          .data(arr)
          .enter()
          .append("circle")
          .classed("response", true);
        //Update circles
        g.selectAll(".response")
          .attr("r", function(d) {
            return responseScale(d.responses);
          })
          .attr("cx", function(d) {
            return x(d.age);
          })
          .attr("cy", function(d) {
            return y(d.value);
          })
          .on("mouseover", function(d, i) {
            var str = d.key + " Donut: ";
            str += "Age: " + d.age + ", ";
            str += "Responses: " + d.responses + ", ";
            str += "Average Rating: " + d.value;
            str += ""
            d3.select(".chart-header").text(str);
          })
          .on("mouseout", function(d, i) {
            d3.select(".chart-header").text("");
          });
        //Remove any unbound elements
        g.selectAll(".response").data(arr).exit().remove();
      });
    }
    plot.call(chart, {
      data: data,
      gridlines: {
        x: xGridlines,
        y: yGridlines
      },
      axis: {
        x: xAxis,
        y: yAxis
      }
    });
  </script>
</body>

</html>

Upvotes: 2

Views: 387

Answers (1)

seaotternerd
seaotternerd

Reputation: 6419

To filter your data so that you just have data from a specific origin, you can use the filter function. This function takes one argument, which is another function that will return true for all data points you want to include and false for all data points you want to exclude. For instance, if you want the circles that have Germany as their origin, you could do this:

var germany = svg.selectAll(".point")
                 .filter(function(d) {return d.Origin == "Germany"});

As for setting color and opacity, it doesn't look like you're doing that anywhere (even in your stylesheet, you don't have any styles for "circle" elements or the ".point" class). Since you want to just change the color and opacity for a subset of your circles, your best bet is to use d3's style() function, which lets you change the style of data points. For instance, if you wanted to make all of the circles representing data points with Germany as their origin be red and completely opaque, you could do this:

germany.style("fill", "red").style("opacity", 1);

Alternatively, if you wanted to color all circles based on their origin, you could skip the filtering step and use a color scale to color all of them at once:

//creates a scale to assign colors
var colorScale = d3.scale.category10(); 

//Then apply it to all points by assigning
// fill based on a callback function
svg.selectAll(".point")
   .style("fill", function(d){return colorScale(d.Origin)});

Upvotes: 2

Related Questions