Published
Edited
Feb 11, 2022
1 fork
Importers
2 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
shape(M.text({contents: "Hello World!", fontSize: "18pt", }))
Insert cell
// TODO: add some interactivity to these inputs
glyph(M.ellipse({cx: 200, cy: 50, "fill": "firebrick"}));
Insert cell
glyph(M.rect({width: 100, height: 200, "fill": "steelblue"}));
Insert cell
Insert cell
// `glyphView` lets you view the glyph while also being able to reuse it in other cells (in this case using the `rect` variable)
viewof rect = glyphView(M.rect({width: 100, height: 200, "fill": "steelblue"}));
Insert cell
G = bfjs.Glyph;
Insert cell
Insert cell
Insert cell
glyph(G.mk({
glyphs: {
"g1": M.text({x: 0, contents: "Hello", fontSize: "18pt", }),
"g2": M.text({x: 70, contents: "World!", fontSize: "18pt", }),
},
}));
Insert cell
glyph(G.mk({
glyphs: {
"g1": M.rect({x: 0, width: 50, height: 100, fill: "steelblue", }),
"g2": M.rect({x: 70, width: 100, height: 100, fill: "firebrick", }),
},
}));
Insert cell
Insert cell
Insert cell
glyph(G.mk({
glyphs: {
"g1": M.text({contents: "Hello", fontSize: "18pt", }),
"g2": M.text({contents: "World!", fontSize: "18pt", }),
},
relations: [{
fields: ["g1", "g2"],
constraints: [C.hAlignCenter, C.hSpace(40)],
}]
}));
Insert cell
glyph(G.mk({
glyphs: {
"g1": M.rect({width: 200, height: 100, fill: "steelblue", }),
"g2": M.rect({width: 150, height: 50, fill: "firebrick", }),
},
relations: [
{
fields: ["g1", "g2"],
constraints: [C.alignBottom, C.hSpace(spacing)],
}
]
}));
Insert cell
Insert cell
Insert cell
glyph(G.mk({
glyphs: {
"g1": M.text({contents: "Hello", fontSize: "18pt", }),
"g2": M.text({contents: "World!", fontSize: "18pt", }),
},
relations: [{
fields: ["g1", "g2"],
constraints: [C.hAlignCenter, C.hSpace(spacing)],
}]
}));
Insert cell
Insert cell
GF = bfjs.GlyphFn;
Insert cell
// adding empty data
glyph({}, GF.mk({
glyphs: {
"g1": M.text({contents: "Hello", fontSize: "18pt", }),
"g2": M.text({contents: "World!", fontSize: "18pt", }),
},
relations: [{
fields: ["g1", "g2"],
constraints: [C.hAlignCenter, C.hSpace(spacing)],
}]
}));
Insert cell
glyph("World", GF.mk({
glyphs: {
"g1": M.text({contents: "Hello", fontSize: "18pt", }),
},
objectGlyph: GF.mk((name) => M.text({contents: name + "!", fontSize: "18pt", })),
relations: [{
fields: ["g1", "$object"],
constraints: [C.hAlignCenter, C.hSpace(spacing)],
}]
}));
Insert cell
helloGlyph = GF.mk({
glyphs: {
"g1": M.text({contents: "Hello", fontSize: "18pt", }),
},
objectGlyph: GF.mk((name) => M.text({contents: name + "!", fontSize: "18pt", })),
relations: [{
fields: ["g1", "$object"],
constraints: [C.hAlignCenter, C.hSpace(spacing)],
}]
});
Insert cell
glyph("World", helloGlyph);
Insert cell
glyph("Bluefish", helloGlyph);
Insert cell
Insert cell
Insert cell
**TODO: put motivating example here of adding a bunch of circles and wanting them to be spaced evenly or something.**
Insert cell
ref = bfjs.mkMyRef;
Insert cell
Suppose we want to make a list of marbles.
We can start by writing something like this.
Insert cell
marblesSet = [1, 2, 3];
Insert cell
Insert cell
marblesList = ({
marbles: [1, 2, 3],
neighbor: [
{
curr: ref("../../marbles/0"),
next: ref("../../marbles/1"),
},
{
curr: ref("../../marbles/1"),
next: ref("../../marbles/2"),
}
]
})
Insert cell
Insert cell
## Making a List Function
Lists are a pretty common data structure, so we can write some code to automatically produce this neighbor relation for us:
Insert cell
_ = require("lodash");
Insert cell
mkList = (name, xs) => ({
[name]: xs,
neighbors: xs.length < 2 ? [] :
_.zipWith(_.range(xs.length - 1), _.range(1, xs.length), (curr, next) => (
{
curr: ref(`../../${name}/${curr}`),
next: ref(`../../${name}/${next}`),
}
))
})
Insert cell
/* play around with some input arrays here! */
mkList("marbles", [1, 2, 3]);
Insert cell
marbleGlyph = GF.mk({
glyphs: {
"circle": M.ellipse({ rx: 300 / 6, ry: 200 / 6, fill: "coral" }),
},
objectGlyph: GF.mk((n) => M.text({ contents: n.toString(), fontSize: "24px" })),
relations: [
{ fields: ["$object", "circle"], constraints: [C.alignCenterX, C.alignCenterY] }
]
});
Insert cell
glyph(1, marbleGlyph);
Insert cell
marblesGlyph = GF.mk({
fieldGlyphs: {
0: marbleGlyph,
1: marbleGlyph,
},
relations: [{
fields: ["0", "1"],
constraints: [C.hSpace(5.), C.alignCenterY]
}]
})
Insert cell
glyph([1, 2], marblesGlyph);
Insert cell
// uh oh!
glyph([1, 2, 3], marblesGlyph);
Insert cell
marblesListGlyph = GF.mk({
fieldGlyphs: {
marbles: marbleGlyph, // renders _every_ marble in the set using marbleGlyph
neighbors: G.mk({
relations: [{
fields: ["curr", "next"],
constraints: [C.hSpace(5.), C.alignCenterY]
}]
})
},
})
Insert cell
glyph(mkList("marbles", [1, 2]), marblesListGlyph);
Insert cell
glyph(mkList("marbles", [1, 2, 3]), marblesListGlyph);
Insert cell
Insert cell
glyph(mkList("marbles", _.range(1, numMarbles + 1)), marblesListGlyph);
Insert cell
## Composition in Bluefish
Insert cell
someMarbles = glyph(mkList("marbles", [1, 2, 3]), marblesListGlyph);
Insert cell
glyph(G.mk({
glyphs: {
"someMarbles": M.nil(), /* uh oh! cannot currently put someMarbles here (even if rendering step is taken away!! too many hacks) */
}
}));
Insert cell
## Let's Make a Bar Chart!(?!)
Insert cell
/* https://vega.github.io/vega-lite/examples/bar.html */
data = [
{ "category": "A", "value": 28 }, { "category": "B", "value": 55 }, { "category": "C", "value": 43 },
{ "category": "D", "value": 91 }, { "category": "E", "value": 81 }, { "category": "F", "value": 53 },
{ "category": "G", "value": 19 }, { "category": "H", "value": 87 }, { "category": "I", "value": 52 }
];
Insert cell
bar = GF.mk({
glyphs: {
// this tick mark might be a relation glyph in the future
"tick": M.rect({ width: 1., height: 8., fill: "gray" })
},
fieldGlyphs: {
"category": GF.mk((contents) => M.text({ contents, fontSize: "12px" })),
"value": GF.mk((height) => M.rect({ width: 20, height, fill: "steelblue" })),
},
relations: [
{
fields: ["value", "tick"],
constraints: [C.vSpace(5), C.vAlignCenter],
},
{
fields: ["tick", "category"],
constraints: [C.vSpace(1), C.vAlignCenter],
},
]
})
Insert cell
glyph(data[0], bar)
Insert cell
Insert cell
Insert cell
bars = GF.mk({
fieldGlyphs: {
bars: bar,
neighbors: GF.mk({
relations: [{ fields: ["curr/value", "next/value"], constraints: [C[alignment === "alignMiddle" ? "hAlignCenter" : alignment], C.hSpace(barSpacing)] }]
})
}
});
Insert cell
glyph(mkList("bars", data), bars);
Insert cell
mkList("bars", data)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
dev = true
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
## Interface Experiments
Insert cell
glyph(G.mk({
glyphs: {
"g1": M.text({contents: "Hello", fontSize: "18pt", }),
"g2": M.text({contents: "World!", fontSize: "18pt", }),
},
relations: [{
fields: ["g1", "g2"],
constraints: [C.hAlignCenter, C.hSpace(20)],
}]
}));
Insert cell
G.mk({
"g1": M.text({contents: "Hello", fontSize: "18pt", }),
"g2": M.text({contents: "World!", fontSize: "18pt", }),
"g1-g2": [C.hAlignCenter, C.hSpace(20)],
})
Insert cell
G.mk([
{
"g1": M.text({contents: "Hello", fontSize: "18pt", }),
"g2": M.text({contents: "World!", fontSize: "18pt", }),
},
{
"g1-g2": [C.hAlignCenter, C.hSpace(20)],
}])
Insert cell
G.mk({
objs: {
"g1": M.text({contents: "Hello", fontSize: "18pt", }),
"g2": M.text({contents: "World!", fontSize: "18pt", }),
},
rels: {
"g1->g2": [C.hAlignCenter, C.hSpace(20)],
},
})
Insert cell
G.mk({
objs: {
"g1": M.text({contents: "Hello", fontSize: "18pt", }),
"g2": M.text({contents: "World!", fontSize: "18pt", }),
},
rels: {
"g1->g2": [C.hAlignCenter, C.hSpace(20), "line"],
},
})
Insert cell
G.mk({
objs: {
"g1": M.text({contents: "Hello", fontSize: "18pt", }),
"g1->g2": "line",
"g2": M.text({contents: "World!", fontSize: "18pt", }),
},
rels: {
"g1->g2": [C.hAlignCenter, C.hSpace(20)],
"g1->(g1->g2)": [C.hSpace(5)],
},
})
Insert cell
G.mk({
objs: {
"g1": M.text({contents: "Hello", fontSize: "18pt", }),
"g1-g2": "line",
"g2": M.text({contents: "World!", fontSize: "18pt", }),
},
rels: {
"g1->g2": [C.hAlignCenter, C.hSpace(20)],
"g1->(g1-g2)": [C.hSpace(5)],
"(g1-g2)->g2": [C.hSpace(5)],
},
})
Insert cell
G.mk({
objs: {
"g1": M.text({contents: "Hello", fontSize: "18pt", }),
"g1->g2": "line",
"g2": M.text({contents: "World!", fontSize: "18pt", }),
},
rels: {
"g1->g2": [C.hAlignCenter, C.hSpace(20)],
"g1->(g1->g2)": [C.hSpace(5)],
"(g1->g2)->g2": [C.hSpace(5)],
},
})
Insert cell
Insert cell
Insert cell
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