290 lines
8.7 KiB
Python
290 lines
8.7 KiB
Python
#!/usr/bin/env python3
|
|
import argparse
|
|
import os
|
|
from pathlib import Path
|
|
from datetime import datetime
|
|
import base64
|
|
|
|
def create_html_dashboard(base_filename: str, charts_dir: str = "charts", output_file: str = None):
|
|
"""
|
|
Create an HTML dashboard with all generated charts.
|
|
|
|
Args:
|
|
base_filename: Base filename used for the data
|
|
charts_dir: Directory containing chart PNG files
|
|
output_file: Output HTML file path
|
|
"""
|
|
charts_path = Path(charts_dir)
|
|
|
|
if not charts_path.exists():
|
|
print(f"Charts directory not found: {charts_path}")
|
|
return
|
|
|
|
# Chart files to include (in display order)
|
|
chart_files = [
|
|
("monthly_comparison.png", "Porównanie miesięczne", "Porównanie zużycia energii w poszczególnych miesiącach"),
|
|
("cost_analysis_miesięczne.png", "Analiza kosztów - miesięczna", "Koszty i przychody z energii elektrycznej w ujęciu miesięcznym"),
|
|
("monthly_hourly_profiles.png", "Profile godzinowe miesięczne", "Średnie godzinowe zużycie energii dla każdego miesiąca"),
|
|
("monthly_timeseries.png", "Trend miesięczny", "Miesięczne zużycie energii w czasie"),
|
|
("cost_analysis_dzienne.png", "Analiza kosztów - dzienna", "Koszty i przychody z energii elektrycznej w ujęciu dziennym"),
|
|
("weekly_timeseries.png", "Trend tygodniowy", "Tygodniowe zużycie energii w czasie"),
|
|
("daily_timeseries.png", "Trend dzienny", "Dzienne zużycie energii w czasie"),
|
|
("daily_stacked.png", "Obszar skumulowany", "Dzienne zużycie - wykres obszarowy"),
|
|
("hourly_timeseries.png", "Dane godzinowe", "Zużycie energii w ciągu dnia (próbka 30 dni)")
|
|
]
|
|
|
|
# Encode images to base64 for embedding
|
|
encoded_images = {}
|
|
for filename, _, _ in chart_files:
|
|
chart_path = charts_path / filename
|
|
if chart_path.exists():
|
|
with open(chart_path, 'rb') as f:
|
|
encoded_images[filename] = base64.b64encode(f.read()).decode('utf-8')
|
|
|
|
# Generate HTML
|
|
html_content = f"""
|
|
<!DOCTYPE html>
|
|
<html lang="pl">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Raport PGE - Dashboard Energii</title>
|
|
<style>
|
|
* {{
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
}}
|
|
|
|
body {{
|
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
background-color: #f5f5f5;
|
|
color: #333;
|
|
line-height: 1.6;
|
|
}}
|
|
|
|
.header {{
|
|
background: linear-gradient(135deg, #2E86AB, #A23B72);
|
|
color: white;
|
|
padding: 2rem 0;
|
|
text-align: center;
|
|
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
|
}}
|
|
|
|
.header h1 {{
|
|
font-size: 2.5rem;
|
|
margin-bottom: 0.5rem;
|
|
}}
|
|
|
|
.header p {{
|
|
font-size: 1.1rem;
|
|
opacity: 0.9;
|
|
}}
|
|
|
|
.container {{
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
padding: 2rem;
|
|
}}
|
|
|
|
.info-section {{
|
|
background: white;
|
|
margin: 2rem 0;
|
|
padding: 1.5rem;
|
|
border-radius: 10px;
|
|
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
|
}}
|
|
|
|
.chart-grid {{
|
|
display: grid;
|
|
gap: 2rem;
|
|
margin: 2rem 0;
|
|
}}
|
|
|
|
.chart-card {{
|
|
background: white;
|
|
border-radius: 10px;
|
|
padding: 1.5rem;
|
|
box-shadow: 0 4px 15px rgba(0,0,0,0.1);
|
|
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
|
}}
|
|
|
|
.chart-card:hover {{
|
|
transform: translateY(-5px);
|
|
box-shadow: 0 8px 25px rgba(0,0,0,0.15);
|
|
}}
|
|
|
|
.chart-card h3 {{
|
|
color: #2E86AB;
|
|
margin-bottom: 0.5rem;
|
|
font-size: 1.4rem;
|
|
}}
|
|
|
|
.chart-card p {{
|
|
color: #666;
|
|
margin-bottom: 1rem;
|
|
}}
|
|
|
|
.chart-card img {{
|
|
width: 100%;
|
|
height: auto;
|
|
border-radius: 5px;
|
|
}}
|
|
|
|
.energy-legend {{
|
|
display: flex;
|
|
justify-content: center;
|
|
gap: 2rem;
|
|
margin: 1rem 0;
|
|
flex-wrap: wrap;
|
|
}}
|
|
|
|
.legend-item {{
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
}}
|
|
|
|
.legend-color {{
|
|
width: 20px;
|
|
height: 20px;
|
|
border-radius: 3px;
|
|
}}
|
|
|
|
.legend-zbilansowana {{ background-color: #2E86AB; }}
|
|
.legend-oddana {{ background-color: #A23B72; }}
|
|
.legend-pobrana {{ background-color: #F18F01; }}
|
|
|
|
.footer {{
|
|
text-align: center;
|
|
padding: 2rem;
|
|
color: #666;
|
|
background: #f9f9f9;
|
|
margin-top: 2rem;
|
|
}}
|
|
|
|
@media (max-width: 768px) {{
|
|
.container {{
|
|
padding: 1rem;
|
|
}}
|
|
|
|
.header h1 {{
|
|
font-size: 2rem;
|
|
}}
|
|
|
|
.energy-legend {{
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
}}
|
|
}}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="header">
|
|
<h1>🔌 Dashboard Energii PGE</h1>
|
|
<p>Analiza zużycia energii elektrycznej</p>
|
|
</div>
|
|
|
|
<div class="container">
|
|
<div class="info-section">
|
|
<h2>📊 Informacje o raporcie</h2>
|
|
<p><strong>Plik źródłowy:</strong> {base_filename}</p>
|
|
<p><strong>Data generowania:</strong> {datetime.now().strftime('%d/%m/%Y %H:%M')}</p>
|
|
<p><strong>Typ analizy:</strong> Kompletna analiza czasowa (godzinowa, dzienna, tygodniowa, miesięczna)</p>
|
|
</div>
|
|
|
|
<div class="info-section">
|
|
<h3>🎨 Legenda typów energii</h3>
|
|
<div class="energy-legend">
|
|
<div class="legend-item">
|
|
<div class="legend-color legend-zbilansowana"></div>
|
|
<span><strong>Czynna zbilansowana</strong> - Energia netto</span>
|
|
</div>
|
|
<div class="legend-item">
|
|
<div class="legend-color legend-oddana"></div>
|
|
<span><strong>Czynna oddana</strong> - Energia oddana do sieci</span>
|
|
</div>
|
|
<div class="legend-item">
|
|
<div class="legend-color legend-pobrana"></div>
|
|
<span><strong>Czynna pobrana</strong> - Energia pobrana z sieci</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="chart-grid">
|
|
"""
|
|
|
|
# Add charts to HTML
|
|
for filename, title, description in chart_files:
|
|
if filename in encoded_images:
|
|
html_content += f"""
|
|
<div class="chart-card">
|
|
<h3>{title}</h3>
|
|
<p>{description}</p>
|
|
<img src="data:image/png;base64,{encoded_images[filename]}" alt="{title}">
|
|
</div>
|
|
"""
|
|
|
|
html_content += """
|
|
</div>
|
|
</div>
|
|
|
|
<div class="footer">
|
|
<p>Generated by PGE Raport Converter | Dashboard automatically created from energy data</p>
|
|
</div>
|
|
</body>
|
|
</html>
|
|
"""
|
|
|
|
# Save HTML file
|
|
if output_file is None:
|
|
output_file = f"dashboard_{base_filename}.html"
|
|
|
|
output_path = Path(output_file)
|
|
with open(output_path, 'w', encoding='utf-8') as f:
|
|
f.write(html_content)
|
|
|
|
print(f"Dashboard saved: {output_path}")
|
|
return output_path
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description="Generate HTML dashboard for PGE energy visualization charts"
|
|
)
|
|
parser.add_argument(
|
|
"base_filename",
|
|
help="Base filename used for the data and charts"
|
|
)
|
|
parser.add_argument(
|
|
"--charts-dir", "-c",
|
|
default="charts",
|
|
help="Directory containing chart PNG files (default: 'charts')"
|
|
)
|
|
parser.add_argument(
|
|
"--output", "-o",
|
|
help="Output HTML file path (default: dashboard_<base_filename>.html)"
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
try:
|
|
dashboard_path = create_html_dashboard(
|
|
base_filename=args.base_filename,
|
|
charts_dir=args.charts_dir,
|
|
output_file=args.output
|
|
)
|
|
|
|
print(f"\\nDashboard created successfully!")
|
|
print(f"Open in browser: file://{dashboard_path.absolute()}")
|
|
|
|
except Exception as e:
|
|
print(f"Error: {e}")
|
|
return 1
|
|
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
exit(main()) |