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>
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>