color_tools.filament_palette

Filament palette management for 3D printing color matching.

This module provides classes and functions for managing 3D printing filament databases, with support for: - Maker-based filtering and synonym resolution - Material type and finish filtering (PLA, PETG, Matte, Glossy, etc.) - Color distance matching with multiple metrics - Owned filaments tracking for personalized recommendations - User extensions via user-filaments.json

The FilamentPalette class offers indexed lookups (O(1)) for maker/type/finish filtering, followed by perceptually accurate nearest-neighbor searches in LAB color space.

class color_tools.filament_palette.FilamentRecord(id, maker, type, finish, color, hex, td_value=None, other_names=None, source='unknown.json')[source]

Bases: object

Immutable record representing a 3D printing filament.

Filament colors are pre-computed in all major color spaces for fast matching. Original hex text and ordered RGB components are retained. The current multi-color mode resolves RGB/LAB once at construction, not on later reads.

The other_names field allows for alternative color names that can be used to find this filament.

The source field tracks which JSON file this filament came from (‘filaments.json’ for core data, ‘user-filaments.json’ for user additions). User records replace system records only when their stable IDs match. Different filament records may share an RGB value.

Parameters:
  • id (str) – Unique identifier for this filament (e.g., “bambu-lab-pla-matte-jet-black”)

  • maker (str) – Manufacturer name (e.g., “Bambu Lab”)

  • type (str) – Material type (e.g., “PLA”, “PETG”, “ABS”)

  • finish (Optional[str]) – Surface finish (e.g., “Matte”, “Glossy”, “Silk”). Optional.

  • color (str) – Human-readable color name (e.g., “Jet Black”)

  • hex (str) – Original single or compound hex text. Components may be separated by hyphen, space, comma, underscore, slash, colon, or semicolon. CSS/PNG RGBA alpha is allowed but dropped from RGB components.

  • td_value (Optional[float]) – Transmission-distance value when available. Values are not normalized percentages. Optional.

  • other_names (Optional[List[str]]) – Alternative names this filament is known by. Optional.

  • source (str) – Source JSON file this record came from (auto-set during loading)

id: str
maker: str
type: str
finish: Optional[str]
color: str
hex: str
td_value: Optional[float] = None
other_names: Optional[List[str]] = None
source: str = 'unknown.json'
__post_init__()[source]

Compute derived color representations in all color spaces.

Return type:

None

rgb: Tuple[int, int, int]
lab: Tuple[float, float, float]
rgb_components: tuple[tuple[int, int, int], ...]
property effective_hex: str

Normalized single-color hex derived from the captured effective RGB.

to_swatch_png(*, width=64, height=64, mode='solid')[source]

Render a dependency-free PNG swatch for this filament.

Solid output uses the captured effective RGB. Blocks and gradients use the immutable source components in their original order without reading the current ambient multi-color configuration.

Return type:

bytes

Parameters:
  • width (int)

  • height (int)

  • mode (Literal['solid', 'blocks', 'gradient'])

save_swatch_png(path, *, width=64, height=64, mode='solid')[source]

Save a PNG swatch, create parent directories, and return its Path.

Return type:

Path

Parameters:
__str__()[source]

Return a human-readable string representation of the filament.

Return type:

str

color_tools.filament_palette.load_filaments(json_path=None, *, include_report=False)[source]

Load and merge filaments, optionally returning structured changes.

Overloads:
Parameters:
Return type:

List[FilamentRecord] | tuple[List[FilamentRecord], FilamentLoadReport]

A user record with an existing ID replaces that complete system record. Duplicate colors and product descriptions are allowed; IDs alone define record identity. The effective records are returned in canonical case-insensitive maker, type, finish, color, and ID order.

color_tools.filament_palette.load_maker_synonyms(json_path=None, *, include_report=False)[source]

Load additive, case-insensitive maker synonyms with reporting.

Overloads:
Parameters:
Return type:

