#!/usr/bin/env python3 """ Data Visualization Tools Comprehensive data visualization system for concert analytics and reporting """ import json import math import base64 import hashlib import datetime import re import string import itertools import collections import dataclasses import random from typing import Dict, List, Optional, Any, Union, Tuple from dataclasses import dataclass, field from collections import defaultdict from enum import Enum class ChartType(Enum): LINE = "line" BAR = "bar" PIE = "pie" SCATTER = "scatter" HEATMAP = "heatmap" GAUGE = "gauge" HISTOGRAM = "histogram" AREA = "area" DONUT = "donut" RADAR = "radar" TREEMAP = "treemap" FUNNEL = "funnel" class VisualizationType(Enum): DASHBOARD = "dashboard" REPORT = "report" REALTIME = "realtime" INTERACTIVE = "interactive" EXPORT = "export" class ColorScheme(Enum): DEFAULT = "default" CONCERT = "concert" BUSINESS = "business" RAINBOW = "rainbow" MONOCHROME = "monochrome" CUSTOM = "custom" @dataclass class DataPoint: """Single data point for visualization""" x: Union[str, float, datetime.datetime] y: Union[float, int, str] label: Optional[str] = None color: Optional[str] = None size: Optional[float] = None metadata: Dict[str, Any] = field(default_factory=dict) @dataclass class ChartSeries: """Series of data points for a chart""" series_id: str name: str data_points: List[DataPoint] color: Optional[str] = None chart_type: Optional[ChartType] = None @dataclass class Visualization: """Complete visualization definition""" viz_id: str title: str description: str chart_type: ChartType data_series: List[ChartSeries] dimensions: Dict[str, int] # width, height color_scheme: ColorScheme interactive: bool = True animation: bool = True export_formats: List[str] = field(default_factory=lambda: ["png", "svg", "pdf"]) @dataclass class Dashboard: """Dashboard containing multiple visualizations""" dashboard_id: str title: str layout: str # grid, freeform, tabs visualizations: List[str] # viz_ids refresh_interval: int = 30 # seconds auto_refresh: bool = True class DataVisualizationTools: """ Comprehensive data visualization system Creates charts, dashboards, and interactive visualizations """ def __init__(self): self.visualizations = {} self.dashboards = {} self.color_palettes = self._initialize_color_palettes() self.chart_templates = self._initialize_chart_templates() self.data_cache = {} def _initialize_color_palettes(self) -> Dict[str, List[str]]: """Initialize color palettes for different themes""" return { "default": ["#1f77b4", "#ff7f0e", "#2ca02c", "#d62728", "#9467bd", "#8c564b", "#e377c2", "#7f7f7f"], "concert": ["#ff6b6b", "#4ecdc4", "#45b7d1", "#f9ca24", "#6c5ce7", "#a29bfe", "#fd79a8", "#fdcb6e"], "business": ["#2c3e50", "#34495e", "#7f8c8d", "#95a5a6", "#bdc3c7", "#ecf0f1", "#3498db", "#2980b9"], "rainbow": ["#ff0000", "#ff7f00", "#ffff00", "#00ff00", "#0000ff", "#4b0082", "#9400d3", "#ff1493"], "monochrome": ["#2c3e50", "#34495e", "#7f8c8d", "#95a5a6", "#bdc3c7", "#ecf0f1", "#d5dbdb", "#aab7b8"] } def _initialize_chart_templates(self) -> Dict[str, Dict[str, Any]]: """Initialize predefined chart templates""" return { "attendance_timeline": { "chart_type": ChartType.LINE, "title": "Attendance Over Time", "description": "Event attendance trends", "dimensions": {"width": 800, "height": 400}, "color_scheme": ColorScheme.CONCERT }, "revenue_breakdown": { "chart_type": ChartType.PIE, "title": "Revenue Breakdown", "description": "Revenue sources distribution", "dimensions": {"width": 600, "height": 400}, "color_scheme": ColorScheme.BUSINESS }, "performance_comparison": { "chart_type": ChartType.BAR, "title": "Performance Comparison", "description": "Compare metrics across events", "dimensions": {"width": 800, "height": 500}, "color_scheme": ColorScheme.DEFAULT }, "realtime_metrics": { "chart_type": ChartType.GAUGE, "title": "Real-time Metrics", "description": "Live performance indicators", "dimensions": {"width": 300, "height": 200}, "color_scheme": ColorScheme.CONCERT }, "attendance_heatmap": { "chart_type": ChartType.HEATMAP, "title": "Attendance Heatmap", "description": "Venue attendance patterns", "dimensions": {"width": 800, "height": 600}, "color_scheme": ColorScheme.RAINBOW }, "kpi_radar": { "chart_type": ChartType.RADAR, "title": "KPI Performance", "description": "Multi-dimensional KPI view", "dimensions": {"width": 500, "height": 500}, "color_scheme": ColorScheme.CONCERT } } def create_chart_from_data(self, chart_data: Dict[str, Any]) -> Optional[Visualization]: """Create chart from raw data""" try: # Validate required fields if "data" not in chart_data or "chart_type" not in chart_data: return None chart_type = ChartType(chart_data["chart_type"]) title = chart_data.get("title", "Chart") description = chart_data.get("description", "") # Process data into series data_series = [] raw_data = chart_data["data"] if isinstance(raw_data, list) and len(raw_data) > 0: # Single series data if isinstance(raw_data[0], dict): series = self._create_series_from_dict_list("Series 1", raw_data) if series: data_series.append(series) elif isinstance(raw_data[0], (list, tuple)) and len(raw_data[0]) >= 2: series = self._create_series_from_tuple_list("Series 1", raw_data) if series: data_series.append(series) elif isinstance(raw_data, dict): # Multiple series or categorical data if chart_type in [ChartType.PIE, ChartType.DONUT]: # Single series from dict (label: value) series = self._create_series_from_dict("Data", raw_data) if series: data_series.append(series) else: # Multiple series from dict for series_name, series_data in raw_data.items(): if isinstance(series_data, list): if len(series_data) > 0 and isinstance(series_data[0], dict): series = self._create_series_from_dict_list(series_name, series_data) elif len(series_data) > 0 and isinstance(series_data[0], (list, tuple)): series = self._create_series_from_tuple_list(series_name, series_data) else: series = self._create_series_from_dict(series_name, {str(i): val for i, val in enumerate(series_data)}) if series: data_series.append(series) if not data_series: return None # Create visualization viz = Visualization( viz_id=f"viz_{datetime.datetime.now().timestamp()}_{random.randint(1000, 9999)}", title=title, description=description, chart_type=chart_type, data_series=data_series, dimensions=chart_data.get("dimensions", {"width": 600, "height": 400}), color_scheme=ColorScheme(chart_data.get("color_scheme", "default")), interactive=chart_data.get("interactive", True), animation=chart_data.get("animation", True), export_formats=chart_data.get("export_formats", ["png", "svg"]) ) self.visualizations[viz.viz_id] = viz return viz except Exception as e: return None def _create_series_from_dict_list(self, series_name: str, data_list: List[Dict[str, Any]]) -> Optional[ChartSeries]: """Create series from list of dictionaries""" try: data_points = [] for item in data_list: # Assume first two values are x and y keys = list(item.keys()) if len(keys) >= 2: x_value = item[keys[0]] y_value = item[keys[1]] data_point = DataPoint( x=x_value, y=y_value, label=item.get("label"), color=item.get("color"), size=item.get("size"), metadata={k: v for k, v in item.items() if k not in [keys[0], keys[1], "label", "color", "size"]} ) data_points.append(data_point) return ChartSeries( series_id=f"series_{datetime.datetime.now().timestamp()}", name=series_name, data_points=data_points ) except Exception as e: return None def _create_series_from_tuple_list(self, series_name: str, data_list: List[Tuple]) -> Optional[ChartSeries]: """Create series from list of tuples""" try: data_points = [] for item in data_list: if len(item) >= 2: x_value, y_value = item[0], item[1] label = item[2] if len(item) > 2 else None data_point = DataPoint(x=x_value, y=y_value, label=label) data_points.append(data_point) return ChartSeries( series_id=f"series_{datetime.datetime.now().timestamp()}", name=series_name, data_points=data_points ) except Exception as e: return None def _create_series_from_dict(self, series_name: str, data_dict: Dict[str, Any]) -> Optional[ChartSeries]: """Create series from dictionary (label: value)""" try: data_points = [] for label, value in data_dict.items(): data_point = DataPoint(x=label, y=value, label=str(label)) data_points.append(data_point) return ChartSeries( series_id=f"series_{datetime.datetime.now().timestamp()}", name=series_name, data_points=data_points ) except Exception as e: return None def create_dashboard(self, dashboard_config: Dict[str, Any]) -> Optional[Dashboard]: """Create a dashboard with multiple visualizations""" try: dashboard = Dashboard( dashboard_id=dashboard_config.get("dashboard_id", f"dash_{datetime.datetime.now().timestamp()}"), title=dashboard_config.get("title", "Dashboard"), layout=dashboard_config.get("layout", "grid"), visualizations=dashboard_config.get("visualizations", []), refresh_interval=dashboard_config.get("refresh_interval", 30), auto_refresh=dashboard_config.get("auto_refresh", True) ) self.dashboards[dashboard.dashboard_id] = dashboard return dashboard except Exception as e: return None def generate_chart_config(self, viz_id: str, format_type: str = "chartjs") -> Dict[str, Any]: """Generate chart configuration for specified library/format""" if viz_id not in self.visualizations: return {"error": "Visualization not found"} viz = self.visualizations[viz_id] if format_type == "chartjs": return self._generate_chartjs_config(viz) elif format_type == "d3": return self._generate_d3_config(viz) elif format_type == "plotly": return self._generate_plotly_config(viz) else: return self._generate_generic_config(viz) def _generate_chartjs_config(self, viz: Visualization) -> Dict[str, Any]: """Generate Chart.js configuration""" config = { "type": viz.chart_type.value, "data": { "labels": [], "datasets": [] }, "options": { "responsive": True, "maintainAspectRatio": False, "title": { "display": True, "text": viz.title }, "animation": { "duration": viz.animation * 1000 if viz.animation else 0 } } } # Extract colors colors = self.color_palettes.get(viz.color_scheme.value, self.color_palettes["default"]) # Process data series for i, series in enumerate(viz.data_series): # Extract labels from first series if i == 0: config["data"]["labels"] = [str(dp.x) for dp in series.data_points] dataset = { "label": series.name, "data": [dp.y for dp in series.data_points], "backgroundColor": colors[i % len(colors)], "borderColor": colors[i % len(colors)], "borderWidth": 1 } # Chart type specific configurations if viz.chart_type == ChartType.LINE: dataset["fill"] = False dataset["tension"] = 0.1 elif viz.chart_type == ChartType.PIE: dataset["backgroundColor"] = [colors[j % len(colors)] for j in range(len(series.data_points))] elif viz.chart_type == ChartType.BAR: pass # Use default bar config config["data"]["datasets"].append(dataset) return config def _generate_d3_config(self, viz: Visualization) -> Dict[str, Any]: """Generate D3.js configuration""" colors = self.color_palettes.get(viz.color_scheme.value, self.color_palettes["default"]) config = { "chartType": viz.chart_type.value, "title": viz.title, "dimensions": viz.dimensions, "colors": colors, "data": [] } for series in viz.data_series: series_data = { "name": series.name, "values": [ { "x": dp.x, "y": dp.y, "label": dp.label, "color": dp.color or colors[0] } for dp in series.data_points ] } config["data"].append(series_data) return config def _generate_plotly_config(self, viz: Visualization) -> Dict[str, Any]: """Generate Plotly configuration""" colors = self.color_palettes.get(viz.color_scheme.value, self.color_palettes["default"]) config = { "data": [], "layout": { "title": viz.title, "width": viz.dimensions["width"], "height": viz.dimensions["height"] } } for i, series in enumerate(viz.data_series): trace = { "name": series.name, "x": [dp.x for dp in series.data_points], "y": [dp.y for dp in series.data_points], "type": self._map_chart_type_to_plotly(viz.chart_type), "marker": {"color": colors[i % len(colors)]} } if viz.chart_type == ChartType.PIE: trace["values"] = [dp.y for dp in series.data_points] trace["labels"] = [dp.x for dp in series.data_points] config["data"].append(trace) return config def _generate_generic_config(self, viz: Visualization) -> Dict[str, Any]: """Generate generic chart configuration""" colors = self.color_palettes.get(viz.color_scheme.value, self.color_palettes["default"]) config = { "chartType": viz.chart_type.value, "title": viz.title, "description": viz.description, "dimensions": viz.dimensions, "colors": colors, "interactive": viz.interactive, "animation": viz.animation, "series": [] } for series in viz.data_series: series_config = { "id": series.series_id, "name": series.name, "data": [ { "x": dp.x, "y": dp.y, "label": dp.label, "color": dp.color, "size": dp.size, "metadata": dp.metadata } for dp in series.data_points ] } config["series"].append(series_config) return config def _map_chart_type_to_plotly(self, chart_type: ChartType) -> str: """Map chart type to Plotly chart type""" mapping = { ChartType.LINE: "scatter", ChartType.BAR: "bar", ChartType.PIE: "pie", ChartType.SCATTER: "scatter", ChartType.AREA: "scatter", ChartType.HISTOGRAM: "histogram" } return mapping.get(chart_type, "scatter") def create_template_chart(self, template_name: str, data: Dict[str, Any]) -> Optional[Visualization]: """Create chart using predefined template""" if template_name not in self.chart_templates: return None template = self.chart_templates[template_name] chart_config = { "title": template["title"], "description": template["description"], "chart_type": template["chart_type"].value, "data": data, "dimensions": template["dimensions"], "color_scheme": template["color_scheme"].value } return self.create_chart_from_data(chart_config) def export_visualization(self, viz_id: str, format_type: str = "png") -> Dict[str, Any]: """Export visualization in specified format""" if viz_id not in self.visualizations: return {"error": "Visualization not found"} viz = self.visualizations[viz_id] if format_type not in viz.export_formats: return {"error": f"Format {format_type} not supported"} export_data = { "viz_id": viz_id, "format": format_type, "title": viz.title, "export_timestamp": datetime.datetime.now().isoformat(), "data_url": self._generate_data_url(viz, format_type) } return export_data def _generate_data_url(self, viz: Visualization, format_type: str) -> str: """Generate data URL for visualization (simplified)""" # In a real implementation, this would render the chart and convert to base64 # For now, return a placeholder mock_data = json.dumps({ "title": viz.title, "chart_type": viz.chart_type.value, "data_points": len(sum([series.data_points for series in viz.data_series], [])) }).encode('utf-8') encoded = base64.b64encode(mock_data).decode('utf-8') return f"data:application/json;base64,{encoded}" def get_dashboard_data(self, dashboard_id: str) -> Dict[str, Any]: """Get comprehensive dashboard data""" if dashboard_id not in self.dashboards: return {"error": "Dashboard not found"} dashboard = self.dashboards[dashboard_id] dashboard_data = { "dashboard_id": dashboard.dashboard_id, "title": dashboard.title, "layout": dashboard.layout, "refresh_interval": dashboard.refresh_interval, "auto_refresh": dashboard.auto_refresh, "visualizations": {}, "generated_at": datetime.datetime.now().isoformat() } # Add visualization data for viz_id in dashboard.visualizations: if viz_id in self.visualizations: viz = self.visualizations[viz_id] dashboard_data["visualizations"][viz_id] = { "title": viz.title, "chart_type": viz.chart_type.value, "dimensions": viz.dimensions, "config": self.generate_chart_config(viz_id) } return dashboard_data def create_concert_dashboard(self) -> str: """Create a comprehensive concert analytics dashboard""" # Sample data for demonstration attendance_data = { "data": [ {"time": "18:00", "attendance": 0}, {"time": "18:30", "attendance": 500}, {"time": "19:00", "attendance": 1500}, {"time": "19:30", "attendance": 2800}, {"time": "20:00", "attendance": 3800}, {"time": "20:30", "attendance": 4200}, {"time": "21:00", "attendance": 4500}, {"time": "21:30", "attendance": 4600}, {"time": "22:00", "attendance": 4700}, {"time": "22:30", "attendance": 4750}, {"time": "23:00", "attendance": 4780} ] } revenue_data = { "data": { "Ticket Sales": 285000, "Merchandise": 45000, "Concessions": 32000, "VIP Packages": 28000, "Parking": 8000 } } performance_data = { "data": { "Attendance": 95, "Revenue": 112, "Satisfaction": 88, "Efficiency": 92, "Safety": 96 } } realtime_data = { "data": [ {"metric": "Current Occupancy", "value": 85, "max": 100}, {"metric": "Staff Efficiency", "value": 78, "max": 100}, {"metric": "Audio Quality", "value": 92, "max": 100}, {"metric": "Safety Score", "value": 95, "max": 100} ] } # Create visualizations viz_ids = [] # Attendance timeline attendance_viz = self.create_template_chart("attendance_timeline", attendance_data) if attendance_viz: viz_ids.append(attendance_viz.viz_id) # Revenue breakdown revenue_viz = self.create_template_chart("revenue_breakdown", revenue_data) if revenue_viz: viz_ids.append(revenue_viz.viz_id) # Performance radar performance_viz = self.create_template_chart("kpi_radar", performance_data) if performance_viz: viz_ids.append(performance_viz.viz_id) # Real-time gauges (simplified as bars for demo) realtime_chart_data = { "data": [ {"metric": "Occupancy", "value": 85}, {"metric": "Efficiency", "value": 78}, {"metric": "Audio", "value": 92}, {"metric": "Safety", "value": 95} ] } realtime_viz = self.create_chart_from_data({ "title": "Real-time Metrics", "chart_type": "bar", "data": realtime_chart_data["data"], "color_scheme": "concert" }) if realtime_viz: viz_ids.append(realtime_viz.viz_id) # Create dashboard dashboard_config = { "dashboard_id": "concert_main_dashboard", "title": "Concert Analytics Dashboard", "layout": "grid", "visualizations": viz_ids, "refresh_interval": 30 } dashboard = self.create_dashboard(dashboard_config) return dashboard.dashboard_id if dashboard else "" def generate_sample_visualization_data() -> Dict[str, Any]: """Generate sample data for testing visualizations""" return { "line_chart_data": [ {"month": "Jan", "attendance": 2500, "revenue": 150000}, {"month": "Feb", "attendance": 3200, "revenue": 195000}, {"month": "Mar", "attendance": 2800, "revenue": 175000}, {"month": "Apr", "attendance": 4100, "revenue": 245000}, {"month": "May", "attendance": 3800, "revenue": 228000}, {"month": "Jun", "attendance": 5200, "revenue": 312000} ], "pie_chart_data": { "Ticket Sales": 350000, "Merchandise": 55000, "Food & Beverage": 42000, "VIP Packages": 38000, "Parking": 12000 }, "bar_chart_data": [ {"event": "Rock Concert", "attendance": 4500, "satisfaction": 4.2}, {"event": "Pop Festival", "attendance": 6200, "satisfaction": 4.5}, {"event": "Jazz Night", "attendance": 1800, "satisfaction": 4.8}, {"event": "Electronic", "attendance": 5300, "satisfaction": 4.1}, {"event": "Classical", "attendance": 2200, "satisfaction": 4.9} ], "gauge_data": [ {"metric": "Occupancy Rate", "value": 85, "max": 100}, {"metric": "Revenue Target", "value": 72, "max": 100}, {"metric": "Satisfaction", "value": 91, "max": 100} ] } if __name__ == "__main__": # Initialize visualization tools viz_tools = DataVisualizationTools() print("=== Data Visualization Tools ===") # Generate sample data sample_data = generate_sample_visualization_data() # Test different chart types print("\n=== Creating Visualizations ===") # Line chart line_chart = viz_tools.create_chart_from_data({ "title": "Monthly Attendance Trend", "chart_type": "line", "data": sample_data["line_chart_data"], "color_scheme": "concert" }) if line_chart: print(f"Created line chart: {line_chart.viz_id}") # Pie chart pie_chart = viz_tools.create_chart_from_data({ "title": "Revenue Sources", "chart_type": "pie", "data": sample_data["pie_chart_data"], "color_scheme": "business" }) if pie_chart: print(f"Created pie chart: {pie_chart.viz_id}") # Bar chart bar_chart = viz_tools.create_chart_from_data({ "title": "Event Comparison", "chart_type": "bar", "data": sample_data["bar_chart_data"], "color_scheme": "default" }) if bar_chart: print(f"Created bar chart: {bar_chart.viz_id}") # Generate chart configurations print("\n=== Chart Configurations ===") for viz_id, viz in list(viz_tools.visualizations.items())[:2]: # Show first 2 print(f"\nChart: {viz.title}") chartjs_config = viz_tools.generate_chart_config(viz_id, "chartjs") print("Chart.js config keys:", list(chartjs_config.keys())) plotly_config = viz_tools.generate_chart_config(viz_id, "plotly") print("Plotly config keys:", list(plotly_config.keys())) # Create concert dashboard print("\n=== Creating Concert Dashboard ===") dashboard_id = viz_tools.create_concert_dashboard() if dashboard_id: print(f"Created dashboard: {dashboard_id}") dashboard_data = viz_tools.get_dashboard_data(dashboard_id) print(f"Dashboard has {len(dashboard_data['visualizations'])} visualizations") print("Dashboard visualizations:") for viz_id, viz_info in dashboard_data["visualizations"].items(): print(f" - {viz_info['title']}: {viz_info['chart_type']}") # Export visualization print("\n=== Exporting Visualization ===") if viz_tools.visualizations: first_viz_id = list(viz_tools.visualizations.keys())[0] export_data = viz_tools.export_visualization(first_viz_id, "png") print("Export result:") print(json.dumps(export_data, indent=2)) print(f"\nTotal visualizations created: {len(viz_tools.visualizations)}") print(f"Total dashboards created: {len(viz_tools.dashboards)}")