Reputation: 14460
TL;DR: How do I get a scaleOrdinal over the d3.symbols?
I'm hoping to use d3.symbols for an ordinal scale, corresponding to a categorical attribute on some data.
d3.symbolsAn array containing the set of all built-in symbol types: circle, cross, diamond, square, star, triangle, and wye. Useful for constructing the range of an ordinal scale should you wish to use a shape encoding for categorical data.
Here's what I thought would work:
var svg = d3.select('#graph-container').append('svg').attr('xmlns', 'http://www.w3.org/2000/svg');
var g = svg.append('g');
var data = [{type: 'a'}, {type: 'a'}, {type: 'a'}, {type: 'b'}, {type: 'b'}, {type: 'c'}];
var shape = d3.scaleOrdinal(d3.symbols);
var s = g.selectAll('.symbol').data(data);
/* Does not render */
s.enter()
.append('path')
.attr('d', d => shape(d.type))
.attr('x', (d, i) => i * 20)
.attr('y', 50);
/* Sanity Check: Properly renders */
s.enter()
.append('circle')
.attr('r',7)
.attr('cx', (d, i) => (i+1)*20)
.attr('cy', 100);
<script src="https://d3js.org/d3.v5.min.js"></script>
<div id="graph-container"></div>
(alternately see fiddle).
Unfortunately the above fails with:
Error: <path> attribute d: Expected moveto path command ('M' or 'm'), "[object Object]".
Clearly shape(d.type)
is not returning a valid path. It's actually returning an object with a single function named draw, i.e. it looks like { draw: function() { ... } }
, which presumably refers to this draw method. Calling that draw method doesn't yield a valid path either, though, unfortunately.
Upvotes: 4
Views: 1212
Reputation: 102188
You're missing the symbol generator itself...
var symbol = d3.symbol();
... to which you'll pass the type:
s.enter()
.append('path')
.attr('d', d => symbol.type(shape(d.type))())
//etc...
Also, <path>
s don't have x
or y
attributes.
Here is the code with those changes:
var svg = d3.select('#graph-container').append('svg').attr('xmlns', 'http://www.w3.org/2000/svg');
var g = svg.append('g');
var data = [{
type: 'a'
}, {
type: 'a'
}, {
type: 'a'
}, {
type: 'b'
}, {
type: 'b'
}, {
type: 'c'
}];
var shape = d3.scaleOrdinal(d3.symbols);
var symbol = d3.symbol();
var s = g.selectAll('.symbol').data(data);
/* Does not render */
s.enter()
.append('path')
.attr('d', d => symbol.type(shape(d.type))())
.attr("transform", (_, i) => "translate(" + (20 + i * 20) + ",50)")
.attr('fill', 'black');
/* Properly renders */
s.enter()
.append('circle')
.attr('r', 7)
.attr('cx', (d, i) => (i + 1) * 20)
.attr('cy', 100)
.attr('fill', 'black');
<div id="graph-container"></div>
<script src="https://d3js.org/d3.v5.min.js"></script>
Upvotes: 3