Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 43 additions & 5 deletions docs/_gen_cmaps.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
if TYPE_CHECKING:
from cmap import _catalog
from cmap import Colormap
from cmap._util import report
from cmap._util import report_cvds

# TODO: convert to jinja
TEMPLATE = """# {name}
Expand All @@ -32,6 +32,29 @@
{{{{ cmap_gray: {name} 30 }}}}
{{{{ cmap_sineramp: {name} }}}}

<form id="cvd" class="radio-group">
<label class="radio-option" title="Full Vision">
<input type="radio" name="cvd_button" value="normal" checked>
<span class="material-icons">visibility</span>
<span class="radio-label"> Normal Vision</span>
</label>
<label class="radio-option" title="Protanopic">
<input type="radio" name="cvd_button" value="protan">
<span class="material-icons">filter_1</span>
<span class="radio-label"> Protanopic</span>
</label>
<label class="radio-option" title="Deuteranopic">
<input type="radio" name="cvd_button" value="deutan">
<span class="material-icons">filter_2</span>
<span class="radio-label"> Deuteranopic</span>
</label>
<label class="radio-option" title="Tritananopic">
<input type="radio" name="cvd_button" value="tritan">
<span class="material-icons">filter_3</span>
<span class="radio-label"> Tritanopic</span>
</label>
</form>

## Perceptual Lightness

<canvas class="linearity-chart cmap-chart" data-cmap-name="{name}" width="800" height="350"></canvas>
Expand All @@ -53,6 +76,19 @@

<script>
window.cmap_data = {data};

cvd?.addEventListener("change", (e) => {{
const selected = cvd.querySelector('input[name="cvd_button"]:checked')?.value;
//window.cmap_data = {data}[selected];
console.log("CVD type selected:", selected);
// re-render the charts
initCharts();

console.log("Selected variant:", selected);
}});



<!-- Note: this is here because of `navigation.instant` in the mkdocs settings -->
typeof(initCharts) !== 'undefined' && initCharts();
</script>
Expand Down Expand Up @@ -111,11 +147,13 @@ def build_catalog(catalog: "_catalog.Catalog") -> None:
# write data used for charts
cm = Colormap(name)
cmap_data = {
k: np.around(v, 4).tolist() if isinstance(v, np.ndarray) else v
for k, v in report(cm).items()
if k in INCLUDE_DATA
cvd_type: {
k: np.around(v, 4).tolist() if isinstance(v, np.ndarray) else v
for k, v in report.items()
if k in INCLUDE_DATA
}
for cvd_type, report in report_cvds(cm).items()
}

_aliases = [x for x in info.aliases if x != info.name]
aliases = _make_aliases_md(_aliases) if _aliases else ""

Expand Down
8 changes: 7 additions & 1 deletion docs/javascripts/cmap_charts.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,20 @@ async function initCharts() {
chartElems[cmap_name] = [charts[i]];
}
}
var cvd_type = document.getElementById("cvd").querySelector('input[name="cvd_button"]:checked')?.value;
// Make all charts for each cmap name
for (var cmap_name in chartElems) {
// NOTE: we're using a global window variable here that will be
// injected into the _gen_cmaps page... because it's much faster
// on readthedocs than making an additional fetch request
var cmap_data = window.cmap_data[cmap_name];
var cmap_data = window.cmap_data[cmap_name][cvd_type] || window.cmap_data[cmap_name]["normal"];
for (var i = 0; i < chartElems[cmap_name].length; i++) {
var canv = chartElems[cmap_name][i];
const chart = Chart.getChart(canv);
if (chart) {
chart.destroy();
}

if (canv.classList.contains("rgb-chart")) {
makeRGBChart(canv, cmap_data);
} else if (canv.classList.contains("hsl-chart")) {
Expand Down
46 changes: 46 additions & 0 deletions docs/stylesheets/extra.css
Original file line number Diff line number Diff line change
Expand Up @@ -176,3 +176,49 @@ body[data-md-color-scheme="slate"] .btn.active {
#readthedocs-ea, .ethical-alabaster {
display: none;
}

.radio-group {
display: flex;
gap: 1rem;
margin-bottom: 1rem;
}

.radio-option {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0.5em;
border-radius: 0.5em;
cursor: pointer;
transition: background-color 0.2s, box-shadow 0.2s;
}

.radio-option input[type="radio"] {
appearance: none;
position: absolute;
opacity: 0;
pointer-events: none;
}

.radio-option .material-icons {
font-size: 1rem;
color: var(--md-default-fg-color);
transition: color 0.2s;
}

.radio-option input[type="radio"]:checked ~ .material-icons,
.radio-option input[type="radio"]:checked ~ .radio-label {
color: var(--md-accent-fg-color);
}


.radio-option:hover {
background-color: var(--md-default-bg-color--lighter);
box-shadow: 0 0 0 2px var(--md-accent-fg-color);
}

.radio-option .radio-label {
font-size: 0.65rem;
color: var(--md-default-fg-color);
}
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ plugins:
summary: true

extra_css:
- https://fonts.googleapis.com/icon?family=Material+Icons
- stylesheets/extra.css

extra_javascript:
Expand Down
59 changes: 58 additions & 1 deletion src/cmap/_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -446,13 +446,27 @@
lightness_derivs: np.ndarray


def report(cm: Colormap, n: int = 256, uniform_space: str = "CAM02-UCS") -> ReportDict:
class CVDReportDict(TypedDict):
normal: ReportDict
protan: ReportDict
deutan: ReportDict
tritan: ReportDict


def report(
cm: Colormap,
n: int = 256,
uniform_space: str = "CAM02-UCS",
initial_space: dict | None = None,
) -> ReportDict:
"""Generate a report of data describing a colormap.

