Metadata-Version: 2.4
Name: ishihara
Version: 0.1.0
Summary: Generate pseudoisochromatic (Ishihara-style) colour vision plates. Reproducible from a seed, no dependencies.
Author-email: Vincent Gonzalez <vincegonzalez@me.com>
License: MIT
Project-URL: Homepage, https://github.com/vince-gonzalez/ishihara
Project-URL: Source, https://github.com/vince-gonzalez/ishihara
Keywords: ishihara,colorblind,color-blindness,colour vision,pseudoisochromatic,accessibility,a11y,vision science,protanopia,deuteranopia,tritanopia,svg
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Visualization
Classifier: Topic :: Multimedia :: Graphics
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: check
Requires-Dist: opticquiz-cvd>=1.1; extra == "check"
Dynamic: license-file

# ishihara

Generate pseudoisochromatic colour vision plates — a figure hidden in a field of
dots, readable only if you can separate two hues. No dependencies, output is
SVG, and every plate is a pure function of its seed.

```
pip install ishihara
```

```python
from ishihara import generate

generate("74", axis="rg", seed=1).save_svg("plate.svg")
```

```
ishihara 74 --axis rg --seed 1 -o plate.svg
ishihara --set --seed 100 -o plates/
```

Three axes: `rg` (red-green), `tritan` (blue-yellow), and `control`, which
separates figure from ground by lightness alone and is therefore readable by
every vision type including total colour blindness.

## Why the dots

The dots are the mechanism, not decoration. Varying their size and lightness
strips out every cue except hue, so the figure cannot be found by shape, edge or
brightness. Packing is dart-throwing against a spatial hash rather than a
lattice, because a regular grid gives the eye a texture to lock onto, and each
dot draws its colour from a *range* rather than a fixed value — a figure painted
one flat colour reads as a shape with an edge.

## The seed

Plates in the wild are generated with an unseeded random number generator, which
is fine for a screening tool and useless for anything you have to reproduce.
Passing `seed` makes the plate deterministic: same seed, same dots, same
colours, forever. Omit it and you get a different plate every call.

## A palette can be wrong in a way that looks right

The tritan palette here replaced one that measured **52.0 degrees off the tritan
confusion axis**. It separated figure from ground *across* the confusion line
instead of along it: mean ΔE2000 of 35.1 to normal vision and 52.4 under tritan
simulation. A tritan viewer saw the digit **more** clearly than someone with
typical colour vision — the plate scored backwards, and it looked completely
normal to the eye.

The pair now shipped is cyan on green: 33.5 to normal vision, 9.0 under tritan
(below the collapse threshold), 37.0 under deutan, so it does not accidentally
screen red-green as well.

That is the argument for measuring plates rather than choosing them. If you
build your own palette, measure it against the confusion axis before trusting
it.

## Custom figures

Digits `0`–`9` ship as bitmap glyphs, so there is no font dependency. Anything
else goes in as a mask — a callable taking pixel coordinates and returning
whether that point is inside the figure:

```python
from ishihara import generate

def circle(x, y):
    return (x - 350) ** 2 + (y - 350) ** 2 < 120 ** 2

generate(mask=circle, axis="rg", seed=7).save_svg("dot.svg")
```

## Checking a plate

For simulating colour vision deficiency, measuring ΔE2000 between two colours,
and testing whether a palette survives protan, deutan and tritan, see
[`opticquiz-cvd`](https://pypi.org/project/opticquiz-cvd/), which this package
lists as an optional extra:

```
pip install "ishihara[check]"
```

## What this is not

Not a diagnostic. A generated plate set screens; it does not diagnose, and a
result from a screen belongs with an optometrist rather than in a conclusion.
Display calibration, ambient light and screen gamut all move the answer, and
none of them are controlled here.

## Licence

MIT.
