renoir

July 29, 2026 · View on GitHub

A computational tool for analyzing artist-specific works from WikiArt with comprehensive color analysis capabilities. Designed for teaching computational color theory and data analysis to art and design students through culturally meaningful examples.

DOI License: MIT Python 3.9+ PyPI PyPI Downloads Tests Documentation Mentioned in Awesome Digital Humanities

Overview

renoir is a pedagogical Python package for computational color analysis of artworks from WikiArt. Its primary contributions are four interpretable metrics designed for art-historical reasoning: Palette Earth Mover's Distance for perceptual palette comparison, Color Complexity Index combining information-theoretic and perceptual measures, Historical Pigment Probability for dating-aware Bayesian pigment attribution, and Color Provenance Score for detecting anachronistic palettes. These sit alongside a complete 17-lesson curriculum, four color naming vocabularies, and a PromptGenerator module for generative AI workflows, designed to take art and design students from k-means basics through machine learning using a culturally meaningful dataset.

Key Features

Artist analysis

  • Extract and analyze works by 100+ artists from WikiArt
  • Built-in visualizations for genre and style distributions
  • Temporal analysis of artistic development
  • Comparative analysis across artists and movements

Advanced color metrics

  • Palette Earth Mover's Distance (PEMD): Perceptual optimal-transport distance between palettes using CIEDE2000 as ground metric
  • Color Complexity Index (CCI): Information-theoretic measure combining hue entropy, perceptual spread, proportion evenness, and harmony
  • Historical Pigment Probability (HPP): Bayesian estimation of which historical pigments could produce a given color at a given date
  • Color Provenance Score (CPS): Anomaly detection for anachronistic palettes in art-historical attribution
  • Cross-vocabulary color translation: Map color names across Werner's, artist pigments, Resene, and XKCD vocabularies via CIEDE2000
  • GenAI color prompt generation: Convert color analysis into structured prompts for DALL-E, Midjourney, and Stable Diffusion

Color analysis

  • Color extraction: K-means clustering for intelligent palette extraction; also supports DSP (Distinctness-First Palette Selection) for perceptually maximally distinct palettes with guaranteed WCAG AA contrast
  • Color naming: Evocative, artist-friendly color names (Burnt Sienna, Prussian Blue, etc.)
    • 4 naming vocabularies: artist pigments, Resene, Werner's, XKCD
    • CIEDE2000 perceptually accurate color matching
    • Color Index names for physical paint matching
  • Color space analysis: RGB, HSV, and HSL conversions
  • Statistical metrics: Color diversity, saturation, brightness, temperature
  • Color relationships: Complementary detection, WCAG contrast ratios
  • Color harmony detection: Triadic, analogous, split-complementary, tetradic schemes
  • 8 visualization types: Palettes, color wheels, distributions, 3D spaces
  • Export capabilities: CSS variables and JSON formats

Educational focus

  • 17 complete Jupyter notebooks -- Progressive curriculum from basics to advanced ML
  • Designed specifically for classroom use and student projects
  • Publication-ready visualizations
  • WikiArt cheatsheet for quick reference
  • Pure Python with minimal dependencies

Applications

  • Creative Coding Courses: Teach programming through culturally meaningful datasets
  • Computational Color Theory: Bridge traditional color theory with data science
  • Art and Design Research: Quantitative analysis of visual patterns and influences
  • Computational Design: Explore historical precedents through data-driven methods
  • Digital Humanities: Generate publication-ready visualizations for academic work

Installation

Basic Installation

pip install renoir-wikiart
pip install 'renoir-wikiart[visualization]'

With CLI Support

pip install 'renoir-wikiart[cli]'

From Source

git clone https://github.com/MichailSemoglou/renoir.git
cd renoir
pip install -e .[visualization]

Quick Start

Basic Artist Analysis

from renoir import quick_analysis

# Text-based analysis
quick_analysis('pierre-auguste-renoir')

# With visualizations
quick_analysis('pierre-auguste-renoir', show_plots=True)

Color Palette Extraction

from renoir import ArtistAnalyzer
from renoir.color import ColorExtractor, ColorVisualizer

# Get artist's works
analyzer = ArtistAnalyzer()
works = analyzer.extract_artist_works('claude-monet', limit=10)

