Public
Edited
Jun 28, 2023
13 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
dispatch = d3.dispatch("log")
Insert cell
log = (...args) => {
dispatch.call("log", null, ...args);
}
Insert cell
Insert cell
Generators.observe(next => {
next(null);
dispatch.on("log", function(...args) {
next(args.length > 1 ? args : args[0]);
});
return () => dispatch.on("fn", null);
})
Insert cell
Insert cell
log("Hello world")
Insert cell
Insert cell
tap = (e, ...f) => log(e, ...f) || e
Insert cell
ftap = f => (...args) => tap(f(...args), ...args)
Insert cell
Insert cell
// `The sum is ${tap(1 + 1)}`
Insert cell
// ftap(Math.min)(1, 2, 3)
Insert cell
Insert cell
Generators.observe(next => {
const history = [];
next(null);
dispatch.on("log.history", function(...args) {
history.unshift(args);
if (history.length > 5) history.pop();
next(history);
});
return () => dispatch.on("fn", null);
})
Insert cell
Insert cell
watch = fn => {
const dispatch = d3.dispatch("fn");
const observer = Generators.observe(next => {
next(null);
dispatch.on("fn", function(first, ...rest) {
next(!rest.length || isEl(first) ? first : [first, ...rest]);
});
return () => dispatch.on("fn", null);
});
const observed = function(...args) {
const result = fn(...args);
dispatch.call("fn", null, result, ...args);
return result;
};
return Object.assign(observed, { observer });
}
Insert cell
Insert cell
sum = watch(d3.sum)
Insert cell
sum.observer
Insert cell
sum([1, 7, 4])
Insert cell
Insert cell
Insert cell
Insert cell
c = watch(chart)
Insert cell
{
const filtered = data.filter(({ date }) => date > new Date(2011, 0, 1));
c(filtered);
return d3.variance(filtered.map(d => d.value));
}
Insert cell
c.observer
Insert cell
Insert cell
// ctap = log => arr => log(arr)
Insert cell
Insert cell
logger = (returnFn, renderFn) => {
const dispatch = d3.dispatch("fn");
const history = [];
const observer = Generators.observe(next => {
next(null);
dispatch.on("fn", function(...args) {
history.unshift(renderFn(...args));
if (history.length > 9) history.pop();
next(
html`<div style="display: flex; flex-wrap: wrap;">${history.map(
d => html`${d}`
)}</div>`
);
});
return () => dispatch.on("fn", null);
});
const log = function(...args) {
dispatch.call("fn", null, ...args);
return returnFn(...args);
};
return Object.assign(log, { observer });
}
Insert cell
newVizLog = logger(d => d, chart)
Insert cell
newVizLog(data.slice(0, 30))
Insert cell
newVizLog(
newVizLog(
newVizLog(data).map(({ date, value }) => ({
date,
value: Math.log(value)
}))
).slice(0, 100)
)
Insert cell
newVizLog.observer
Insert cell
Insert cell
Insert cell
getLog = (n = 100) => {
const dispatch = d3.dispatch("fn");
const history = [];
const observer = Generators.observe(next => {
next(null);
dispatch.on("fn", function(args) {
history.push(args);
if (history.length > n) history.shift();
next(
html`<div style="display: flex; flex-wrap: wrap; max-height: 600px; overflow: scroll;">${history.map(
d => html`${d}`
)}</div>`
);
});
return () => dispatch.on("fn", null);
});
const log = function(msg) {
dispatch.call("fn", null, msg);
};
return Object.assign(log, { observer });
}
Insert cell
myArray = [1, 2, 3, 5, 5.5, 3, 4, 3.5, 6]
Insert cell
myLog = getLog(100)
Insert cell
myLog.observer
Insert cell
d3log.mean(myArray)
Insert cell
d3log.min(myArray)
Insert cell
d3log.variance(myArray)
Insert cell
d3log.shuffle(myArray.slice(0))
Insert cell
Insert cell
Insert cell
Insert cell
myLog2 = getLog()
Insert cell
myLog2.observer
Insert cell
d3log2.min(myArray)
Insert cell
d3log2.extent(myArray)
Insert cell
d3log2.quantile(myArray, .5)
Insert cell
d3log2.bisect(myArray.slice(0).sort(d3.ascending), 3)
Insert cell
d3log2.transpose(d3.pairs(myArray))
Insert cell
d3log2.zip(d3.pairs(myArray), d3.pairs(myArray), d3.pairs(myArray))
Insert cell
d3log2.ticks(0, 100, 20)
Insert cell
d3log2.range(10, 30, .5)
Insert cell
d3log2.cumsum(myArray)
Insert cell
d3log2.shuffle(myArray)
Insert cell
d3log2.permute(myArray, [0, 3, 2, 1])
Insert cell
d3log2.pairs(myArray)
Insert cell
d3log2.cross(myArray, myArray)
Insert cell
d3log2.group(d3.range(100).map(() => ~~d3.randomNormal(50, 20)()), d =>
Math.floor(d / 10)
)
Insert cell
Insert cell
Insert cell
Insert cell
getLog2 = (n = 100) => {
const dispatch = d3.dispatch("fn");
const history = [];
const log = function(msg) {
dispatch.call("fn", null, msg);
};
const observer = Generators.observe(next => {
next(Object.assign(md`No logs yet`, {value: log}));
dispatch.on("fn", function(args) {
history.push(args);
if (history.length > n) history.shift();
next(
html`<div style="
display: flex;
flex-wrap: wrap;
max-height: 600px;
overflow: scroll;"
>${history.map(d => html`${d}`)}</div>`,
{value: log}
);
});
return () => dispatch.on("fn", null);
});
return observer;
}
Insert cell
viewof test = getLog2()
Insert cell
// // prints "hello" over and over again:
// test("hello")
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
key = keys =>
html`${keys
.split(" ")
.map(
key => `<span style="
font-family: -apple-system, BlinkMacSystemFont, 'avenir next', avenir,
helvetica, 'helvetica neue', ubuntu, roboto, noto, 'segoe ui', arial,
sans-serif;
font-size: 14px;
font-weight: 500;
box-shadow: 0 0 0 1px #dedede, 1px 1px 0 1px #e8e8e8;
margin: 0 4px;
min-width: 6px;
padding-left: 4px;
padding-right: 4px;
text-align: center;
white-space: nowrap;
border-radius: .25rem;">${key}</span>`
)
.join("")}`
Insert cell
colors = [
"#1f77b4",
"#ff7f0e",
"#2ca02c",
"#d62728",
"#9467bd",
"#8c564b",
"#e377c2",
"#bcbd22",
"#17becf"
]
Insert cell
isEl = el => el instanceof HTMLElement || el instanceof SVGElement
Insert cell
// https://stackoverflow.com/a/32538867
isIterable = obj =>
obj == null ? false : typeof obj[Symbol.iterator] === 'function'
Insert cell
stringify = d =>
!isNaN(d)
? d
: Array.isArray(d)
? JSON.stringify(d.slice(0, 4))
: isIterable(d)
? JSON.stringify(Array.from(d).slice(0, 4))
: d.toString()
Insert cell
d3 = require("d3@6")
Insert cell
d3array = require("d3-array@2")
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