From 33e2386cffdd43b293e4638801610f87940fc6c9 Mon Sep 17 00:00:00 2001 From: Andrew Michael McNutt Date: Fri, 15 Mar 2024 16:43:27 -0700 Subject: [PATCH] abandon the full integration of the new check --- public/lang-docs.md | 156 ---------------- src/lib/ColorLint.test.ts | 5 - src/lib/__snapshots__/ColorLint.test.ts.snap | 10 - src/lib/__snapshots__/LintDocs.test.ts.snap | 156 ---------------- src/lib/lint-language/LintLanguage.test.ts | 7 +- src/lib/linter.ts | 6 +- src/lib/lints/diverging-order.ts | 187 +++++++++---------- 7 files changed, 97 insertions(+), 430 deletions(-) diff --git a/public/lang-docs.md b/public/lang-docs.md index 1308a156..1358188f 100644 --- a/public/lang-docs.md +++ b/public/lang-docs.md @@ -1308,162 +1308,6 @@ Program: -### Diverging Palettes order - -Description: Diverging palettes should have a middle color that is the lightest or darkest color. This is because if they are not, then they will not be differentiable from each other in some contexts. - -Natural Language: (sort(filter(colors, x => index(x) < count(colors) // 2), y => lab.l(y)) == map(filter(colors, x => index(x) < count(colors) // 2), y => lab.l(y)) AND sort(filter(colors, x => index(x) > count(colors) // 2), y => lab.l(y)) == reverse(map(filter(colors, x => index(x) > count(colors) // 2), y => lab.l(y))) AND (ALL z IN colors WHERE index(z) != count(colors) // 2 SUCH THAT lab.l(middle(colors)) > lab.l(z) OR ALL z IN colors WHERE index(z) != count(colors) // 2 SUCH THAT lab.l(middle(colors)) < lab.l(z))) - -Palettes that will fail this test: - -- #000, #fff, #ff7e0e, #0f0, #0084a9, #00f with a #fff background - -- #be4704, #008000, #801242 with a #fff background - - - -Palettes that will pass this test: - -- #ff7e0e with a #fff background - -- #67001f, #b2182b, #d6604d, #f4a582, #fddbc7, #fff, #e0e0e0, #bababa, #878787, #4d4d4d, #1a1a1a with a #fff background - -- #67001f, #fff, #1a1a1a with a #fff background - - -Program: - -```json -{ - "$schema": "http://localhost:3000/lint-schema.json", - "and": [ - { - "==": { - "left": { - "sort": { - "filter": "colors", - "varb": "x", - "func": { - "<": { - "left": "index(x)", - "right": { - "//": { "left": {"count": "colors"}, "right": 2 } - } - } - } - }, - "varb": "y", - "func": {"lab.l": "y"} - }, - "right": { - "map": { - "filter": "colors", - "varb": "x", - "func": { - "<": { - "left": "index(x)", - "right": { - "//": { "left": {"count": "colors"}, "right": 2 } - } - } - } - }, - "varb": "y", - "func": {"lab.l": "y"} - } - } - }, - { - "==": { - "left": { - "sort": { - "filter": "colors", - "varb": "x", - "func": { - ">": { - "left": "index(x)", - "right": { - "//": { "left": {"count": "colors"}, "right": 2 } - } - } - } - }, - "varb": "y", - "func": {"lab.l": "y"} - }, - "right": { - "reverse": { - "map": { - "filter": "colors", - "varb": "x", - "func": { - ">": { - "left": "index(x)", - "right": { - "//": { "left": {"count": "colors"}, "right": 2 } - } - } - } - }, - "varb": "y", - "func": {"lab.l": "y"} - } - } - } - }, - { - "or": [ - { - "all": { - "in": "colors", - "varb": "z", - "where": { - "!=": { - "left": "index(z)", - "right": { - "//": { "left": {"count": "colors"}, "right": 2 } - } - } - }, - "predicate": { - ">": { - "left" : { "lab.l": {"middle": "colors"} }, - "right": { "lab.l": "z" } - } - } - } - }, - { - "all": { - "in": "colors", - "varb": "z", - "where": { - "!=": { - "left": "index(z)", - "right": { - "//": { "left": {"count": "colors"}, "right": 2 } - } - } - }, - "predicate": { - "<": { - "left" : { "lab.l": {"middle": "colors"} }, - "right": { "lab.l": "z" } - } - } - } - } - ] - } - ] -} - -``` - - - - - ### Even Distribution Description: Categorical values should have an even distribution around the hue circle in LCH color space diff --git a/src/lib/ColorLint.test.ts b/src/lib/ColorLint.test.ts index b80582aa..f7f459b5 100644 --- a/src/lib/ColorLint.test.ts +++ b/src/lib/ColorLint.test.ts @@ -16,7 +16,6 @@ import CatOrderSimilarity from "./lints/cat-order-similarity"; import CVDCheck from "./lints/cvd-check"; import ColorNameDiscriminability, { getName } from "./lints/name-discrim"; import ColorTags from "./lints/color-tags"; -import DivergingOrder from "./lints/diverging-order"; import EvenDistribution from "./lints/even-distribution"; import Fair from "./lints/fair"; import Gamut from "./lints/in-gamut"; @@ -140,10 +139,6 @@ test("ColorLint - CVD: Grayscale", async () => { autoTest(CVDCheck[3]); }); -test("ColorLint - Diverging", async () => { - autoTest(DivergingOrder); -}); - const ughWhat = ["#00ffff", "#00faff", "#00e4ff", "#fdfdfc", "#00ffff"]; test("ColorLint - Background Contrast", async () => { const examplePal = makePalFromString(ughWhat); diff --git a/src/lib/__snapshots__/ColorLint.test.ts.snap b/src/lib/__snapshots__/ColorLint.test.ts.snap index 8250de60..5f0afa98 100644 --- a/src/lib/__snapshots__/ColorLint.test.ts.snap +++ b/src/lib/__snapshots__/ColorLint.test.ts.snap @@ -64,16 +64,6 @@ exports[`ColorLint - Contrast (3) contrastTextAAA 1`] = `"These colors () do not exports[`ColorLint - Contrast (3) contrastTextAAA 2`] = `"These colors (#af3b4b) do not have a sufficient contrast ratio with the background and may be hard to discriminate in some contexts."`; -exports[`ColorLint - Diverging 1`] = `"This palette should have a middle color that is the lightest or darkest color, from which the other colors grow darker or lighter respectively."`; - -exports[`ColorLint - Diverging 2`] = `"This palette should have a middle color that is the lightest or darkest color, from which the other colors grow darker or lighter respectively."`; - -exports[`ColorLint - Diverging 3`] = `"This palette should have a middle color that is the lightest or darkest color, from which the other colors grow darker or lighter respectively."`; - -exports[`ColorLint - Diverging 4`] = `"This palette should have a middle color that is the lightest or darkest color, from which the other colors grow darker or lighter respectively."`; - -exports[`ColorLint - Diverging 5`] = `"This palette should have a middle color that is the lightest or darkest color, from which the other colors grow darker or lighter respectively."`; - exports[`ColorLint - EvenDistribution 1`] = `"This palette does not evenly distribute the colors around its range correctly. Try making the spacing between the colors more regular to resolve this issue. "`; exports[`ColorLint - EvenDistribution 2`] = `"This palette does not evenly distribute the colors around its range correctly. Try making the spacing between the colors more regular to resolve this issue. "`; diff --git a/src/lib/__snapshots__/LintDocs.test.ts.snap b/src/lib/__snapshots__/LintDocs.test.ts.snap index bcb74b64..a6c4065c 100644 --- a/src/lib/__snapshots__/LintDocs.test.ts.snap +++ b/src/lib/__snapshots__/LintDocs.test.ts.snap @@ -1311,162 +1311,6 @@ Program: -### Diverging Palettes order - -Description: Diverging palettes should have a middle color that is the lightest or darkest color. This is because if they are not, then they will not be differentiable from each other in some contexts. - -Natural Language: (sort(filter(colors, x => index(x) < count(colors) // 2), y => lab.l(y)) == map(filter(colors, x => index(x) < count(colors) // 2), y => lab.l(y)) AND sort(filter(colors, x => index(x) > count(colors) // 2), y => lab.l(y)) == reverse(map(filter(colors, x => index(x) > count(colors) // 2), y => lab.l(y))) AND (ALL z IN colors WHERE index(z) != count(colors) // 2 SUCH THAT lab.l(middle(colors)) > lab.l(z) OR ALL z IN colors WHERE index(z) != count(colors) // 2 SUCH THAT lab.l(middle(colors)) < lab.l(z))) - -Palettes that will fail this test: - -- #000, #fff, #ff7e0e, #0f0, #0084a9, #00f with a #fff background - -- #be4704, #008000, #801242 with a #fff background - - - -Palettes that will pass this test: - -- #ff7e0e with a #fff background - -- #67001f, #b2182b, #d6604d, #f4a582, #fddbc7, #fff, #e0e0e0, #bababa, #878787, #4d4d4d, #1a1a1a with a #fff background - -- #67001f, #fff, #1a1a1a with a #fff background - - -Program: - -\`\`\`json -{ - "$schema": "http://localhost:3000/lint-schema.json", - "and": [ - { - "==": { - "left": { - "sort": { - "filter": "colors", - "varb": "x", - "func": { - "<": { - "left": "index(x)", - "right": { - "//": { "left": {"count": "colors"}, "right": 2 } - } - } - } - }, - "varb": "y", - "func": {"lab.l": "y"} - }, - "right": { - "map": { - "filter": "colors", - "varb": "x", - "func": { - "<": { - "left": "index(x)", - "right": { - "//": { "left": {"count": "colors"}, "right": 2 } - } - } - } - }, - "varb": "y", - "func": {"lab.l": "y"} - } - } - }, - { - "==": { - "left": { - "sort": { - "filter": "colors", - "varb": "x", - "func": { - ">": { - "left": "index(x)", - "right": { - "//": { "left": {"count": "colors"}, "right": 2 } - } - } - } - }, - "varb": "y", - "func": {"lab.l": "y"} - }, - "right": { - "reverse": { - "map": { - "filter": "colors", - "varb": "x", - "func": { - ">": { - "left": "index(x)", - "right": { - "//": { "left": {"count": "colors"}, "right": 2 } - } - } - } - }, - "varb": "y", - "func": {"lab.l": "y"} - } - } - } - }, - { - "or": [ - { - "all": { - "in": "colors", - "varb": "z", - "where": { - "!=": { - "left": "index(z)", - "right": { - "//": { "left": {"count": "colors"}, "right": 2 } - } - } - }, - "predicate": { - ">": { - "left" : { "lab.l": {"middle": "colors"} }, - "right": { "lab.l": "z" } - } - } - } - }, - { - "all": { - "in": "colors", - "varb": "z", - "where": { - "!=": { - "left": "index(z)", - "right": { - "//": { "left": {"count": "colors"}, "right": 2 } - } - } - }, - "predicate": { - "<": { - "left" : { "lab.l": {"middle": "colors"} }, - "right": { "lab.l": "z" } - } - } - } - } - ] - } - ] -} - -\`\`\` - - - - - ### Even Distribution Description: Categorical values should have an even distribution around the hue circle in LCH color space diff --git a/src/lib/lint-language/LintLanguage.test.ts b/src/lib/lint-language/LintLanguage.test.ts index ed1e64c8..761b8b30 100644 --- a/src/lib/lint-language/LintLanguage.test.ts +++ b/src/lib/lint-language/LintLanguage.test.ts @@ -681,7 +681,7 @@ test("LintLanguage Sequential Colors", () => { ); }); -test.only("LintLanguage Diverging Colors", () => { +test("LintLanguage Diverging Colors", () => { const middleIndex = { "//": { left: { count: "colors" }, right: 2 } }; const leftFilter = { filter: "colors", @@ -755,7 +755,10 @@ test.only("LintLanguage Diverging Colors", () => { ]); const result = LLEval(prog, divergingColors, { debugCompare: false }); expect(result.result).toBe(true); - const result2 = LLEval(prog, toPal(["#be4704", "#e00050", "#008000"])); + const result2 = LLEval( + prog, + toPal(["#be4704", "#008000", "#1a1a1a", "#e00050"]) + ); expect(result2.result).toBe(false); }); diff --git a/src/lib/linter.ts b/src/lib/linter.ts index a33b0140..c0c6b930 100644 --- a/src/lib/linter.ts +++ b/src/lib/linter.ts @@ -34,7 +34,6 @@ export const BUILT_INS: CustomLint[] = [ ...SizeDiscrim, AvoidExtremes, CatOrderSimilarity, - DivergingOrder, EvenDistribution, Gamut, MaxColors, @@ -50,7 +49,10 @@ export function runLintChecks( ): ColorLint[] { const ignoreList = palette.evalConfig; const globallyIgnoredLints = palette.evalConfig?.globallyIgnoredLints || []; - const lints = customLints.map((x) => CreateCustomLint(x)); + const lints = [ + DivergingOrder, + ...customLints.map((x) => CreateCustomLint(x)), + ] as (typeof ColorLint)[]; return ( lints .map((x) => new x(palette)) diff --git a/src/lib/lints/diverging-order.ts b/src/lib/lints/diverging-order.ts index 07e90288..6524c4b7 100644 --- a/src/lib/lints/diverging-order.ts +++ b/src/lib/lints/diverging-order.ts @@ -1,122 +1,78 @@ -import { JSONToPrettyString, makePalFromString } from "../utils"; -import type { CustomLint } from "../ColorLint"; - +import { ColorLint } from "../ColorLint"; +import type { PalType } from "../../types"; import { Color } from "../Color"; import type { ColorWrap } from "../../types"; import type { LintFixer } from "../linter-tools/lint-fixer"; -const middleIndex = { "//": { left: { count: "colors" }, right: 2 } }; -const leftFilter = { - filter: "colors", - varb: "x", - func: { "<": { left: "index(x)", right: middleIndex } }, -}; -const rightFilter = { - filter: "colors", - varb: "x", - func: { ">": { left: "index(x)", right: middleIndex } }, -}; -const middlePred = { - left: { "lab.l": { middle: "colors" } }, - right: { "lab.l": "z" }, +const meanPoint2d = (points: Color[]) => { + const labPoints = points.map((x) => x.toColorIO().to("lab").coords); + const xs = labPoints.map((x) => x[1]); + const ys = labPoints.map((x) => x[2]); + const x = xs.reduce((a, b) => a + b, 0) / xs.length; + const y = ys.reduce((a, b) => a + b, 0) / ys.length; + return { x, y }; }; -const allLighter = { - all: { - in: "colors", - varb: "z", - where: { "!=": { left: "index(z)", right: middleIndex } }, - predicate: { ">": middlePred }, - }, +const findMinDistPoint = (points: Color[], pos: { x: number; y: number }) => { + const labPoints = points.map((x) => x.toColorIO().to("lab").coords); + const { x, y } = pos; + const distances = labPoints.map(([x1, y1]) => Math.hypot(x1 - x, y1 - y)); + const minDist = Math.min(...distances); + return points[distances.indexOf(minDist)]; }; -const allDarker = { - all: { - in: "colors", - varb: "z", - where: { "!=": { left: "index(z)", right: middleIndex } }, - predicate: { "<": middlePred }, - }, -}; -const lint: CustomLint = { - name: "Diverging Palettes order", - program: JSONToPrettyString({ - $schema: `${location.href}lint-schema.json`, - and: [ - // order - { - "==": { - left: { sort: leftFilter, varb: "y", func: { "lab.l": "y" } }, - right: { map: leftFilter, varb: "y", func: { "lab.l": "y" } }, - }, - }, - { - "==": { - left: { sort: rightFilter, varb: "y", func: { "lab.l": "y" } }, - right: { - reverse: { - map: rightFilter, - varb: "y", - func: { "lab.l": "y" }, - }, - }, - }, - }, - // darkest or lightest is in the middle +export default class DivergingOrder extends ColorLint { + name = "Diverging Palettes order"; + taskTypes = ["diverging"] as PalType[]; + group = "usability" as const; + requiredTags = []; + description: string = `Diverging palettes should have a middle color that is the lightest or darkest color. This is because if they are not, then they will not be differentiable from each other in some contexts.`; + _runCheck() { + const { colors } = this.palette; + if (colors.length <= 2) { + return { passCheck: true, data: false }; + } - { or: [allLighter, allDarker] }, - ], - }), + const summarizedDirections = colors + .slice(0, -1) + .map((x, i) => + x.color.luminance() > colors[i + 1].color.luminance() ? 1 : -1 + ) + .reduce((acc, x) => { + if (acc.length === 0) return [x]; + if (acc[acc.length - 1] === x) return acc; + return [...acc, x]; + }, [] as number[]); - taskTypes: ["diverging"] as const, - requiredTags: [], - level: "error", - group: "usability", - description: `Diverging palettes should have a middle color that is the lightest or darkest color. This is because if they are not, then they will not be differentiable from each other in some contexts.`, - failMessage: `This palette should have a middle color that is the lightest or darkest color, from which the other colors grow darker or lighter respectively.`, - id: "extreme-colors-built-in", - blameMode: "none", - subscribedFix: "fixDivergingOrder", - expectedPassingTests: [ - makePalFromString(["#ff7e0e"]), - makePalFromString([ - "#67001f", - "#b2182b", - "#d6604d", - "#f4a582", - "#fddbc7", - "#fff", - "#e0e0e0", - "#bababa", - "#878787", - "#4d4d4d", - "#1a1a1a", - ]), - makePalFromString(["#67001f", "#fff", "#1a1a1a"]), - ], - expectedFailingTests: [ - makePalFromString([ - "#000000", - "#ffffff", - "#ff7e0e", - "#00ff00", - "#0084a9", - "#0000ff", - ]), - makePalFromString(["#be4704", "#008000", "#801242"]), - ], -}; -export default lint; + return { passCheck: summarizedDirections.length === 2, data: false }; + } + buildMessage(): string { + return `This palette should have a middle color that is the lightest or darkest color, from which the other colors grow darker or lighter respectively.`; + } + subscribedFix: string = "fixDivergingOrder"; +} export const fixDivergingOrder: LintFixer = async (palette) => { // figure out if its centered on a light color or a dark color? // a dumb hueristic is just look at what the center color is in lab space, and see if its darker or lighter than most colors let colors = [...palette.colors]; + // const medianPoint = findMinDistPoint(colors, meanPoint2d(colors)); + // console.log(medianPoint.toHex()); + // let darkerThanMedian = colors.filter( + // (x) => x.luminance() < medianPoint.luminance() + // ).length; + const sortByLum = (a: ColorWrap, b: ColorWrap) => { const aL = a.color.luminance(); const bL = b.color.luminance(); if (aL === bL) return 0; return aL > bL ? 1 : -1; }; + // if (darkerThanMedian < colors.length / 2) { + // console.log("reversing"); + // colors = colors.reverse(); + // } + + // const lightPoint = colors.at(-1)!; const leftColors = [colors.at(-1)!]; const rightColors = [colors.at(-2)!]; for (let i = 0; i < colors.length - 2; i++) { @@ -137,3 +93,36 @@ export const fixDivergingOrder: LintFixer = async (palette) => { ]; return [{ ...palette, colors }]; }; +// { +// "exist": { +// "in": "colors", +// "varb": "c", +// "predicate": { +// "all": { +// "in": "colors", +// "varbs": ["a", "b"], +// "where": { +// "and": [ +// { "<": {"left": "index(a)", "right": "index(c)"} }, +// { +// "==": { +// "left": "index(a)", +// "right": { "-": {"left": "index(b)", "right": 1} } +// } +// } +// ] +// }, +// "predicate": { +// "and": [ +// { +// "<": { "left": {"lab.l": "a"}, "right": {"lab.l": "c"} } +// }, +// { +// ">": { "left": {"lab.l": "b"}, "right": {"lab.l": "a"} } +// } +// ] +// } +// } +// } +// } +// }