# Extract color palette
extractor = ColorExtractor()
colors = extractor.extract_dominant_colors(works[0]['image'], n_colors=5)

# Visualize with evocative names
visualizer = ColorVisualizer()
visualizer.plot_palette(colors, title="Monet's Palette", show_names=True, vocabulary="artist")

Accessible Palette Extraction (DSP)

from renoir.color import ColorExtractor

extractor = ColorExtractor()

# Extract a perceptually distinct palette with guaranteed WCAG AA contrast
colors = extractor.extract_dominant_colors(works[0]['image'], n_colors=5, method="dsp")

# Or use DSP directly for full metadata
from renoir.color.dsp import select_palette, assign_roles
result = select_palette(works[0]['image'], n=5)
roles = assign_roles(result.palette_rgb, result.palette_lab, result.frequencies)
print(f"WCAG AA guaranteed: {result.wcag_guaranteed}")
print(f"Surface color: {result.palette_rgb[roles.surface]}")

Color Naming

from renoir.color import ColorNamer

namer = ColorNamer(vocabulary="artist")

# Name a single color
name = namer.name((255, 87, 51))
print(name)  # "Burnt Sienna"

# Get detailed information including Color Index name
result = namer.name((0, 49, 83), return_metadata=True)
print(f"{result['name']} ({result['ci_name']})")  # "Prussian Blue (PB27)"

# Find closest physical pigment for digital-to-physical matching
pigment = namer.closest_pigment((100, 150, 220))
print(f"Paint with: {pigment['name']} ({pigment['ci_name']})")

Color Analysis

from renoir.color import ColorAnalyzer

analyzer = ColorAnalyzer()

# Analyze palette statistics
stats = analyzer.analyze_palette_statistics(colors)
print(f"Mean Saturation: {stats['mean_saturation']:.1f}%")
print(f"Mean Brightness: {stats['mean_value']:.1f}%")

# Calculate color diversity
diversity = analyzer.calculate_color_diversity(colors)
print(f"Color Diversity: {diversity:.3f}")

# Analyze color temperature
temp = analyzer.analyze_color_temperature_distribution(colors)
print(f"Warm: {temp['warm_percentage']:.1f}%")
print(f"Cool: {temp['cool_percentage']:.1f}%")

# Detect color harmonies
harmony = analyzer.analyze_color_harmony(colors)
print(f"Harmony Score: {harmony['harmony_score']:.2f}")
print(f"Dominant harmony: {harmony['dominant_harmony']}")

Jupyter Notebooks - Complete 17-Lesson Curriculum

All notebooks are in examples/color_analysis/:

Fundamentals (Lessons 1-3)

  1. 01_color_palette_extraction.ipynb - Introduction to k-means clustering through art
  2. 02_color_space_analysis.ipynb - Understanding RGB vs HSV color spaces
  3. 03_comparative_artist_analysis.ipynb - Comparing artistic movements statistically

Intermediate (Lessons 4-6)

  1. 04_artist_color_signature.ipynb - Identifying unique color signatures of artists
  2. 05_color_harmony_principles.ipynb - Advanced color harmony detection and analysis
  3. 06_thematic_color_analysis.ipynb - Analyzing portraits, landscapes, and still life

Advanced (Lessons 7-11)

  1. 07_color_analysis_pipeline.ipynb - Building a complete analysis workflow from scratch
  2. 08_movement_color_evolution.ipynb - Tracing color evolution across art movements
  3. 09_color_psychology.ipynb - Exploring emotional associations of colors in art
  4. 10_style_classifier.ipynb - Building a ML classifier with color features
  5. 11_color_naming.ipynb - Evocative color naming with artist pigments, XKCD, Werner's, and Resene vocabularies

Deep Learning & Embeddings (Lessons 12-16)

  1. 12_art_movement_classification.ipynb - Movement classification with SHAP explainability
  2. 13_palette_generation_vae.ipynb - Variational Autoencoder palette generation
  3. 14_artist_color_dna.ipynb - Artist similarity and color DNA embeddings
  4. 15_clustering_anomaly_detection.ipynb - Unsupervised learning for art analysis
  5. 16_temporal_artist_evolution.ipynb - Tracking artist palette evolution over time