Dict[str, List[str]] | tuple[Dict[str, List[str]], SynonymLoadReport]

Maker keys must identify a maker in the merged filament database. Synonyms are globally unique after case folding, cannot duplicate a canonical maker name, and never remove bundled synonyms.

color_tools.filament_palette.get_canonical_filament_name(maker, type_name, finish, color, hex_value)[source]

Return the canonical human-readable display name for a filament.

The format is "{maker} {type}[ {finish}] - {color} ({hex})". The finish and its preceding space are omitted when finish is None or empty. Input values are otherwise preserved unchanged.

This function does not perform any validation or normalization of the input values; it simply formats them into the canonical display name. Those responsibilities lie with the caller.

Parameters:
  • maker (str) – Filament manufacturer.

  • type_name (str) – Filament material or type.

  • finish (str | None) – Optional filament finish.

  • color (str) – Filament color name.

  • hex_value (str) – Original hexadecimal color value.

Return type:

str

Returns:

The formatted filament display name.

color_tools.filament_palette.load_owned_filaments(json_path=None)[source]

Load owned filament IDs from JSON file.

Loads a list of filament IDs that the user owns from owned-filaments.json. This file is optional - if it doesn’t exist, an empty set is returned.

The JSON format is:

{
    "owned_filaments": ["id1", "id2", "id3"]
}
Parameters:

json_path (Path | str | None) – Path to directory containing owned-filaments.json, or path to specific owned filaments JSON file. If None, looks for owned-filaments.json in the package’s data/ directory.

Return type:

Set[str]

Returns:

Set of canonical owned filament IDs (empty set if file doesn’t exist).

Raises:

ValueError – If the document shape or any owned filament ID is invalid.

color_tools.filament_palette.save_owned_filaments(owned_ids, json_path=None)[source]

Save owned filament IDs to JSON file.

Saves the list of owned filament IDs to owned-filaments.json.

Parameters:
  • owned_ids (Set[str]) – Set of filament IDs to save

  • json_path (Path | str | None) – Path to directory for owned-filaments.json, or path to specific file. If None, saves to package’s data/ directory.

Return type:

None

class color_tools.filament_palette.FilamentPalette(records, maker_synonyms=None, owned_filaments=None)[source]

Bases: object

Filament palette with multiple indexing strategies for fast lookup.

Similar to Palette, but designed for 3D printing filaments which have additional properties (maker, type, finish) that we want to search by.

The indices allow for fast filtering: “Show me all Bambu Lab PLA Matte filaments” becomes a simple dictionary lookup instead of scanning the whole list! 📇

Supports maker synonyms: you can search for “Bambu” and it will find “Bambu Lab” filaments automatically.

Parameters:
  • records (List[FilamentRecord])

  • maker_synonyms (Optional[Dict[str, List[str]]])

  • owned_filaments (Optional[Set[str]])

maker_synonyms: Dict[str, List[str]]
owned_filaments: Set[str]
classmethod load_default(json_path=None)[source]

Load the default filament palette from the package data.

Convenience method for quick loading without worrying about paths. Also loads maker synonyms and owned filaments automatically.

Auto-detects owned filaments: If owned-filaments.json exists and contains IDs, owned filtering will be the default behavior in filter/nearest methods.

Parameters:

json_path (Path | str | None) – Optional custom data directory containing the system and user JSON files.

Return type:

FilamentPalette

find_by_maker(maker)[source]

Find all filaments by a single maker or a list of makers.

Supports synonyms: searching for “Bambu” will find “Bambu Lab” filaments.

Parameters:

maker (Union[str, List[str]]) – A single maker name (str) or a list of names (can use synonyms).

Return type:

List[FilamentRecord]

Returns:

A list of all matching FilamentRecord objects.

find_by_type(type_name)[source]

Find all filaments by a single type or a list of types.

Parameters:

type_name (Union[str, List[str]]) – A single filament type (str) or a list of types.

Return type:

