Published unlisted
Edited
Jul 12, 2021
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
const height = 500;
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height]);

// Flower code
const plot = flowerPlot()
// flower width
.width(width)
// flower height
.height(height)
// 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 svg.node();
}
Insert cell
Insert cell
Insert cell
popByAgeData
Insert cell
In `values`, we store the data objects we want to render in each petal. Please, note that we need just one data object for rendering a basic flower.
Insert cell
Insert cell
{
const height = 500;
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height]);

// Flower code
const plot = flowerPlot()
// flower width
.width(width)
// flower height
.height(height)
// 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 vaccinations in Italy by age, updated to Jul 1, 2021 ')
/*
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 svg.node();
}
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: 80 };
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
foo = data[2]
Insert cell
test = {
const height = 500;
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height]);
return svg.node()
}
Insert cell
testplot.data(foo)(d3.select(test))
Insert cell
testplot = flowerPlot()
.width(width)
.height(500)
.colors(colors[0])
.staticStroke({ color: colors[0][0].color, width: 1 })
.overStroke({ color: colors[0][0].color, width: 5 })
.title('Hello Flower Plot 0')
.id('hrikhrf');
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