Capstone (Lesson 17)

  1. 17_capstone_project.ipynb - Complete AI-powered art intelligence platform

Documentation

  • WikiArt Cheatsheet - Quick reference for all API methods, common artists, genres, styles, and code snippets

Advanced Color Metrics: Examples

Palette Comparison (PEMD)

from renoir.color import ColorAnalyzer

analyzer = ColorAnalyzer()

# Two palettes as (color, proportion) pairs
palette1 = [((255, 87, 51), 0.4), ((0, 49, 83), 0.6)]
palette2 = [((240, 90, 55), 0.5), ((10, 55, 90), 0.5)]

distance = analyzer.palette_earth_movers_distance(palette1, palette2)
print(f"Perceptual palette distance: {distance:.2f}")

Color Complexity Index

colors = [(255, 87, 51), (0, 49, 83), (34, 139, 34), (255, 215, 0)]
proportions = [0.3, 0.3, 0.2, 0.2]

result = analyzer.calculate_color_complexity(colors, proportions=proportions)
print(f"Complexity Index: {result['cci']:.3f}")

Historical Pigment Probability

from renoir.color import ColorNamer

namer = ColorNamer(vocabulary="artist")

# What pigments could produce this blue in 1665 (Vermeer's era)?
pigments = namer.historical_pigment_probability((0, 49, 83), year=1665)
for p in pigments:
    print(f"{p['name']}: {p['probability']:.2%}")

Cross-Vocabulary Translation

namer = ColorNamer(vocabulary="artist")

# Translate an artist pigment name to XKCD vocabulary
result = namer.translate("Cadmium Yellow Light", to_vocabulary="xkcd")
print(result)  # Closest XKCD equivalents

# Translate across all vocabularies at once
all_translations = namer.translate_all_vocabularies("Prussian Blue")

Color Provenance Score

colors = [(0, 49, 83), (255, 215, 0), (139, 69, 19)]
score = analyzer.color_provenance_score(colors, year=1700)
print(f"Provenance score: {score['score']:.2f}")
print(f"Flagged: {score['flagged']}")

GenAI Color Prompts

from renoir.color import PromptGenerator

generator = PromptGenerator(vocabulary="artist")

colors = [(255, 87, 51), (0, 49, 83), (34, 139, 34)]
prompt = generator.generate(
    colors,
    style="impressionist",
    mood="serene",
    target_model="midjourney"
)
print(prompt)

# Generate variations
variations = generator.generate_variation_prompts(colors, n_variations=3)

Advanced Usage

Artist Work Extraction

from renoir import ArtistAnalyzer

analyzer = ArtistAnalyzer()

# Extract works by specific artist
works = analyzer.extract_artist_works('pierre-auguste-renoir')

# Analyze distributions
genres = analyzer.analyze_genres(works)
styles = analyzer.analyze_styles(works)

print(f"Found {len(works)} works")
print(f"Genres: {genres}")
print(f"Styles: {styles}")

Visualization Examples

# Single artist visualizations
analyzer.plot_genre_distribution('pierre-auguste-renoir')
analyzer.plot_style_distribution('pablo-picasso')

# Compare multiple artists
analyzer.compare_artists_genres(['claude-monet', 'pierre-auguste-renoir', 'edgar-degas'])

# Comprehensive overview
analyzer.create_artist_overview('vincent-van-gogh')

# Save to file
analyzer.plot_genre_distribution('monet', save_path='monet_genres.png')

Color Space Conversions

from renoir.color import ColorAnalyzer

analyzer = ColorAnalyzer()

# Convert RGB to HSV
hsv = analyzer.rgb_to_hsv((255, 87, 51))
print(f"HSV: Hue={hsv[0]:.0f}°, Sat={hsv[1]:.0f}%, Val={hsv[2]:.0f}%")

# Detect complementary colors
complementary = analyzer.detect_complementary_colors(colors)

# Detect triadic harmonies
triadic = analyzer.detect_triadic_harmony(colors)

# Detect analogous color groups
analogous = analyzer.detect_analogous_harmony(colors)

# Calculate contrast ratio
ratio = analyzer.calculate_contrast_ratio((255, 255, 255), (0, 0, 0))
print(f"Contrast ratio: {ratio:.2f}:1")

