I am trying to learn D3 and am looking at this example:
http://bl.ocks.org/weiglemc/6185069
What I want to do now is change the shape of the dots, so I want circles, squares, and triangles based on the brand of the cereal in the data set instead of all circles as datapoints. This seems like it should be a simple change, but I can't get the shapes to show up when I make my change.
I know that this change needs to be made in this segment of the code:
svg.selectAll(".dot")
.data(data)
.enter().append("circle")
.attr("class", "dot")
.attr("r", 3.5)
.attr("cx", xMap)
.attr("cy", yMap)
.style("fill", function(d) { return color(cValue(d));})
.on("mouseover", function(d) {
tooltip.transition()
.duration(200)
.style("opacity", .9);
tooltip.html(d["Cereal Name"] + "<br/> (" + xValue(d)
+ ", " + yValue(d) + ")")
.style("left", (d3.event.pageX + 5) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
tooltip.transition()
.duration(500)
.style("opacity", 0);
});
I need to change the append of the circle and the attributes. I want to use a conditional so
.attr("d", function(d,i) {if (d["Cereal Name"] == "Nabisco" return d3.svg.symbol().type("circle");
else if (d["Cereal Name"] == "Post" return d3.svg.symbol().type("triangle-down");
else return d3.svg.symbol().type("circle")
However, this is not working for me. Does anyone have an insight in how to do this? I don't want to have all circles, I want different shapes depending on the brand name of the cereal in the example. Thank you.
Edit: I tried looking at this:
Filter data in d3 to draw either circle or square
But I couldn't get this to work
First, you have to set the symbol generator (in d3 v4.x):
var symbol = d3.symbol();
And then appending a path element:
var dots = svg.selectAll(".dots")
.data(data)
.enter()
.append("path");
After that, it comes the most important part: you have to specify the type of your symbol generator. In the following demo, we can set the shape depending on the name of the brand (I'm using a dataset about chocolate that i found online):
dots.attr("d", symbol.type(function(d){
if(d.name == "Lindt"){ return d3.symbolCross
} else if (d.name == "Bournville"){ return d3.symbolDiamond
} else if (d.name == "Dolfin"){ return d3.symbolSquare
} else if (d.name == "Hershey"){ return d3.symbolStar
} else if (d.name == "Galaxy"){ return d3.symbolTriangle
} else if (d.name == "Dairy Milk"){ return d3.symbolCircle
}}))
Of course, you could avoid that ugly bunch of if...else defining the symbol type in the dataset itself, or just using an ordinal scale.
Check the working demo (using manufacturer instead, to have fewer shapes):
var data = [{
"name": "Dairy Milk",
"manufacturer": "cadbury",
"price": 45,
"rating": 2
}, {
"name": "Galaxy",
"manufacturer": "Nestle",
"price": 42,
"rating": 3
}, {
"name": "Lindt",
"manufacturer": "Lindt",
"price": 80,
"rating": 4
}, {
"name": "Hershey",
"manufacturer": "Hershey",
"price": 40,
"rating": 1
}, {
"name": "Dolfin",
"manufacturer": "Lindt",
"price": 90,
"rating": 5
}, {
"name": "Bournville",
"manufacturer": "cadbury",
"price": 70,
"rating": 2
}];
var w = 300, h = 300;
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
var xScale = d3.scaleLinear().domain([0, d3.max(data, function(d){ return d.price})]).range([30,w*0.9]);
var yScale = d3.scaleLinear().domain([d3.max(data, function(d){ return d.rating})*1.1, 0]).range([10,h*0.9]);
var symbol = d3.symbol();
var dots = svg.selectAll(".dots")
.data(data)
.enter()
.append("path");
dots.attr("d", symbol.type(function(d){if(d.manufacturer == "Lindt"){ return d3.symbolCross} else if (d.manufacturer == "cadbury"){ return d3.symbolDiamond} else if (d.manufacturer == "Nestle"){ return d3.symbolSquare} else if (d.manufacturer == "Hershey"){ return d3.symbolStar} }))
.attr('fill', "teal")
.attr('stroke','#000')
.attr('stroke-width',1)
.attr('transform',function(d){ return "translate("+xScale(d.price)+","+yScale(d.rating)+")"; });
var xAxis = d3.axisBottom(xScale);
var yAxis = d3.axisLeft(yScale);
var gX = svg.append("g")
.call(xAxis)
.attr("transform", "translate(0," + w*0.9 + ")");
var gY = svg.append("g")
.call(yAxis)
.attr("transform", "translate(30,0)");
<script src="https://d3js.org/d3.v4.min.js"></script>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With