Public
Edited
Jul 28, 2023
2 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
colorSpacesLocal
Insert cell
transitionFilter(
transitionGenerator(viewof spaceRef, {
states: luminanceDomain
}),
viewof transSpaceRef
)
Insert cell
viewof transSpaceRef = Inputs.input()
Insert cell
luminanceRefTens = tidy.tidy(
[],
tidy.expand({
space: Object.keys(colorSpacesLocal),
luminanceRef: math.range(0, 100, 10, true).toArray()
}),
tidy.mutate({
sRgbRef: (d) =>
transitionInterpolate(transSpaceRef, (spaceRef) =>
_.flow([
colorSpacesLocal[spaceRef].from100,
colorSpacesLocal[spaceRef].toSRgb,
colorUtils.clampRgbGamut
])([d.luminanceRef, 0, 0])
),
hexRef: (d) => colorUtils.hexFromSRgb(d.sRgbRef),
luminance: (d) =>
_.flow([
colorSpacesLocal[d.space].fromSRgb,
colorSpacesLocal[d.space].to100,
(x) => x[0]
])(d.sRgbRef)
})
)
Insert cell
luminanceRef = tidy.tidy(
[],
tidy.expand({
space: Object.keys(colorSpacesLocal),
luminanceRef: [
...math
.range(0, 1, 0.1)
.toArray()
.map((x) => math.pow(x, 3)),
...math.range(1, 100, 1, true).toArray()
]
}),
tidy.mutate({
luminance: (d) =>
transitionInterpolate(transSpaceRef, (spaceRef) =>
_.flow([
colorSpacesLocal[spaceRef].from100,
colorSpacesLocal[spaceRef].toSRgb,
colorUtils.clampRgbGamut,
colorSpacesLocal[d.space].fromSRgb,
colorSpacesLocal[d.space].to100,
(x) => x[0]
])([d.luminanceRef, 0, 0])
)
})
)
Insert cell
// uses each space's luminance scale to determine color
luminanceStatic = tidy.tidy(
[],
tidy.expand({
space: Object.keys(colorSpacesLocal),
luminance: math.range(0, 100, 10, true).toArray()
}),
tidy.mutate({
sRgb: (d) =>
_.flow([
colorSpacesLocal[d.space].from100,
colorSpacesLocal[d.space].toSRgb
])([d.luminance, 0, 0]),
hex: (d) => colorUtils.hexFromSRgb(d.sRgb)
})
)
Insert cell
colorSpacesLocal.sRgb.from100([100, 0, 0])
Insert cell
// names of colorspaces, ordered
luminanceDomain = tidy
.tidy(
luminanceStatic,
tidy.mutate({
lumSRgb: (d) => _.flow(math.mean)(d.sRgb)
}),
tidy.groupBy(["space"], [tidy.summarize({ total: tidy.sum("lumSRgb") })]),
tidy.arrange("total")
)
.map((x) => x.space)
Insert cell
// add a couple "fake" color spaces here, only to make luminance comparisons
colorSpacesLocal = {
const spaces = {
...colorSpaces,
sRgb: new ColorSpace({
label: "SRGB",
fromSRgb: _.identity,
toSRgb: _.identity
}),
linearRgb: new ColorSpace({
label: "Linear RGB",
fromSRgb: colorUtils.linearRgbFromSRgb,
toSRgb: colorUtils.linearRgbToSRgb
})
};

// overwrite from/to 100 methods
spaces.sRgb.from100 = rgbFrom100;
spaces.sRgb.to100 = rgbTo100;
spaces.linearRgb.from100 = rgbFrom100;
spaces.linearRgb.to100 = rgbTo100;

return spaces;
}
Insert cell
// sorted using luminanceDomain
mapColorSpacesLocal = new Map(
[
...colorUtils
.mapColorSpaces({
colorSpaces: colorSpacesLocal
})
.entries()
].sort(
(a, b) => luminanceDomain.indexOf(a[1]) - luminanceDomain.indexOf(b[1])
)
)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// return only luminance, mean of all components
rgbTo100 = function (x) {
const L = math.mean(x) * 100;

return [L, 0, 0];
}
Insert cell
// consider only luminance, put into each component
rgbFrom100 = function (x) {
const [L, a, b] = x;
const val = L / 100;

return [val, val, val];
}
Insert cell
Insert cell
tidy = import("https://unpkg.com/@tidyjs/tidy@2.5.2/dist/es/index.js?module")
Insert cell
math = import("https://cdn.skypack.dev/mathjs@11.8.2?")
Insert cell
import {
transitionGenerator,
transitionFilter,
transitionInterpolate,
Easing
} from "@ijlyttle/transition-helper"
Insert cell
import { colorSpaces, colorUtils, ColorSpace } from "@ijlyttle/color-utilities"
Insert cell
import { changeTable } from "@ijlyttle/change-log"
Insert cell
import { inputMode, invokeMode, styleDark } from "@ijlyttle/dark-mode-input"
Insert cell
invokeMode(dark)
Insert cell
styleDark({ light: { background: "#fafafa" } })
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