Advanced Color Visualizations

from renoir.color import ColorVisualizer

visualizer = ColorVisualizer()

# Color wheel visualization
visualizer.plot_color_wheel(colors)

# RGB distribution
visualizer.plot_rgb_distribution(colors)

# HSV distribution
visualizer.plot_hsv_distribution(colors)

# 3D color space
visualizer.plot_3d_rgb_space(colors)

# Compare two palettes
visualizer.compare_palettes(colors1, colors2, labels=("Artist 1", "Artist 2"))

# Comprehensive report
visualizer.create_artist_color_report(colors, "Claude Monet")

Export Color Palettes

from renoir.color import ColorExtractor

extractor = ColorExtractor()

# Export as CSS variables
extractor.export_palette_css(colors, 'palette.css', prefix='monet')

# Export as JSON
extractor.export_palette_json(colors, 'palette.json')

Portfolio Color Signature

from renoir import ArtistAnalyzer

analyzer = ArtistAnalyzer()

# Aggregated color signature across an artist's corpus
signature = analyzer.artist_color_signature('claude-monet', limit=10)

print(f"Analyzed {signature['n_works_selected']} of {signature['n_works_available']} works")
print(f"Strategy used: {signature['effective_strategy']}")
print(f"Signature palette: {signature['palette']}")
print(f"Dominant harmony: {signature['metrics']['harmony']['dominant_harmony']}")

# Per-period breakdown (available when works have date metadata)
for period, data in signature['by_period'].items():
    print(f"{period}s: {data['n_works']} works, CCI={data['metrics']['complexity']['cci']:.3f}")

Dataset Information

Uses the WikiArt dataset from HuggingFace:

  • Over 81,000 artworks
  • Works by 129 artists
  • Rich metadata including genre, style, and artist information

Requirements

Core Requirements

  • Python 3.9+
  • datasets >= 2.0.0
  • Pillow >= 10.3.0
  • numpy >= 1.20.0
  • scikit-learn >= 1.0.0
  • pandas >= 1.3.0
  • scipy >= 1.7.0 (for PEMD optimal transport)

Visualization Requirements (Optional)

  • matplotlib >= 3.5.0
  • seaborn >= 0.11.0

Install with: pip install 'renoir-wikiart[visualization]'

Educational Philosophy

renoir is built on these pedagogical principles:

  1. Cultural Relevance: Uses art history to teach computational concepts
  2. Progressive Complexity: From simple function calls to advanced ML
  3. Visual Learning: Students see immediate, meaningful results
  4. Real Data: Works with actual cultural heritage data, not toy examples
  5. Extensible: Students can fork and extend for their own projects

API Overview

Artist Analysis

  • ArtistAnalyzer - Main class for artist work extraction and analysis
  • quick_analysis() - Convenience function for quick exploration

Color Analysis

  • ColorExtractor - Extract color palettes using k-means clustering
  • ColorAnalyzer - Analyze colors across multiple color spaces (includes PEMD, CCI, CPS)
  • ColorNamer - Perceptual color naming, cross-vocabulary translation, historical pigment probability
  • ColorVisualizer - Create publication-quality color visualizations
  • PromptGenerator - Generate structured color prompts for generative AI models

Citation

If you use this software in your research or teaching, please cite:

@software{semoglou2026renoir,
  author = {Semoglou, Michail},
  title = {renoir: A Python Tool for Analyzing Artist-Specific Works from WikiArt},
  year = {2026},
  version = {3.8.0},
  doi = {10.5281/zenodo.17355170},
  url = {https://github.com/MichailSemoglou/renoir}
}

Contributing

Contributions are welcome, especially:

  • Additional pedagogical examples
  • Classroom exercises and assignments
  • Educational notebooks
  • Documentation improvements
  • Bug fixes

See CONTRIBUTING.md for details.

License

MIT License - see LICENSE file for details.

Acknowledgments

  • WikiArt dataset creators
  • HuggingFace Datasets library
  • Students at Tongji University, College of Design and Innovation, whose feedback shaped this tool

Contact

For questions about using this tool in your classroom or research:

What's New

See CHANGELOG.md for the full version history.