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.
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
With Visualization Support (Recommended)
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)
- 01_color_palette_extraction.ipynb - Introduction to k-means clustering through art
- 02_color_space_analysis.ipynb - Understanding RGB vs HSV color spaces
- 03_comparative_artist_analysis.ipynb - Comparing artistic movements statistically
Intermediate (Lessons 4-6)
- 04_artist_color_signature.ipynb - Identifying unique color signatures of artists
- 05_color_harmony_principles.ipynb - Advanced color harmony detection and analysis
- 06_thematic_color_analysis.ipynb - Analyzing portraits, landscapes, and still life
Advanced (Lessons 7-11)
- 07_color_analysis_pipeline.ipynb - Building a complete analysis workflow from scratch
- 08_movement_color_evolution.ipynb - Tracing color evolution across art movements
- 09_color_psychology.ipynb - Exploring emotional associations of colors in art
- 10_style_classifier.ipynb - Building a ML classifier with color features
- 11_color_naming.ipynb - Evocative color naming with artist pigments, XKCD, Werner's, and Resene vocabularies
Deep Learning & Embeddings (Lessons 12-16)
- 12_art_movement_classification.ipynb - Movement classification with SHAP explainability
- 13_palette_generation_vae.ipynb - Variational Autoencoder palette generation
- 14_artist_color_dna.ipynb - Artist similarity and color DNA embeddings
- 15_clustering_anomaly_detection.ipynb - Unsupervised learning for art analysis
- 16_temporal_artist_evolution.ipynb - Tracking artist palette evolution over time
Capstone (Lesson 17)
- 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:
- Cultural Relevance: Uses art history to teach computational concepts
- Progressive Complexity: From simple function calls to advanced ML
- Visual Learning: Students see immediate, meaningful results
- Real Data: Works with actual cultural heritage data, not toy examples
- Extensible: Students can fork and extend for their own projects
API Overview
Artist Analysis
ArtistAnalyzer- Main class for artist work extraction and analysisquick_analysis()- Convenience function for quick exploration
Color Analysis
ColorExtractor- Extract color palettes using k-means clusteringColorAnalyzer- Analyze colors across multiple color spaces (includes PEMD, CCI, CPS)ColorNamer- Perceptual color naming, cross-vocabulary translation, historical pigment probabilityColorVisualizer- Create publication-quality color visualizationsPromptGenerator- 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:
- Email: m.semoglou@tongji.edu.cn
- Issues: GitHub Issues
What's New
See CHANGELOG.md for the full version history.