This is primarily used for generating charts in the documentation
"""
from colorspacious import cspace_convert

if initial_space is None:
initial_space = {"name": "sRGB1"}
if len(cm.color_stops) >= 100:
RGBA = np.asarray(cm.color_stops.color_array)
n = RGBA.shape[0]
Expand All @@ -462,6 +476,7 @@
RGBA = cm(x)
RGB = RGBA[:, :3]

RGB = np.clip(cast("np.ndarray", cspace_convert(RGB, initial_space, "sRGB1")), 0, 1)
Jab = cast("np.ndarray", cspace_convert(RGB, "sRGB1", uniform_space))

local_deltas = np.sqrt(np.sum((Jab[:-1, :] - Jab[1:, :]) ** 2, axis=-1))
Expand Down Expand Up @@ -504,6 +519,48 @@
# H -> hue composition


def report_cvds(
cm: Colormap, n: int = 256, uniform_space: str = "CAM02-UCS"
) -> CVDReportDict:
"""Generate a report of data describing a colormap for different CVD types.

This is primarily used for generating charts in the documentation
"""
return {

Check warning on line 529 in src/cmap/_util.py

View check run for this annotation

Codecov / codecov/patch

src/cmap/_util.py#L529

Added line #L529 was not covered by tests
"normal": report(cm, n=n, uniform_space=uniform_space),
"protan": report(
cm,
n=n,
uniform_space=uniform_space,
initial_space={
"name": "sRGB1+CVD",
"cvd_type": "protanomaly",
"severity": 100,
},
),
"deutan": report(
cm,
n=n,
uniform_space=uniform_space,
initial_space={
"name": "sRGB1+CVD",
"cvd_type": "deuteranomaly",
"severity": 100,
},
),
"tritan": report(
cm,
n=n,
uniform_space=uniform_space,
initial_space={
"name": "sRGB1+CVD",
"cvd_type": "tritanomaly",
"severity": 100,
},
),
}


def to_mpl(
value: ColorStopsLike,
/,
Expand Down