Published
Edited
Jul 19, 2021
2 forks
Importers
35 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
const div = d3.select(DOM.element('div'))
.style('overflow-x', 'auto')
.attr('class', 'eligibles');
const svg = div.append('svg')
.style("width", `${box}px`)
.style("height", `${box}px`);
// Flower code
const plot = flowerPlot()
// flower width
.width(box)
// flower height
.height(box)
// data
.data(popByAgeData)
// fill color(s) of each petal
.colors([{color: flower_color, opacity: 0.1}])
// petal stroke
.staticStroke({ color: flower_color, width: 1 })
// petal-over-stroke (try hovering the mouse over a petal!)
.overStroke({ color: flower_color, width: 5 })
// chart title
.title('Eligibles for COVID-19 vaccines in Italy by age')
/*
chart ID (ie., namespace for gradients IDs,
useful if you deal with multiple charts
in the same notebook / project / ...)
*/
.id('popByAge');
svg.call(plot);
return div.node();
}
Insert cell
Insert cell
Insert cell
popByAgeData
Insert cell
Insert cell
Insert cell
{
const div = d3.select(DOM.element('div'))
.style('overflow-x', 'auto')
.attr('class', 'eligibles');
const svg = div.append('svg')
.style("width", `${box}px`)
.style("height", `${box}px`);
// Flower code
const plot = flowerPlot()
// flower width
.width(box)
// flower height
.height(box)
// data
.data(vaxxedByAgeData)
// fill colors of the petal stack
.colors([{color: flower_color, opacity: 1}, {color: flower_color, opacity: 0.5}, {color: flower_color, opacity: 0.1}])
// petal stroke
.staticStroke({ color: flower_color, width: 1 })
// petal-over-stroke (try hovering the mouse over a petal!)
.overStroke({ color: flower_color, width: 5 })
// chart title
.title('COVID-19 vaxxs in Italy by age')
/*
chart ID (ie., namespace for gradients IDs,
useful if you deal with multiple charts
in the same notebook / project / ...)
*/
.id('VaxxedPopByAge');
svg.call(plot);
return div.node();
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
flowerPlot = () => {
let id = 'flower'; // namespace
let title;
let width;
let height;
let margin = { top: 20, right: 20, bottom: 20, left: 20 };
let data;
let colors;
let staticStroke = { color: 'transparent', width: 1 };
let overStroke = { color: '#A8234E', width: 5 };
let displayLabels = true;
let displayLegend = true;
let debug = false;

const my = (selection) => {
const flowerRadius = Math.min(
(width / 2 - margin.right - margin.left) * 0.8,
(height / 2 - margin.top - margin.bottom) * 0.8
);

const petalStartLength = flowerRadius * 0.1;
const petalStopLength = flowerRadius;
const labelRadius = flowerRadius * 1.25;


// accessor to the petal width value (ie. last item in values)
const petalWidth = (d) =>
d.values[d.values.length - 1].value;

/*
* Title
*/

if (title !== 'undefined') {
const titleGroup = selection
.selectAll('g.title')
.data([null])
.join('g')
.attr('class', 'title')
.selectAll('text')
.data([null])
.join('text')
.text(title)
.attr('text-anchor', 'middle')
.attr('dominant-baseline', 'hanging')
.attr('font-weight', 'bold')
.style('font-family', 'Georgia')
.attr('x', width / 2)
.attr('y', margin.top / 3);
}

// create the main group containing the flower
const container = selection
.selectAll('g.flower')
.data([null])
.join('g')
.attr('class', 'flower')
.attr(
'transform',
`translate(${width / 2} , ${height / 2})`
);

/*
* Petals
*/

const petalsGroup = container
.selectAll('g.petals')
.data([null])
.join('g')
.attr('class', 'petals');

// angle generator: it computes the necessary angles without sorting data
const pie = d3
.pie()
.value(petalWidth)
.padAngle(0.1)
.sort(null)(data);

const p = petals()
.pie(pie)
.id(id)
.petalWidth(petalWidth)
.petalStartLength(petalStartLength)
.petalStopLenght(petalStopLength)
.stroke(staticStroke);

petalsGroup.call(p);

/*
* Colors
*/

const g = gradients()
.pie(pie)
.id(id)
.start(petalStartLength)
.stop(petalStopLength)
.colors(colors);

container.call(g);

/*
* Labels
*/

if (displayLabels) {
const groupLabels = container
.selectAll('g.labels')
.data([null])
.join('g')
.attr('class', 'labels');

const la = labels().pie(pie).position(labelRadius);

groupLabels.call(la);
}

/*
* Legend
*/

if (displayLegend) {
const legendGroup = container
.selectAll('g.legend')
.data([null])
.join('g')
.attr('class', 'legend');

const le = legend()
.petals(p.arcs()) // p.arcs() is the selection of the petals
.colors(colors)
.staticStroke(staticStroke)
.overStroke(overStroke)
.verticalTransformation((height / 2 - margin.bottom));

legendGroup.call(le);
}

/*
* VISUAL DEBUGGERS
*/

if (debug) {
const d = debuggers()
.pie(pie)
.petalStartLength(petalStartLength)
.petalStopLength(petalStopLength)
.labelRadius(labelRadius);
container.call(d);

}
};

// Accessors here below

// the underscore is the name of the thing passed in
// Here we cannot use arrow functions cause `arguments` is not defined for them!
my.id = function (_) {
//(height = +_, my) <----- (foo, bar, ..., baz) it executes all and it implicitly returns the last entry
return arguments.length ? ((id = _), my) : id;
};

my.title = function (_) {
return arguments.length ? ((title = _), my) : title;
};

my.width = function (_) {
//(height = +_, my) <----- (foo, bar, ..., baz) it executes all and it implicitly returns the last entry
return arguments.length ? ((width = +_), my) : width;
};

my.height = function (_) {
return arguments.length ? ((height = +_), my) : height;
};

my.data = function (_) {
return arguments.length ? ((data = _), my) : data;
};

my.colors = function (_) {
return arguments.length ? ((colors = _), my) : colors;
};

my.staticStroke = function (_) {
return arguments.length
? ((staticStroke = _), my)
: staticStroke;
};

my.overStroke = function (_) {
return arguments.length
? ((overStroke = _), my)
: overStroke;
};

my.displayLabels = function (_) {
return arguments.length
? ((displayLabels = _), my)
: displayLabels;
};

my.displayLegend = function (_) {
return arguments.length
? ((displayLegend = _), my)
: displayLegend;
};

my.debug = function (_) {
return arguments.length ? ((debug = _), my) : debug;
};

return my;
};

Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
test = {
const div = d3.select(DOM.element('div'))
.style('overflow-x', 'auto')
.attr('class', 'eligibles');
const svg = div.append('svg')
.style("width", `${box}px`)
.style("height", `${box}px`)
.attr('class', 'animationTest');

return div.node()
}
Insert cell
testplot.data(selectedData)(d3.select('svg.animationTest')) // or d3.select(test).call(testplot.data(selectedData)
Insert cell
testplot = flowerPlot()
.width(box)
.height(box)
.colors(colors[0])
.staticStroke({ color: colors[0][0].color, width: 1 })
.overStroke({ color: colors[0][0].color, width: 5 })
.title('Hey, Flower Plot')
.id('animationTest');
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more