Metadata-Version: 2.4
Name: colorreg
Version: 0.1.0
Summary: Persistent color assignment for categorical keys
Author-email: Matthew Neil <matthewneiluk@gmail.com>
License: MIT
Requires-Python: >=3.11
Requires-Dist: matplotlib
Requires-Dist: platformdirs
Requires-Dist: tomli-w
Description-Content-Type: text/markdown

# colorreg

A Python package for consistent color assignment across a project. `colorreg` maintains a persistent database of key-color mappings, ensuring that the same key always gets the same color — whether you're generating a plot today or six months from now.

## Installation

```bash
pip install colorreg
```

## Motivation

When working on projects with multiple scripts or notebooks, keeping colors consistent across figures is surprisingly tedious. You either hardcode color dicts in every script, or pass them around as variables. `colorreg` solves this by maintaining a persistent database of key-color mappings on your machine, so any script in your project can retrieve the same colors without any coordination.

## Quick Start

```python
import colorreg as cr

# Assign colors to a list of keys
color_dict = cr.get_colors(["sample_A", "sample_B", "control"])
# {"sample_A": "#1f77b4", "sample_B": "#ff7f0e", "control": "#2ca02c"}

# The same keys will always return the same colors
color_dict = cr.get_colors(["sample_A"])
# {"sample_A": "#1f77b4"}
```

## Database

`colorreg` stores its database in your system's user config directory:

| Platform | Path |
|----------|------|
| Linux/Mac | `~/.config/colorreg/colors.toml` |
| Windows | `C:\Users\<name>\AppData\Local\colorreg\colors.toml` |

The database is created automatically on first use. You can check its location at any time:

```python
cr.show_db_path()
# or capture the path
path = cr.show_db_path(return_path=True)
```

## Pre-populating the Database

If you want to start with a known set of mappings rather than letting `colorreg` assign them automatically, you can pre-populate the database using `add_key`:

```python
cr.add_key(color_dict_input={
    "control":  "#000000",
    "sample_A": "#1f77b4",
    "sample_B": "#ff7f0e",
})
```

Note that if a key already exists in the database, `add_key` will override it with the new color and print a warning.

## API

### Retrieving Colors

#### `get_colors(keys, novel_colors_only=False, db_path=None)`
Takes a string or list of strings and returns a dict mapping each key to a color. Keys seen before are assigned their stored color. New keys are assigned the first color from the palette not already in use by other keys in the same query.

```python
color_dict = cr.get_colors("sample_A")
color_dict = cr.get_colors(["sample_A", "sample_B", "control"])
```

Setting `novel_colors_only=True` ensures new keys are only assigned colors not present anywhere in the database, guaranteeing its uniqueness:

```python
color_dict = cr.get_colors(["sample_D"], novel_colors_only=True)
```

#### `get_new_color(unavailable=None, palette=None)`
Returns a single new color. If `unavailable` is provided, the returned color will not be in that set. Falls back to a random hex color if the palette is exhausted.

```python
color = cr.get_new_color()
color = cr.get_new_color(unavailable={"#1f77b4", "#ff7f0e"})
```

---

### Managing Keys

#### `add_key(key=None, color=None, color_dict_input=None, db_path=None)`
Add a single key-color pair or a dict of key-color pairs. Prints a warning if a key already exists and overrides it.

```python
cr.add_key(key="control", color="#000000")
cr.add_key(color_dict_input={"control": "#000000", "sample_A": "#ff0000"})
```

#### `modify_key(key=None, color=None, color_dict_input=None, db_path=None)`
Modify the color of an existing key or dict of keys. Raises a `KeyError` if the key does not exist.

```python
cr.modify_key(key="control", color="#ffffff")
cr.modify_key(color_dict_input={"control": "#ffffff", "sample_A": "#00ff00"})
```

#### `remove_key(key=None, keys=None, db_path=None)`
Remove a single key or a list of keys from the database. Raises a `KeyError` if a key does not exist.

```python
cr.remove_key(key="control")
cr.remove_key(keys=["control", "sample_A"])
```

#### `list_keys(db_path=None, return_dict=False)`
Print all key-color mappings currently stored in the database. Optionally return the mappings as a dict.

```python
cr.list_keys()
color_dict = cr.list_keys(return_dict=True)
```

---

### Database Management

#### `show_db_path(return_path=False)`
Print the path to the default database. Optionally return the path.

```python
cr.show_db_path()
path = cr.show_db_path(return_path=True)
```

#### `get_palette(db_path=None)`
Return the palette list currently stored in the database.

```python
palette = cr.get_palette()
```

#### `delete_db(db_path=None)`
Delete the database file and its parent directory. Use with caution — this is irreversible.

```python
cr.delete_db()
```

---

## Customisation

### Custom Database Path

By default `colorreg` uses a single database in your system config directory. If you want per-project databases, or simply want to store the database somewhere specific, pass a `db_path` to any function:

```python
# Retrieve colors from a custom database
color_dict = cr.get_colors(["sample_A"], db_path="./my_project_colors.toml")

# List keys in a custom database
cr.list_keys(db_path="./my_project_colors.toml")
color_dict = cr.list_keys(return_dict=True, db_path="./my_project_colors.toml")

# Add keys to a custom database
cr.add_key(key="control", color="#000000", db_path="./my_project_colors.toml")

# Remove keys from a custom database
cr.remove_key(key="control", db_path="./my_project_colors.toml")

# Delete a custom database entirely
cr.delete_db(db_path="./my_project_colors.toml")
```

If the file does not exist at that path, it will be created automatically with the default settings.

### Custom Palette

The palette is stored in the `[settings]` section of the database TOML and can be edited directly:

```toml
[settings]
palette = ["#ff0000", "#00ff00", "#0000ff"]
```

Note that changing the palette only affects future color assignments — existing key-color mappings in the database are not altered.

## Default Palette

`colorreg` ships with a broad default palette of colors drawn from several well-known color sets. New keys are assigned colors from this palette in order. Once the palette is exhausted, random hex colors are generated to ensure every key always receives a color.

## Dependencies

- [`platformdirs`](https://github.com/platformdirs/platformdirs)
- [`tomli_w`](https://github.com/hukkin/tomli-w)
- [`matplotlib`](https://matplotlib.org/)
- `tomllib` (stdlib, Python ≥ 3.11)

## Contributing

Bug reports and feature requests are welcome — please raise them on the associated [GitHub issues page](https://github.com/Mattn286/colorreg/issues).

## License

MIT