🔍 Code Extractor

class ChartGenerator

Maturity: 51

A class that generates various types of charts (bar, line, pie, scatter) optimized for e-ink displays with high contrast and clear visibility.

File:
/tf/active/vicechatdev/e-ink-llm/graphics_generator.py
Lines:
84 - 226
Complexity:
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 on
  • params: 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 on
  • params: 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 on
  • params: 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 on
  • params: 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 object
  • ax: 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 image
  • error_msg: Error message to display in the placeholder

Returns: GraphicSpec object with error placeholder image (600x400)

Dependencies

  • matplotlib
  • numpy
  • io
  • base64

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

Similar Components

AI-powered semantic similarity - components with related functionality:

  • function demo_graphics_generation 72.9% similar

    Demonstrates the generation of three types of graphics (bar chart, process diagram, and mathematical illustration) using the GraphicsGenerator class with e-ink optimized styling.

    From: /tf/active/vicechatdev/e-ink-llm/demo_hybrid_mode.py
  • class GraphicsGenerator 70.0% similar

    GraphicsGenerator is a coordinator class that orchestrates the generation of different types of graphics (charts, diagrams, illustrations, and sketches) by delegating to specialized generator classes.

    From: /tf/active/vicechatdev/e-ink-llm/graphics_generator.py
  • class IllustrationGenerator 67.1% similar

    A class that generates educational illustrations and technical drawings for mathematical and scientific concepts using matplotlib and programmatic rendering.

    From: /tf/active/vicechatdev/e-ink-llm/graphics_generator.py
  • class DiagramGenerator 64.8% similar

    A class that generates various types of diagrams including flowcharts, process flows, and network diagrams using matplotlib and networkx, returning base64-encoded PNG images.

    From: /tf/active/vicechatdev/e-ink-llm/graphics_generator.py
  • class PDFGenerator 60.5% similar

    A class that generates PDF documents optimized for e-ink displays, converting LLM responses and images into formatted, high-contrast PDFs with custom styling.

    From: /tf/active/vicechatdev/e-ink-llm/pdf_generator.py
← Back to Browse