List[FilamentRecord]

Returns:

A list of all matching FilamentRecord objects.

find_by_color(color)[source]

Find all filaments by color name (case-insensitive).

Return type:

List[FilamentRecord]

Parameters:

color (str)

find_by_rgb(rgb)[source]

Find all filaments by exact RGB match, with user filaments prioritized.

Return type:

List[FilamentRecord]

Parameters:

rgb (Tuple[int, int, int])

find_by_finish(finish)[source]

Find all filaments by a single finish or a list of finishes.

Parameters:

finish (Union[str, List[str]]) – A single filament finish (str) or a list of finishes.

Return type:

List[FilamentRecord]

Returns:

A list of all matching FilamentRecord objects.

filter(maker=None, type_name=None, finish=None, color=None, owned=None, has_td=None)[source]

Filter filaments by multiple criteria.

This is like SQL WHERE clauses! Start with all records, then filter down by each criterion that’s provided. Maker, type, and finish can accept a single string or a list of strings.

Supports maker synonyms: filtering by “Bambu” will include “Bambu Lab”.

Auto-detects owned filtering: If owned-filaments.json exists with IDs, defaults to owned filaments only unless owned=False is explicitly passed.

Parameters:
  • maker (Union[str, List[str], None]) – A maker name or list of maker names (can use synonyms).

  • type_name (Union[str, List[str], None]) – A filament type or list of types.

  • finish (Union[str, List[str], None]) – A filament finish or list of finishes.

  • color (Optional[str]) – A single color name to match (case-insensitive).

  • owned (Optional[bool]) – Filter to owned filaments only. None (default) = auto-detect, True = owned only, False = all filaments.

  • has_td (bool | None) – True selects records with TD values, False selects records without TD values, and None does not filter by TD.

Return type:

List[FilamentRecord]

Returns:

A list of FilamentRecord objects matching the criteria.

filter_by_criteria(include=None, exclude=None, *, owned=None)[source]

Filter filaments with reusable inclusion and exclusion criteria.

Active fields within each criterion use AND semantics, while multiple values within a field use OR semantics. An exclusion removes a record only when the complete exclusion criterion matches.

Return type:

list[FilamentRecord]

Parameters:
nearest_filament(target_rgb, metric='de2000', *, maker=None, type_name=None, finish=None, owned=None, cmc_l=2.0, cmc_c=1.0, max_hue_delta=None)[source]

Find nearest filament by color similarity, with optional filters.

The killer feature for 3D printing! “I want this exact color… what filament should I buy?” 🎨🖨️

Auto-detects owned filtering: If owned-filaments.json exists with IDs, defaults to searching owned filaments only unless owned=False is explicitly passed.

Parameters:
  • target_rgb (Tuple[int, int, int]) – Target RGB color tuple.

  • metric (str) – Distance metric - ‘euclidean’, ‘de76’, ‘de94’, ‘de2000’, ‘cmc’.

  • maker (Union[str, List[str], None]) – Optional maker name or list of names to filter by. Use “*” to ignore filter.

  • type_name (Union[str, List[str], None]) – Optional filament type or list of types to filter by. Use “*” to ignore filter.

  • finish (Union[str, List[str], None]) – Optional filament finish or list of finishes to filter by. Use “*” to ignore filter.

  • owned (Optional[bool]) – Filter to owned filaments only. None (default) = auto-detect, True = owned only, False = all filaments.

  • cmc_l (float) – Parameters for CMC metric.

  • cmc_c (float) – Parameters for CMC metric.

  • max_hue_delta (Optional[float]) – Maximum allowed hue angle difference in degrees (LCH hue, 0-180). Filters out candidates whose hue differs by more than this amount. Achromatic targets (chroma < 5) skip hue filtering automatically. Example: 30.0 keeps results within the same hue family.

Return type:

Tuple[FilamentRecord, float]

Returns:

(nearest_filament_record, distance) tuple.

