Published
Edited
May 23, 2022
1 fork
Importers
68 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// munsell = yaml.safeLoad(await d3.text(munsell_url))
munsell = yaml.safeLoad(await FileAttachment("real.yaml").text())
Insert cell
Insert cell
xyY_to_XYZ = ([x, y, Y]) => {
Y *= 0.9749629514078465;
return [x*Y/y, Y, (1 - x - y)*Y/y]; }
Insert cell
Insert cell
adapt_C_D65_bradford = ([X, Y, Z]) =>
[+0.9904476*X -0.0071683*Y -0.0116156*Z,
-0.0123712*X +1.0155950*Y -0.0029282*Z,
-0.0035635*X +0.0067697*Y +0.9181569*Z]
Insert cell
Insert cell
munsell_XYZ_D65 = {
const xyY = zip(munsell.x, munsell.y, munsell.Y);
const XYZ_C = map(xyY_to_XYZ, xyY);
return Array.from(XYZ_C, adapt_C_D65_bradford); }
Insert cell
Insert cell
munsell_in_gamut = Int8Array.from(munsell_XYZ_D65, in_gamut)
Insert cell
Insert cell
munsell_XYZ_D65_in_gamut = [...compress(munsell_XYZ_D65, munsell_in_gamut)]
Insert cell
Insert cell
munsell_hex_in_gamut = {
const srgb = map(xyz_to_srgb, munsell_XYZ_D65_in_gamut);
return Array.from(srgb, to_hex); }
Insert cell
Insert cell
hue_names = Array.from(
product(
['R', 'YR', 'Y', 'GY', 'G', 'BG', 'B', 'PB', 'P', 'RP'],
['2.5', '5', '7.5', '10']),
([H, num]) => `${num}${H}`)
Insert cell
Insert cell
munsell_h_to_radians = {
const hue_radians = map(i => i*2*Math.PI/40, range(40));
const names_radians_map = Object.fromEntries(zip(hue_names, hue_radians));
return H => names_radians_map[H]; }
Insert cell
Insert cell
cylindrical_to_cartesian = ([height, angle, radius]) =>
[height, Math.cos(angle)*radius, Math.sin(angle)*radius]
Insert cell
Insert cell
munsell_Vab_in_gamut = {
const angle = map(munsell_h_to_radians, munsell.h);
const VangleC = zip(munsell.V, angle, munsell.C);
const VangleC_in_gamut = compress(VangleC, munsell_in_gamut);
return Array.from(VangleC_in_gamut, cylindrical_to_cartesian); }
Insert cell
Insert cell
Y_for_V = (V) =>
V * (1.2219 + V * (-0.23111 + V * (0.23951 + V * (-0.021009 + V * (0.0008404)))))
Insert cell
hex_for_neutral_V = function XYZ_for_V(V) {
const
[Xw, Yw, Zw] = standard_whitepoints.C,
Y = Y_for_V(V) * 0.9749629514078465,
X = Xw * Y / Yw,
Z = Zw * Y / Yw,
XYZ_D65 = adapt_C_D65_bradford([X, Y, Z]),
sRGB = xyz_to_srgb(XYZ_D65);
return to_hex(sRGB); }
Insert cell
neutral_V_hex = Array.from(zip(count(), map(hex_for_neutral_V, range(11))))
Insert cell
neutral_Vab_hex = Array.from(neutral_V_hex, ([i, hex]) => [[i, 0, 0], hex])
Insert cell
Insert cell
static_zdog_picture = {
const element = DOM.canvas(width, width * 10/16);
const illo = new Zdog.Illustration({element,
zoom: width/55, scale: {y: 2.5},
rotate: {x: -Math.PI/5} });
const shapes = Array.from(
chain(zip(munsell_Vab_in_gamut, munsell_hex_in_gamut), neutral_Vab_hex),
([[V, a, b], hex]) =>
new Zdog.Shape({
addTo: illo,
translate: {x: b, y: 5-V, z: a},
color: hex,
stroke: 1.2 }));
illo.updateRenderGraph();
return element; }
Insert cell
Insert cell
munsell_h_to_paired_indices = {
const hue_indices = chain(range(1, 21), range(-1, -21, -1));
const names_indices_map = Object.fromEntries(zip(hue_names, hue_indices));
return H => names_indices_map[H]; }
Insert cell
neutral_VChex = Array.from(neutral_V_hex, ([i, hex]) => [i, 0, hex])
Insert cell
munsell_VChex_in_gamut_in_hue_groups = {
const Hi = map(munsell_h_to_paired_indices, munsell.h)
const iVC = zip(Hi, munsell.V, munsell.C);
const iVC_in_gamut = compress(iVC, munsell_in_gamut);
const i_VChex_in_gamut = map(
([[i, V, C], hex]) => [i, [V, C, hex]],
zip(iVC_in_gamut, munsell_hex_in_gamut));
const igroups = groupby(
sorted(i_VChex_in_gamut, ([i]) => Math.abs(i)),
([i]) => Math.abs(i));
const sign = (i) => (i > 0) - (i < 0);
return Array.from(igroups,
([group_key, i_VCh]) => Array.from(i_VCh,
([i, [V, C, hex]]) => [V, C*sign(i), hex]).concat(neutral_VChex)); }
Insert cell
zdog_hue_slices = {
const canvases = Array.from(munsell_VChex_in_gamut_in_hue_groups,
(VChex, k) => {
const right = k % 2, left = !right;
const w = width/2;
const element = DOM.canvas(w, w * .55);
Object.assign(element.style, {background: '#555'});
const illo = new Zdog.Illustration({element,
zoom: w/47, scale: {y: 2},
rotate: {x: 0} });
const shapes = Array.from(VChex,
([V, C, hex]) =>
new Zdog.Shape({
addTo: illo,
translate: {y: 5 - V, x: C + 3*left + 3.5*right, z: 0},
color: hex,
stroke: 1.7 }));
illo.updateRenderGraph();
return element; });
return html`${canvases}`; }
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
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