score:8
Accepted answer
Here's a quick example which combines the ideas of your beeswarm
example with your initial boxplot. I've commented the tricky parts below:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
<script>
// set the dimensions and margins of the graph
var margin = {
top: 10,
right: 30,
bottom: 30,
left: 40
},
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 and compute summary statistics for each specie
d3.csv("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/iris.csv", function(data) {
// Compute quartiles, median, inter quantile range min and max --> these info are then used to draw the box.
var sumstat = d3.nest() // nest function allows to group the calculation per level of a factor
.key(function(d) {
return d.Species;
})
.rollup(function(d) {
q1 = d3.quantile(d.map(function(g) {
return g.Sepal_Length;
}).sort(d3.ascending), .25)
median = d3.quantile(d.map(function(g) {
return g.Sepal_Length;
}).sort(d3.ascending), .5)
q3 = d3.quantile(d.map(function(g) {
return g.Sepal_Length;
}).sort(d3.ascending), .75)
interQuantileRange = q3 - q1
min = q1 - 1.5 * interQuantileRange
max = q3 + 1.5 * interQuantileRange
return ({
q1: q1,
median: median,
q3: q3,
interQuantileRange: interQuantileRange,
min: min,
max: max
})
})
.entries(data)
// Show the X scale
var x = d3.scaleBand()
.range([0, width])
.domain(["setosa", "versicolor", "virginica"])
.paddingInner(1)
.paddingOuter(.5)
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
// Show the Y scale
var y = d3.scaleLinear()
.domain([3, 9])
.range([height, 0])
svg.append("g").call(d3.axisLeft(y))
// Show the main vertical line
svg
.selectAll("vertLines")
.data(sumstat)
.enter()
.append("line")
.attr("x1", function(d) {
return (x(d.key))
})
.attr("x2", function(d) {
return (x(d.key))
})
.attr("y1", function(d) {
return (y(d.value.min))
})
.attr("y2", function(d) {
return (y(d.value.max))
})
.attr("stroke", "black")
.style("width", 40)
// rectangle for the main box
var boxWidth = 100
svg
.selectAll("boxes")
.data(sumstat)
.enter()
.append("rect")
.attr("x", function(d) {
return (x(d.key) - boxWidth / 2)
})
.attr("y", function(d) {
return (y(d.value.q3))
})
.attr("height", function(d) {
return (y(d.value.q1) - y(d.value.q3))
})
.attr("width", boxWidth)
.attr("stroke", "black")
.style("fill", "#69b3a2")
// Show the median
svg
.selectAll("medianLines")
.data(sumstat)
.enter()
.append("line")
.attr("x1", function(d) {
return (x(d.key) - boxWidth / 2)
})
.attr("x2", function(d) {
return (x(d.key) + boxWidth / 2)
})
.attr("y1", function(d) {
return (y(d.value.median))
})
.attr("y2", function(d) {
return (y(d.value.median))
})
.attr("stroke", "black")
.style("width", 80)
var r = 8;
// create a scale that'll return a discreet value
// so that close y values fall in a line
var yPtScale = y.copy()
.range([Math.floor(y.range()[0] / r), 0])
.interpolate(d3.interpolateRound)
.domain(y.domain());
// bucket the data
var ptsObj = {};
data.forEach(function(d,i) {
var yBucket = yPtScale(d.Sepal_Length);
if (!ptsObj[d.Species]){
ptsObj[d.Species] = {};
}
if (!ptsObj[d.Species][yBucket]){
ptsObj[d.Species][yBucket] = [];
}
ptsObj[d.Species][yBucket].push({
cy: yPtScale(d.Sepal_Length) * r,
cx: x(d.Species)
});
});
// determine the x position
for (var x in ptsObj){
for (var row in ptsObj[x]) {
var v = ptsObj[x][row], // array of points
m = v[0].cx, // mid-point
l = m - (((v.length / 2) * r) - r/2); // left most position based on count of points in the bucket
v.forEach(function(d,i){
d.cx = l + (r * i); // x position
});
}
}
// flatten the data structure
var flatData = Object.values(ptsObj)
.map(function(d){return Object.values(d)})
.flat(2);
svg
.selectAll("points")
.data(flatData)
.enter()
.append("circle")
.attr("cx", function(d) {
return d.cx;
})
.attr("cy", function(d) {
return d.cy;
})
.attr("r", 4)
.style("fill", "white")
.attr("stroke", "black")
})
</script>
</body>
</html>
Source: stackoverflow.com
Related Query
- D3js Grouped Scatter plot with no collision
- Grouped scatter plot with multiple datasets D3
- Show labels based on collision detection scatter plot in d3js
- Using D3 transition method with data for scatter plot
- nvd3 scatter plot with ordinal scale
- how do you draw linear line in scatter plot with d3.js
- How can I plot positive and negative values for both axes in a scatter plot with d3?
- Making an interactive scatter plot with d3?
- Create an interactive 3d scatter plot with D3.js and Three.js with json data
- Create bode plot with minor and major ticks d3js
- Moving scatter plot circles with context zooming and brush in D3
- How to create a beeswarm plot with variable radius in d3js v5?
- Basic math 101 scatter plot with Plottable.js
- D3 Ordinal Scales with Scatter Plot
- Create scatter plot with ordinal scale in d3 version 4
- How to handle the scales with d3.drag in a scatter plot
- Creating scatter plot with D3.js
- How to draw a scatter plot with multiple y values for each x value?
- dc.js Scatter Plot with multiple values for a single key
- Create scatter plot with unequal intervals on x-axis using d3.js
- Example for animating a scatter plot in d3js
- How to render dates on x axis prior to 1900 with d3 .js scatter plot
- D3: Rescaling scatter plot elements with Update, without removing elements
- c3 (v4) scatter plot with two sets of data
- D3JS - Horizontal highlight on scatter plot
- How to color the area under a scatter plot with different colors
- How to use this data with D3js Scatter Plot?
- Label Not Generating For All Value In Scatter Plot D3js
- D3JS - Display both circles and triangles in a scatter plot
- Y Axis not displaying for scatter plot with d3 v4
More Query from same tag
- Contamination in a graph using d3js
- n3-chart width not set according to parent width
- D3js/Javascript with Dart
- Changing one element of an array of arrays with event
- D3's data update not functioning as expected
- Bar chart columns not grouping in D3/C3
- dc.js - Hide the div container till the svg is created
- Why is date from CSV file being outputted as NaN?
- Trying to implement d3.js version 4 as a polymer component
- Panning and zooming to an SVG element
- Set the value of a <select> element in D3?
- D3 incorrect drag behaviour
- D3 line graph getting error and not getting plotted
- threejs render text on or next to object
- Restrict line chart zoom in upto hours in dc chart library
- How can I put a country name on the world map?
- Spark 2.0.0 - JSON malformed output
- Text not displaying in the middle of circles in d3js
- Unable to make pie chart from the dataset
- Get bounding box of individual countries from topojson
- Stacked Area Chart in nvd3js - X Axis overflow
- Svg text element being overlapped by another svg element
- d3.scaleLog ticks with base 2
- Add constant horizontal line
- Nested functions in typescript gives errors
- Opening UI5 Quickview by non-SAPUI5 control
- Relative positioning of generated svg objects in D3
- Does the main D3 module namespace not get updated with bleeding edge submodule additions?
- Unpin all fixed nodes
- d3 trying to open html in div or iframe on click