class ChartGenerator
A class that generates various types of charts (bar, line, pie, scatter) optimized for e-ink displays with high contrast and clear visibility.
/tf/active/vicechatdev/e-ink-llm/graphics_generator.py
84 - 226
moderate
Purpose
ChartGenerator is responsible for creating matplotlib-based charts specifically styled for e-ink displays. It handles chart generation from GraphicSpec objects, applies e-ink optimizations (high contrast, clear edges, white backgrounds), and converts the resulting figures to base64-encoded PNG images. The class supports multiple chart types and includes error handling with placeholder generation.
Source Code
class ChartGenerator:
"""Generates various types of charts optimized for e-ink displays"""
def __init__(self):
# Apply e-ink styling
plt.style.use('default')
plt.rcParams.update(EInkStyler.get_eink_style())
def generate_chart(self, spec: GraphicSpec) -> GraphicSpec:
"""Generate a chart based on specification"""
params = spec.parameters
chart_type = params.get('type', 'bar').lower()
try:
fig, ax = plt.subplots(figsize=(8, 6))
if chart_type == 'bar':
self._create_bar_chart(ax, params)
elif chart_type == 'line':
self._create_line_chart(ax, params)
elif chart_type == 'pie':
self._create_pie_chart(ax, params)
elif chart_type == 'scatter':
self._create_scatter_chart(ax, params)
else:
self._create_bar_chart(ax, params) # Default to bar chart
# Apply e-ink optimizations
self._apply_eink_styling(fig, ax)
# Convert to image data
spec.image_data = self._fig_to_base64(fig)
spec.width = 800
spec.height = 600
plt.close(fig)
return spec
except Exception as e:
print(f"Error generating chart: {e}")
return self._create_error_placeholder(spec, f"Chart generation failed: {e}")
def _create_bar_chart(self, ax, params):
"""Create a bar chart"""
data = params.get('data', [1, 2, 3])
labels = params.get('labels', [f'Item {i+1}' for i in range(len(data))])
title = params.get('title', 'Bar Chart')
bars = ax.bar(labels, data, color=EInkStyler.CHART_COLORS[0],
edgecolor='black', linewidth=1)
# Add value labels on bars
for bar, value in zip(bars, data):
height = bar.get_height()
ax.text(bar.get_x() + bar.get_width()/2., height + 0.01*max(data),
f'{value}', ha='center', va='bottom', fontsize=10)
ax.set_title(title, fontsize=14, fontweight='bold', pad=20)
ax.set_ylabel(params.get('ylabel', 'Value'))
ax.grid(True, alpha=0.3)
def _create_line_chart(self, ax, params):
"""Create a line chart"""
data = params.get('data', [1, 2, 3, 4])
labels = params.get('labels', list(range(len(data))))
title = params.get('title', 'Line Chart')
ax.plot(labels, data, color='black', linewidth=2, marker='o',
markersize=6, markerfacecolor='white', markeredgecolor='black')
ax.set_title(title, fontsize=14, fontweight='bold', pad=20)
ax.set_xlabel(params.get('xlabel', 'X-axis'))
ax.set_ylabel(params.get('ylabel', 'Y-axis'))
ax.grid(True, alpha=0.3)
def _create_pie_chart(self, ax, params):
"""Create a pie chart"""
data = params.get('data', [1, 2, 3])
labels = params.get('labels', [f'Segment {i+1}' for i in range(len(data))])
title = params.get('title', 'Pie Chart')
# Use patterns for e-ink compatibility
patterns = ['', '///', '...', '|||', '---']
wedges, texts, autotexts = ax.pie(data, labels=labels, autopct='%1.1f%%',
colors=EInkStyler.CHART_COLORS[:len(data)],
wedgeprops={'edgecolor': 'black', 'linewidth': 1})
ax.set_title(title, fontsize=14, fontweight='bold', pad=20)
def _create_scatter_chart(self, ax, params):
"""Create a scatter plot"""
x_data = params.get('x_data', [1, 2, 3, 4])
y_data = params.get('y_data', [1, 4, 2, 3])
title = params.get('title', 'Scatter Plot')
ax.scatter(x_data, y_data, c='black', s=50, alpha=0.7, edgecolors='black')
ax.set_title(title, fontsize=14, fontweight='bold', pad=20)
ax.set_xlabel(params.get('xlabel', 'X-axis'))
ax.set_ylabel(params.get('ylabel', 'Y-axis'))
ax.grid(True, alpha=0.3)
def _apply_eink_styling(self, fig, ax):
"""Apply e-ink specific styling to the figure"""
# Ensure white background
fig.patch.set_facecolor('white')
ax.set_facecolor('white')
# Increase contrast
for spine in ax.spines.values():
spine.set_edgecolor('black')
spine.set_linewidth(1)
# Optimize for e-ink display
plt.tight_layout()
def _fig_to_base64(self, fig) -> str:
"""Convert matplotlib figure to base64 encoded image"""
buffer = io.BytesIO()
fig.savefig(buffer, format='png', dpi=150, bbox_inches='tight',
facecolor='white', edgecolor='none')
buffer.seek(0)
image_data = buffer.getvalue()
buffer.close()
return base64.b64encode(image_data).decode('utf-8')
def _create_error_placeholder(self, spec: GraphicSpec, error_msg: str) -> GraphicSpec:
"""Create an error placeholder image"""
fig, ax = plt.subplots(figsize=(6, 4))
ax.text(0.5, 0.5, f"Error: {error_msg}", ha='center', va='center',
transform=ax.transAxes, fontsize=12,
bbox=dict(boxstyle="round,pad=0.3", facecolor="lightgray"))
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
ax.axis('off')
spec.image_data = self._fig_to_base64(fig)
spec.width = 600
spec.height = 400
plt.close(fig)
return spec
Parameters
| Name | Type | Default | Kind |
|---|---|---|---|
bases |
- | - |
Parameter Details
__init__: No parameters required. The constructor initializes matplotlib with default style and applies e-ink specific styling from EInkStyler.get_eink_style().
Return Value
Instantiation returns a ChartGenerator object. The main method generate_chart() returns a GraphicSpec object with populated image_data (base64-encoded PNG), width, and height attributes. Private methods return None (styling methods) or strings (base64 conversion) or GraphicSpec (error placeholder).
Class Interface
Methods
__init__(self)
Purpose: Initialize the ChartGenerator and configure matplotlib with e-ink optimized styling
Returns: None
generate_chart(self, spec: GraphicSpec) -> GraphicSpec
Purpose: Main public method to generate a chart based on the provided specification
Parameters:
spec: GraphicSpec object containing chart parameters including type, data, labels, and title
Returns: GraphicSpec object with populated image_data (base64 PNG), width (800), and height (600)
_create_bar_chart(self, ax, params)
Purpose: Create a bar chart on the provided matplotlib axes
Parameters:
ax: Matplotlib axes object to draw onparams: Dictionary with 'data', 'labels', 'title', and 'ylabel' keys
Returns: None (modifies ax in place)
_create_line_chart(self, ax, params)
Purpose: Create a line chart on the provided matplotlib axes
Parameters:
ax: Matplotlib axes object to draw onparams: Dictionary with 'data', 'labels', 'title', 'xlabel', and 'ylabel' keys
Returns: None (modifies ax in place)
_create_pie_chart(self, ax, params)
Purpose: Create a pie chart on the provided matplotlib axes with patterns for e-ink compatibility
Parameters:
ax: Matplotlib axes object to draw onparams: Dictionary with 'data', 'labels', and 'title' keys
Returns: None (modifies ax in place)
_create_scatter_chart(self, ax, params)
Purpose: Create a scatter plot on the provided matplotlib axes
Parameters:
ax: Matplotlib axes object to draw onparams: Dictionary with 'x_data', 'y_data', 'title', 'xlabel', and 'ylabel' keys
Returns: None (modifies ax in place)
_apply_eink_styling(self, fig, ax)
Purpose: Apply e-ink specific styling to ensure high contrast and visibility
Parameters:
fig: Matplotlib figure objectax: Matplotlib axes object
Returns: None (modifies fig and ax in place)
_fig_to_base64(self, fig) -> str
Purpose: Convert a matplotlib figure to a base64-encoded PNG string
Parameters:
fig: Matplotlib figure object to convert
Returns: Base64-encoded string representation of the PNG image at 150 DPI
_create_error_placeholder(self, spec: GraphicSpec, error_msg: str) -> GraphicSpec
Purpose: Create an error placeholder image when chart generation fails
Parameters:
spec: GraphicSpec object to populate with error imageerror_msg: Error message to display in the placeholder
Returns: GraphicSpec object with error placeholder image (600x400)
Dependencies
matplotlibnumpyiobase64
Required Imports
import matplotlib.pyplot as plt
import io
import base64
Usage Example
from dataclasses import dataclass
from typing import Dict, Any
@dataclass
class GraphicSpec:
parameters: Dict[str, Any]
image_data: str = ''
width: int = 0
height: int = 0
class EInkStyler:
CHART_COLORS = ['#CCCCCC', '#999999', '#666666', '#333333']
@staticmethod
def get_eink_style():
return {'figure.facecolor': 'white', 'axes.facecolor': 'white'}
# Create chart generator
generator = ChartGenerator()
# Create a bar chart
bar_spec = GraphicSpec(parameters={
'type': 'bar',
'data': [10, 25, 15, 30],
'labels': ['Q1', 'Q2', 'Q3', 'Q4'],
'title': 'Quarterly Sales',
'ylabel': 'Revenue ($K)'
})
result = generator.generate_chart(bar_spec)
print(f"Generated chart: {result.width}x{result.height}")
# Create a line chart
line_spec = GraphicSpec(parameters={
'type': 'line',
'data': [5, 10, 8, 15, 12],
'labels': ['Jan', 'Feb', 'Mar', 'Apr', 'May'],
'title': 'Monthly Trends',
'xlabel': 'Month',
'ylabel': 'Value'
})
result = generator.generate_chart(line_spec)
# Create a pie chart
pie_spec = GraphicSpec(parameters={
'type': 'pie',
'data': [30, 25, 20, 25],
'labels': ['A', 'B', 'C', 'D'],
'title': 'Distribution'
})
result = generator.generate_chart(pie_spec)
Best Practices
- Always instantiate ChartGenerator before generating charts to ensure matplotlib styling is properly configured
- Ensure EInkStyler class is available and properly configured before instantiation
- GraphicSpec objects must have a 'parameters' dictionary with at least a 'type' key
- The class automatically closes matplotlib figures after conversion to prevent memory leaks
- Default chart type is 'bar' if an invalid or missing type is specified
- Chart data should be provided as lists in the parameters dictionary
- The class handles exceptions internally and returns error placeholder images on failure
- Generated images are base64-encoded PNG format at 150 DPI
- All charts are optimized for e-ink displays with high contrast, black edges, and white backgrounds
- Call generate_chart() for each chart needed; the method is stateless and can be called multiple times
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
function demo_graphics_generation 72.9% similar
-
class GraphicsGenerator 70.0% similar
-
class IllustrationGenerator 67.1% similar
-
class DiagramGenerator 64.8% similar
-
class PDFGenerator 60.5% similar