Published
Edited
Mar 15, 2022
1 star
Insert cell
# Bluefish Charts (DEMO)

Proof-of-concept charts in Bluefish.
Insert cell
## Bar Charts
Insert cell
stackedData = [
{ "category": "A", bar: {"value": 28, "anotherValue": 42,}, },
{ "category": "B", bar: {"value": 55, "anotherValue": 70,} },
{ "category": "C", bar: {"value": 43, "anotherValue": 30,} },
{ "category": "D", bar: {"value": 91, "anotherValue": 42,} },
{ "category": "E", bar: {"value": 81, "anotherValue": 29,} },
{ "category": "F", bar: {"value": 53, "anotherValue": 42,} },
{ "category": "G", bar: {"value": 19, "anotherValue": 100,} },
{ "category": "H", bar: {"value": 87, "anotherValue": 42,} },
{ "category": "I", bar: {"value": 52, "anotherValue": 42,} },
];
Insert cell
stackedDataEntries = stackedData.map(d => ({ ...d, bar: Object.entries(d.bar).map(([k, v]) => ({ name: k, value: v}))}))
Insert cell
barData = mkList(stackedData.map(d => ({ ...d, bar: mkList(Object.entries(d.bar).map(([k, v]) => ({ name: k, value: v})))})))
Insert cell
colors = d3.scaleOrdinal().domain(Object.keys(stackedData[0].bar)).range(d3.schemeTableau10)
Insert cell
createListShape = (elementShape, relations, flip=false) => createShape2({
$elements$: elementShape,
$neighbors$: createShape2({
$curr$: 'ref',
$next$: 'ref',
}, flip ? {
'next->curr': relations
}
: {
'curr->next': relations
})
})
Insert cell
bar = createShape2({
// this tick mark might be a relation glyph in the future
$bar$: createListShape(
({ name, value }) => M.rect({ width: 20, height: value, fill: colors(name)}),
// [C.vSpace(0), C.alignCenter],
// [C.vSpace(3), C.alignCenter],
[C.hSpace(0), C.alignBottom],
true,
),
// box: M.rect({ fill: 'none', stroke: 'magenta', }),
"tick": M.rect({ width: 1., height: 8., fill: "gray" }),
"underline": M.rect({ height: 1., fill: "gray" }),
"$category$": (contents) => M.text({ contents, fontSize: "12px" }),
},{
"bar->tick": [C.vSpace(5), C.vAlignCenter],
"bar->underline": [C.alignLeft, C.alignRight, C.vSpace(2)],
"tick->category": [C.vSpace(1), C.vAlignCenter],
// 'box->bar': [...C.containsShrinkWrap],
})
Insert cell
barChart = createShape({
shapes: {
$elements$: bar,
$neighbors$: createShape({
shapes: {
$curr$: 'ref',
$next$: 'ref',
},
rels: {
"curr/bar->next/bar": [C.alignBottom, C.hSpace(5)],
// 'curr->next': [C.vSpace(5), C.alignCenter],
// "curr/bar->next/bar": [C.alignMiddle, C.hSpace(5)],
// "curr/bar/elements/0->next/bar/elements/0": [C.alignMiddle, C.hSpace(5)],
// "curr/bar/elements/1->next/bar/elements/0": [C.alignTop, C.hSpace(5)],

// "curr/bar/elements/0->next/bar/elements/0": [C.alignBottom, C.hSpace(7.5)],
}
})
}
});
Insert cell
render(barData, barChart)
Insert cell
mkList(stackedData)
Insert cell
stackedBarRect = (fieldNames, colors) => {
return createShape({
shapes: Object.fromEntries(fieldNames.map((fn) => [`$${fn}$`, (height) => M.rect({ width: 20, height, fill: colors[fn] })])),
rels: Object.fromEntries(_.zipWith(fieldNames.slice(0, -1), fieldNames.slice(1), (curr, next) =>
{
return [`${curr}->${next}`, [C.vSpace(0), C.vAlignCenter]]
})),
})
}
Insert cell
stackedBarRect(['value', 'anotherValue'], ['coral', 'steelblue'])(stackedData[0].bar)
Insert cell
groupedBarRect = (fieldNames, colors) => {
return createShape({
shapes: Object.fromEntries(fieldNames.map((fn) => [`$${fn}$`, (height) => M.rect({ width: 20, height, fill: colors[fn] })])),
rels: Object.fromEntries(_.zipWith(fieldNames.slice(0, -1), fieldNames.slice(1), (curr, next) =>
{
return [`${curr}->${next}`, [C.hSpace(0), C.alignBottom]]
})),
})
}
Insert cell
stackedBar = createShape({
shapes: {
// this tick mark might be a relation glyph in the future
"$bar$": stackedBarRect(["anotherValue", "value"], {"value": "steelblue", "anotherValue": "coral"}),
"tick": M.rect({ width: 1., height: 8., fill: "gray" }),
"$category$": (contents) => M.text({ contents, fontSize: "12px" }),
},
rels: {
// "anotherValue->value": [C.vSpace(0), C.vAlignCenter],
"bar->tick": [C.vSpace(5), C.vAlignCenter],
"tick->category": [C.vSpace(1), C.vAlignCenter],
},
})
Insert cell
groupedBar = createShape({
shapes: {
// this tick mark might be a relation glyph in the future
"$bar$": groupedBarRect(["anotherValue", "value"], {"value": "steelblue", "anotherValue": "coral"}),
"tick": M.rect({ width: 1., height: 8., fill: "gray" }),
"underline": M.rect({ height: 1., fill: "gray" }),
"$category$": (contents) => M.text({ contents, fontSize: "12px" }),
},
rels: {
// "anotherValue->value": [C.vSpace(0), C.vAlignCenter],
"bar->tick": [C.vSpace(5), C.vAlignCenter],
"bar->underline": [C.alignLeft, C.alignRight, C.vSpace(2)],
"tick->category": [C.vSpace(1), C.vAlignCenter],
},
})
Insert cell
stackedBars = createShape({
shapes: {
$elements$: stackedBar,
$neighbors$: createShape({
shapes: {
$curr$: 'ref',
$next$: 'ref',
},
rels: { "curr/bar/anotherValue->next/bar/value": [C.alignTop, C.hSpace(2)] }
})
}
});
Insert cell
groupedBars = createShape({
shapes: {
$elements$: groupedBar,
$neighbors$: createShape({
shapes: {
$curr$: 'ref',
$next$: 'ref',
},
// TODO: need to add the ability to access the children of a ref back for this!!
rels: { "curr/bar/value->next/bar/value": [C.alignBottom, C.hSpace(5)] }
})
}
});
Insert cell
render(mkList(stackedData), stackedBars)
Insert cell
render(mkList(stackedData), groupedBars)
Insert cell
stackedData
Insert cell
## Imports
Insert cell
bfjs = require('@bfjs/core@0.8.7/dist/main.js')
Insert cell
M = bfjs.marks
Insert cell
C = bfjs.constraints
Insert cell
createShape = bfjs.createShape
Insert cell
createShape2 = (shapes, rels={}) => bfjs.createShape({ shapes, rels })
Insert cell
ref = bfjs.ref
Insert cell
render = (dataOrShape, shapeFn = undefined) => myRender(bfjs.render(dataOrShape, shapeFn))
Insert cell
import {myRender} from '@joshpoll/bluefish-tutorial-0-8'
Insert cell
mkList = (xs) => ({
elements: xs,
neighbors: xs.length < 2 ? [] :
_.zipWith(_.range(xs.length - 1), _.range(1, xs.length), (curr, next) => (
{
curr: ref(`../../elements/${curr}`),
next: ref(`../../elements/${next}`),
}
))
})
Insert cell
mkList(['a', 'b', 'c'])
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more