nearest_filaments(target_rgb, metric='de2000', count=5, *, maker=None, type_name=None, finish=None, owned=None, cmc_l=2.0, cmc_c=1.0, max_hue_delta=None)[source]

Find nearest N filaments by color similarity, with optional filters.

Similar to nearest_filament but returns multiple results sorted by distance.

Auto-detects owned filtering: If owned-filaments.json exists with IDs, defaults to searching owned filaments only unless owned=False is explicitly passed.

Parameters:
  • target_rgb (Tuple[int, int, int]) – Target RGB color tuple.

  • metric (str) – Distance metric - ‘euclidean’, ‘de76’, ‘de94’, ‘de2000’, ‘cmc’.

  • count (int) – Number of results to return (default: 5, max: 50)

  • maker (Union[str, List[str], None]) – Optional maker name or list of names to filter by. Use “*” to ignore filter.

  • type_name (Union[str, List[str], None]) – Optional filament type or list of types to filter by. Use “*” to ignore filter.

  • finish (Union[str, List[str], None]) – Optional filament finish or list of finishes to filter by. Use “*” to ignore filter.

  • owned (Optional[bool]) – Filter to owned filaments only. None (default) = auto-detect, True = owned only, False = all filaments.

  • cmc_l (float) – Parameters for CMC metric.

  • cmc_c (float) – Parameters for CMC metric.

  • max_hue_delta (Optional[float]) – Maximum allowed hue angle difference in degrees (LCH hue, 0-180). Filters out candidates whose hue differs by more than this amount. Achromatic targets (chroma < 5) skip hue filtering automatically. Example: 30.0 keeps results within the same hue family.

Return type:

List[Tuple[FilamentRecord, float]]

Returns:

List of (filament_record, distance) tuples sorted by distance (closest first).

nearest_filament_by_criteria(target_rgb, metric='de2000', *, include=None, exclude=None, owned=None, cmc_l=2.0, cmc_c=1.0, max_hue_delta=None)[source]

Find the nearest filament using reusable inclusion and exclusion criteria.

Return type:

tuple[FilamentRecord, float]

Parameters:
nearest_filaments_by_criteria(target_rgb, metric='de2000', count=5, *, include=None, exclude=None, owned=None, cmc_l=2.0, cmc_c=1.0, max_hue_delta=None)[source]

Find the nearest filaments using reusable inclusion and exclusion criteria.

Return type:

list[tuple[FilamentRecord, float]]

Parameters:
property makers: List[str]

Get sorted list of all makers.

property types: List[str]

Get sorted list of all types.

property finishes: List[str]

Get sorted list of all finishes.

get_filament_by_id(filament_id)[source]

Get a filament by its ID.

Parameters:

filament_id (str) – Filament ID to look up

Return type:

Optional[FilamentRecord]

Returns:

FilamentRecord if found, None otherwise

list_owned()[source]

Get list of all owned filament records.

Return type:

List[FilamentRecord]

Returns:

List of FilamentRecord objects that are marked as owned (sorted by maker, type, color)

add_owned(filament_id, json_path=None)[source]

Add a filament ID to the owned list and save to file.

Parameters:
  • filament_id (str) – Filament ID to add

  • json_path (Path | str | None) – Optional path to owned-filaments.json file (uses default if None)

Raises:

ValueError – If the filament ID doesn’t exist in the database

Return type:

None

remove_owned(filament_id, json_path=None)[source]

Remove a filament ID from the owned list and save to file.

Parameters:
  • filament_id (str) – Filament ID to remove

  • json_path (Path | str | None) – Optional path to owned-filaments.json file (uses default if None)

Raises:

ValueError – If the filament ID is not in the owned list

Return type:

None

save_owned(json_path=None)[source]

Save the current owned filaments list to file.

Useful after programmatic modifications to owned_filaments set.

Parameters:

json_path (Path | str | None) – Optional path to owned-filaments.json file (uses default if None)

Return type:

None