showing results for - "d3 violin plot with points"
Axel
26 Sep 2017
1<script>
2
3// set the dimensions and margins of the graph
4var margin = {top: 10, right: 30, bottom: 30, left: 40},
5    width = 460 - margin.left - margin.right,
6    height = 400 - margin.top - margin.bottom;
7
8// append the svg object to the body of the page
9var svg = d3.select("#my_dataviz")
10  .append("svg")
11    .attr("width", width + margin.left + margin.right)
12    .attr("height", height + margin.top + margin.bottom)
13  .append("g")
14    .attr("transform",
15          "translate(" + margin.left + "," + margin.top + ")");
16
17// Read the data and compute summary statistics for each specie
18d3.csv("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/iris.csv", function(data) {
19
20  // Build and Show the Y scale
21  var y = d3.scaleLinear()
22    .domain([ 3.5,8 ])          // Note that here the Y scale is set manually
23    .range([height, 0])
24  svg.append("g").call( d3.axisLeft(y) )
25
26  // Build and Show the X scale. It is a band scale like for a boxplot: each group has an dedicated RANGE on the axis. This range has a length of x.bandwidth
27  var x = d3.scaleBand()
28    .range([ 0, width ])
29    .domain(["setosa", "versicolor", "virginica"])
30    .padding(0.25)     // This is important: it is the space between 2 groups. 0 means no padding. 1 is the maximum.
31  svg.append("g")
32    .attr("transform", "translate(0," + height + ")")
33    .call(d3.axisBottom(x))
34
35  // Features of the histogram
36  var histogram = d3.histogram()
37        .domain(y.domain())
38        .thresholds(y.ticks(20))    // Important: how many bins approx are going to be made? It is the 'resolution' of the violin plot
39        .value(d => d)
40
41  // Compute the binning for each group of the dataset
42  var sumstat = d3.nest()  // nest function allows to group the calculation per level of a factor
43    .key(function(d) { return d.Species;})
44    .rollup(function(d) {   // For each key..
45      input = d.map(function(g) { return g.Sepal_Length;})    // Keep the variable called Sepal_Length
46      bins = histogram(input)   // And compute the binning on it.
47      return(bins)
48    })
49    .entries(data)
50
51  // What is the biggest number of value in a bin? We need it cause this value will have a width of 100% of the bandwidth.
52  var maxNum = 0
53  for ( i in sumstat ){
54    allBins = sumstat[i].value
55    lengths = allBins.map(function(a){return a.length;})
56    longuest = d3.max(lengths)
57    if (longuest > maxNum) { maxNum = longuest }
58  }
59
60  // The maximum width of a violin must be x.bandwidth = the width dedicated to a group
61  var xNum = d3.scaleLinear()
62    .range([0, x.bandwidth()])
63    .domain([-maxNum,maxNum])
64
65  // Color scale for dots
66  var myColor = d3.scaleSequential()
67    .interpolator(d3.interpolateInferno)
68    .domain([3,9])
69
70  // Add the shape to this svg!
71  svg
72    .selectAll("myViolin")
73    .data(sumstat)
74    .enter()        // So now we are working group per group
75    .append("g")
76      .attr("transform", function(d){ return("translate(" + x(d.key) +" ,0)") } ) // Translation on the right to be at the group position
77    .append("path")
78        .datum(function(d){ return(d.value)})     // So now we are working bin per bin
79        .style("stroke", "none")
80        .style("fill","grey")
81        .attr("d", d3.area()
82            .x0( xNum(0) )
83            .x1(function(d){ return(xNum(d.length)) } )
84            .y(function(d){ return(y(d.x0)) } )
85            .curve(d3.curveCatmullRom)    // This makes the line smoother to give the violin appearance. Try d3.curveStep to see the difference
86        )
87
88  // Add individual points with jitter
89  var jitterWidth = 40
90  svg
91    .selectAll("indPoints")
92    .data(data)
93    .enter()
94    .append("circle")
95      .attr("cx", function(d){return(x(d.Species) + x.bandwidth()/2 - Math.random()*jitterWidth )})
96      .attr("cy", function(d){return(y(d.Sepal_Length))})
97      .attr("r", 5)
98      .style("fill", function(d){ return(myColor(d.Sepal_Length))})
99      .attr("stroke", "white")
100
101})
102
103</script>
Aggie
18 Jun 2018
1<script>
2
3// set the dimensions and margins of the graph
4var margin = {top: 10, right: 30, bottom: 30, left: 40},
5    width = 460 - margin.left - margin.right,
6    height = 400 - margin.top - margin.bottom;
7
8// append the svg object to the body of the page
9var svg = d3.select("#my_dataviz")
10  .append("svg")
11    .attr("width", width + margin.left + margin.right)
12    .attr("height", height + margin.top + margin.bottom)
13  .append("g")
14    .attr("transform",
15          "translate(" + margin.left + "," + margin.top + ")");
16
17// Read the data and compute summary statistics for each specie
18d3.csv("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/iris.csv", function(data) {
19
20  // Build and Show the Y scale
21  var y = d3.scaleLinear()
22    .domain([ 3.5,8 ])          // Note that here the Y scale is set manually
23    .range([height, 0])
24  svg.append("g").call( d3.axisLeft(y) )
25
26  // Build and Show the X scale. It is a band scale like for a boxplot: each group has an dedicated RANGE on the axis. This range has a length of x.bandwidth
27  var x = d3.scaleBand()
28    .range([ 0, width ])
29    .domain(["setosa", "versicolor", "virginica"])
30    .padding(0.25)     // This is important: it is the space between 2 groups. 0 means no padding. 1 is the maximum.
31  svg.append("g")
32    .attr("transform", "translate(0," + height + ")")
33    .call(d3.axisBottom(x))
34
35  // Features of the histogram
36
37  var histogram = d3.histogram()
38        .domain(y.domain())
39        .thresholds(y.ticks(20))    // Important: how many bins approx are going to be made? It is the 'resolution' of the violin plot
40        .value(d => d)
41
42  // Compute the binning for each group of the dataset
43  var sumstat = d3.nest()  // nest function allows to group the calculation per level of a factor
44    .key(function(d) { return d.Species;})
45    .rollup(function(d) {   // For each key..
46      input = d.map(function(g) { return g.Sepal_Length;})    // Keep the variable called Sepal_Length
47      bins = histogram(input)   // And compute the binning on it.
48      return(bins)
49    })
50    .entries(data)
51
52  // What is the biggest number of value in a bin? We need it cause this value will have a width of 100% of the bandwidth.
53  var maxNum = 0
54  for ( i in sumstat ){
55    allBins = sumstat[i].value
56    lengths = allBins.map(function(a){return a.length;})
57    longuest = d3.max(lengths)
58    if (longuest > maxNum) { maxNum = longuest }
59  }
60
61  // The maximum width of a violin must be x.bandwidth = the width dedicated to a group
62  var xNum = d3.scaleLinear()
63    .range([0, x.bandwidth()])
64    .domain([-maxNum,maxNum])
65
66  // Color scale for dots
67  var myColor = d3.scaleSequential()
68    .interpolator(d3.interpolateInferno)
69    .domain([3,9])
70
71  // Add the shape to this svg!
72  svg
73    .selectAll("myViolin")
74    .data(sumstat)
75    .enter()        // So now we are working group per group
76    .append("g")
77      .attr("transform", function(d){ return("translate(" + x(d.key) +" ,0)") } ) // Translation on the right to be at the group position
78    .append("path")
79        .datum(function(d){ return(d.value)})     // So now we are working bin per bin
80        .style("stroke", "none")
81        .style("fill","grey")
82        .attr("d", d3.area()
83            .x0( xNum(0) )
84            .x1(function(d){ return(xNum(d.length)) } )
85            .y(function(d){ return(y(d.x0)) } )
86            .curve(d3.curveCatmullRom)    // This makes the line smoother to give the violin appearance. Try d3.curveStep to see the difference
87        )
88
89  // Add individual points with jitter
90  var jitterWidth = 40
91  svg
92    .selectAll("indPoints")
93    .data(data)
94    .enter()
95    .append("circle")
96      .attr("cx", function(d){return(x(d.Species) + x.bandwidth()/2 - Math.random()*jitterWidth )})
97      .attr("cy", function(d){return(y(d.Sepal_Length))})
98      .attr("r", 5)
99      .style("fill", function(d){ return(myColor(d.Sepal_Length))})
100      .attr("stroke", "white")
101
102})
103
104</script>