Feat: Chart preview function now working.

fix: chart formating and styling tweaks to match typical reports.
This commit is contained in:
2026-03-05 06:56:44 +00:00
parent 7fde14d882
commit 3637cf5af8

View File

@@ -1928,8 +1928,13 @@ async def generate_excel_report(
ws.title = "Sound Level Data" ws.title = "Sound Level Data"
# Define styles # Define styles
title_font = Font(bold=True, size=14) title_font = Font(name='Arial', bold=True, size=12)
header_font = Font(bold=True, size=10) subtitle_font = Font(name='Arial', bold=True, size=12)
client_font = Font(name='Arial', italic=True, size=10)
filter_font = Font(name='Arial', italic=True, size=10, color="666666")
header_font = Font(name='Arial', bold=True, size=10)
data_font = Font(name='Arial', size=10)
summary_title_font = Font(name='Arial', bold=True, size=12)
thin_border = Border( thin_border = Border(
left=Side(style='thin'), left=Side(style='thin'),
right=Side(style='thin'), right=Side(style='thin'),
@@ -1937,6 +1942,9 @@ async def generate_excel_report(
bottom=Side(style='thin') bottom=Side(style='thin')
) )
header_fill = PatternFill(start_color="DAEEF3", end_color="DAEEF3", fill_type="solid") header_fill = PatternFill(start_color="DAEEF3", end_color="DAEEF3", fill_type="solid")
center_align = Alignment(horizontal='center', vertical='center')
left_align = Alignment(horizontal='left', vertical='center')
right_align = Alignment(horizontal='right', vertical='center')
# Row 1: Report title # Row 1: Report title
final_project_name = project_name if project_name else (project.name if project else "") final_project_name = project_name if project_name else (project.name if project else "")
@@ -1945,12 +1953,17 @@ async def generate_excel_report(
final_title = f"{report_title} - {final_project_name}" final_title = f"{report_title} - {final_project_name}"
ws['A1'] = final_title ws['A1'] = final_title
ws['A1'].font = title_font ws['A1'].font = title_font
ws['A1'].alignment = center_align
ws.merge_cells('A1:G1') ws.merge_cells('A1:G1')
ws.row_dimensions[1].height = 20
# Row 2: Client name (if provided) # Row 2: Client name (if provided)
if client_name: if client_name:
ws['A2'] = f"Client: {client_name}" ws['A2'] = f"Client: {client_name}"
ws['A2'].font = Font(italic=True, size=10) ws['A2'].font = client_font
ws['A2'].alignment = center_align
ws.merge_cells('A2:G2')
ws.row_dimensions[2].height = 16
# Row 3: Location name # Row 3: Location name
final_location = location_name final_location = location_name
@@ -1958,7 +1971,10 @@ async def generate_excel_report(
final_location = location.name final_location = location.name
if final_location: if final_location:
ws['A3'] = final_location ws['A3'] = final_location
ws['A3'].font = Font(bold=True, size=11) ws['A3'].font = subtitle_font
ws['A3'].alignment = center_align
ws.merge_cells('A3:G3')
ws.row_dimensions[3].height = 20
# Row 4: Time filter info (if applied) # Row 4: Time filter info (if applied)
if start_time and end_time: if start_time and end_time:
@@ -1967,7 +1983,10 @@ async def generate_excel_report(
filter_info += f" | Date Range: {start_date or 'start'} to {end_date or 'end'}" filter_info += f" | Date Range: {start_date or 'start'} to {end_date or 'end'}"
filter_info += f" | {len(rnd_rows)} of {original_count} rows" filter_info += f" | {len(rnd_rows)} of {original_count} rows"
ws['A4'] = filter_info ws['A4'] = filter_info
ws['A4'].font = Font(italic=True, size=9, color="666666") ws['A4'].font = filter_font
ws['A4'].alignment = center_align
ws.merge_cells('A4:G4')
ws.row_dimensions[4].height = 14
# Row 7: Headers # Row 7: Headers
headers = ['Test Increment #', 'Date', 'Time', 'LAmax (dBA)', 'LA01 (dBA)', 'LA10 (dBA)', 'Comments'] headers = ['Test Increment #', 'Date', 'Time', 'LAmax (dBA)', 'LA01 (dBA)', 'LA10 (dBA)', 'Comments']
@@ -1976,10 +1995,11 @@ async def generate_excel_report(
cell.font = header_font cell.font = header_font
cell.border = thin_border cell.border = thin_border
cell.fill = header_fill cell.fill = header_fill
cell.alignment = Alignment(horizontal='center') cell.alignment = center_align
ws.row_dimensions[7].height = 16
# Set column widths # Set column widths — A-G sized to fit one printed page width
column_widths = [16, 12, 10, 12, 12, 12, 40] column_widths = [12, 11, 9, 11, 11, 11, 20]
for i, width in enumerate(column_widths, 1): for i, width in enumerate(column_widths, 1):
ws.column_dimensions[get_column_letter(i)].width = width ws.column_dimensions[get_column_letter(i)].width = width
@@ -1989,41 +2009,34 @@ async def generate_excel_report(
data_row = data_start_row + idx - 1 data_row = data_start_row + idx - 1
# Test Increment # # Test Increment #
ws.cell(row=data_row, column=1, value=idx).border = thin_border c = ws.cell(row=data_row, column=1, value=idx)
c.border = thin_border; c.font = data_font; c.alignment = center_align
# Parse the Start Time to get Date and Time # Parse the Start Time to get Date and Time
start_time_str = row.get('Start Time', '') start_time_str = row.get('Start Time', '')
if start_time_str: if start_time_str:
try: try:
# Format: "2025/12/26 20:23:38"
dt = datetime.strptime(start_time_str, '%Y/%m/%d %H:%M:%S') dt = datetime.strptime(start_time_str, '%Y/%m/%d %H:%M:%S')
ws.cell(row=data_row, column=2, value=dt.date()) c2 = ws.cell(row=data_row, column=2, value=dt.strftime('%m/%d/%y'))
ws.cell(row=data_row, column=3, value=dt.time()) c3 = ws.cell(row=data_row, column=3, value=dt.strftime('%H:%M'))
except ValueError: except ValueError:
ws.cell(row=data_row, column=2, value=start_time_str) c2 = ws.cell(row=data_row, column=2, value=start_time_str)
ws.cell(row=data_row, column=3, value='') c3 = ws.cell(row=data_row, column=3, value='')
else: else:
ws.cell(row=data_row, column=2, value='') c2 = ws.cell(row=data_row, column=2, value='')
ws.cell(row=data_row, column=3, value='') c3 = ws.cell(row=data_row, column=3, value='')
for c in (c2, c3):
c.border = thin_border; c.font = data_font; c.alignment = center_align
# LAmax - from Lmax(Main) # LAmax, LA01, LA10
lmax = row.get('Lmax(Main)') for col_idx, key in [(4, 'Lmax(Main)'), (5, 'LN1(Main)'), (6, 'LN2(Main)')]:
ws.cell(row=data_row, column=4, value=lmax if lmax else '').border = thin_border val = row.get(key)
c = ws.cell(row=data_row, column=col_idx, value=val if val else '')
c.border = thin_border; c.font = data_font; c.alignment = right_align
# LA01 - from LN1(Main) # Comments
ln1 = row.get('LN1(Main)') c = ws.cell(row=data_row, column=7, value='')
ws.cell(row=data_row, column=5, value=ln1 if ln1 else '').border = thin_border c.border = thin_border; c.font = data_font; c.alignment = left_align
# LA10 - from LN2(Main)
ln2 = row.get('LN2(Main)')
ws.cell(row=data_row, column=6, value=ln2 if ln2 else '').border = thin_border
# Comments (empty for now, can be populated)
ws.cell(row=data_row, column=7, value='').border = thin_border
# Apply borders to date/time cells
ws.cell(row=data_row, column=2).border = thin_border
ws.cell(row=data_row, column=3).border = thin_border
data_end_row = data_start_row + len(rnd_rows) - 1 data_end_row = data_start_row + len(rnd_rows) - 1
@@ -2032,13 +2045,13 @@ async def generate_excel_report(
chart.title = f"{final_location or 'Sound Level Data'} - Background Noise Study" chart.title = f"{final_location or 'Sound Level Data'} - Background Noise Study"
chart.style = 10 chart.style = 10
chart.y_axis.title = "Sound Level (dBA)" chart.y_axis.title = "Sound Level (dBA)"
chart.x_axis.title = "Test Increment" chart.x_axis.title = "Time"
chart.height = 12 chart.height = 18
chart.width = 20 chart.width = 22
# Data references (LAmax, LA01, LA10 are columns D, E, F) # Data references (LAmax, LA01, LA10 are columns D, E, F)
data_ref = Reference(ws, min_col=4, min_row=7, max_col=6, max_row=data_end_row) data_ref = Reference(ws, min_col=4, min_row=7, max_col=6, max_row=data_end_row)
categories = Reference(ws, min_col=1, min_row=data_start_row, max_row=data_end_row) categories = Reference(ws, min_col=3, min_row=data_start_row, max_row=data_end_row)
chart.add_data(data_ref, titles_from_data=True) chart.add_data(data_ref, titles_from_data=True)
chart.set_categories(categories) chart.set_categories(categories)
@@ -2049,12 +2062,20 @@ async def generate_excel_report(
chart.series[1].graphicalProperties.line.solidFill = "00B050" # LA01 - Green chart.series[1].graphicalProperties.line.solidFill = "00B050" # LA01 - Green
chart.series[2].graphicalProperties.line.solidFill = "0070C0" # LA10 - Blue chart.series[2].graphicalProperties.line.solidFill = "0070C0" # LA10 - Blue
# Position chart to the right of data # Position chart starting at column H
ws.add_chart(chart, "I3") ws.add_chart(chart, "H3")
# Print layout: A-G fits one page width, landscape
from openpyxl.worksheet.properties import PageSetupProperties
ws.sheet_properties.pageSetUpPr = PageSetupProperties(fitToPage=True)
ws.page_setup.orientation = 'landscape'
ws.page_setup.fitToWidth = 1
ws.page_setup.fitToHeight = 0
# Add summary statistics section below the data # Add summary statistics section below the data
summary_row = data_end_row + 3 summary_row = data_end_row + 3
ws.cell(row=summary_row, column=1, value="Summary Statistics").font = Font(bold=True, size=12) c = ws.cell(row=summary_row, column=1, value="Summary Statistics")
c.font = summary_title_font
# Calculate time-period statistics # Calculate time-period statistics
time_periods = { time_periods = {
@@ -2097,43 +2118,45 @@ async def generate_excel_report(
cell.font = header_font cell.font = header_font
cell.fill = header_fill cell.fill = header_fill
cell.border = thin_border cell.border = thin_border
cell.alignment = center_align
# Summary data # Summary data
summary_row += 1 summary_row += 1
for period_name, samples in time_periods.items(): for period_name, samples in time_periods.items():
ws.cell(row=summary_row, column=1, value=period_name).border = thin_border c = ws.cell(row=summary_row, column=1, value=period_name)
ws.cell(row=summary_row, column=2, value=len(samples)).border = thin_border c.border = thin_border; c.font = data_font; c.alignment = left_align
c = ws.cell(row=summary_row, column=2, value=len(samples))
c.border = thin_border; c.font = data_font; c.alignment = center_align
if samples: if samples:
avg_lmax = sum(s['lmax'] for s in samples) / len(samples) avg_lmax = sum(s['lmax'] for s in samples) / len(samples)
avg_ln1 = sum(s['ln1'] for s in samples) / len(samples) avg_ln1 = sum(s['ln1'] for s in samples) / len(samples)
avg_ln2 = sum(s['ln2'] for s in samples) / len(samples) avg_ln2 = sum(s['ln2'] for s in samples) / len(samples)
ws.cell(row=summary_row, column=3, value=round(avg_lmax, 1)).border = thin_border for col_idx, val in [(3, avg_lmax), (4, avg_ln1), (5, avg_ln2)]:
ws.cell(row=summary_row, column=4, value=round(avg_ln1, 1)).border = thin_border c = ws.cell(row=summary_row, column=col_idx, value=round(val, 1))
ws.cell(row=summary_row, column=5, value=round(avg_ln2, 1)).border = thin_border c.border = thin_border; c.font = data_font; c.alignment = right_align
else: else:
ws.cell(row=summary_row, column=3, value='-').border = thin_border for col_idx in [3, 4, 5]:
ws.cell(row=summary_row, column=4, value='-').border = thin_border c = ws.cell(row=summary_row, column=col_idx, value='-')
ws.cell(row=summary_row, column=5, value='-').border = thin_border c.border = thin_border; c.font = data_font; c.alignment = center_align
summary_row += 1 summary_row += 1
# Overall summary # Overall summary
summary_row += 1 summary_row += 1
ws.cell(row=summary_row, column=1, value='Overall').font = Font(bold=True) c = ws.cell(row=summary_row, column=1, value='Overall')
ws.cell(row=summary_row, column=1).border = thin_border c.font = Font(name='Arial', bold=True, size=10); c.border = thin_border; c.alignment = left_align
ws.cell(row=summary_row, column=2, value=len(rnd_rows)).border = thin_border c = ws.cell(row=summary_row, column=2, value=len(rnd_rows))
c.border = thin_border; c.font = data_font; c.alignment = center_align
all_lmax = [r.get('Lmax(Main)') for r in rnd_rows if isinstance(r.get('Lmax(Main)'), (int, float))] all_lmax = [r.get('Lmax(Main)') for r in rnd_rows if isinstance(r.get('Lmax(Main)'), (int, float))]
all_ln1 = [r.get('LN1(Main)') for r in rnd_rows if isinstance(r.get('LN1(Main)'), (int, float))] all_ln1 = [r.get('LN1(Main)') for r in rnd_rows if isinstance(r.get('LN1(Main)'), (int, float))]
all_ln2 = [r.get('LN2(Main)') for r in rnd_rows if isinstance(r.get('LN2(Main)'), (int, float))] all_ln2 = [r.get('LN2(Main)') for r in rnd_rows if isinstance(r.get('LN2(Main)'), (int, float))]
if all_lmax: for col_idx, vals in [(3, all_lmax), (4, all_ln1), (5, all_ln2)]:
ws.cell(row=summary_row, column=3, value=round(sum(all_lmax) / len(all_lmax), 1)).border = thin_border if vals:
if all_ln1: c = ws.cell(row=summary_row, column=col_idx, value=round(sum(vals) / len(vals), 1))
ws.cell(row=summary_row, column=4, value=round(sum(all_ln1) / len(all_ln1), 1)).border = thin_border c.border = thin_border; c.font = data_font; c.alignment = right_align
if all_ln2:
ws.cell(row=summary_row, column=5, value=round(sum(all_ln2) / len(all_ln2), 1)).border = thin_border
# Save to buffer # Save to buffer
output = io.BytesIO() output = io.BytesIO()
@@ -2344,7 +2367,7 @@ async def preview_report_data(
final_location = location_name if location_name else (location.name if location else "") final_location = location_name if location_name else (location.name if location else "")
# Get templates for the dropdown # Get templates for the dropdown
templates = db.query(ReportTemplate).all() report_templates = db.query(ReportTemplate).all()
return templates.TemplateResponse("report_preview.html", { return templates.TemplateResponse("report_preview.html", {
"request": request, "request": request,
@@ -2364,7 +2387,7 @@ async def preview_report_data(
"end_date": end_date, "end_date": end_date,
"original_count": original_count, "original_count": original_count,
"filtered_count": len(rnd_rows), "filtered_count": len(rnd_rows),
"templates": templates, "templates": report_templates,
}) })
@@ -2419,8 +2442,12 @@ async def generate_report_from_preview(
ws.title = "Sound Level Data" ws.title = "Sound Level Data"
# Styles # Styles
title_font = Font(bold=True, size=14) title_font = Font(name='Arial', bold=True, size=12)
header_font = Font(bold=True, size=10) subtitle_font = Font(name='Arial', bold=True, size=12)
client_font = Font(name='Arial', italic=True, size=10)
filter_font = Font(name='Arial', italic=True, size=10, color="666666")
header_font = Font(name='Arial', bold=True, size=10)
data_font = Font(name='Arial', size=10)
thin_border = Border( thin_border = Border(
left=Side(style='thin'), left=Side(style='thin'),
right=Side(style='thin'), right=Side(style='thin'),
@@ -2428,27 +2455,41 @@ async def generate_report_from_preview(
bottom=Side(style='thin') bottom=Side(style='thin')
) )
header_fill = PatternFill(start_color="DAEEF3", end_color="DAEEF3", fill_type="solid") header_fill = PatternFill(start_color="DAEEF3", end_color="DAEEF3", fill_type="solid")
center_align = Alignment(horizontal='center', vertical='center')
left_align = Alignment(horizontal='left', vertical='center')
right_align = Alignment(horizontal='right', vertical='center')
# Row 1: Title # Row 1: Title
final_title = f"{report_title} - {project_name}" if project_name else report_title final_title = f"{report_title} - {project_name}" if project_name else report_title
ws['A1'] = final_title ws['A1'] = final_title
ws['A1'].font = title_font ws['A1'].font = title_font
ws['A1'].alignment = center_align
ws.merge_cells('A1:G1') ws.merge_cells('A1:G1')
ws.row_dimensions[1].height = 20
# Row 2: Client # Row 2: Client
if client_name: if client_name:
ws['A2'] = f"Client: {client_name}" ws['A2'] = f"Client: {client_name}"
ws['A2'].font = Font(italic=True, size=10) ws['A2'].font = client_font
ws['A2'].alignment = center_align
ws.merge_cells('A2:G2')
ws.row_dimensions[2].height = 16
# Row 3: Location # Row 3: Location
if location_name: if location_name:
ws['A3'] = location_name ws['A3'] = location_name
ws['A3'].font = Font(bold=True, size=11) ws['A3'].font = subtitle_font
ws['A3'].alignment = center_align
ws.merge_cells('A3:G3')
ws.row_dimensions[3].height = 20
# Row 4: Time filter info # Row 4: Time filter info
if time_filter: if time_filter:
ws['A4'] = time_filter ws['A4'] = time_filter
ws['A4'].font = Font(italic=True, size=9, color="666666") ws['A4'].font = filter_font
ws['A4'].alignment = center_align
ws.merge_cells('A4:G4')
ws.row_dimensions[4].height = 14
# Row 7: Headers # Row 7: Headers
headers = ['Test Increment #', 'Date', 'Time', 'LAmax (dBA)', 'LA01 (dBA)', 'LA10 (dBA)', 'Comments'] headers = ['Test Increment #', 'Date', 'Time', 'LAmax (dBA)', 'LA01 (dBA)', 'LA10 (dBA)', 'Comments']
@@ -2457,20 +2498,24 @@ async def generate_report_from_preview(
cell.font = header_font cell.font = header_font
cell.border = thin_border cell.border = thin_border
cell.fill = header_fill cell.fill = header_fill
cell.alignment = Alignment(horizontal='center') cell.alignment = center_align
ws.row_dimensions[7].height = 16
# Column widths # Column widths — A-G sized to fit one printed page width
column_widths = [16, 12, 10, 12, 12, 12, 40] column_widths = [12, 11, 9, 11, 11, 11, 20]
for i, width in enumerate(column_widths, 1): for i, width in enumerate(column_widths, 1):
ws.column_dimensions[get_column_letter(i)].width = width ws.column_dimensions[get_column_letter(i)].width = width
# Data rows # Data rows
data_start_row = 8 data_start_row = 8
col_aligns = [center_align, center_align, center_align, right_align, right_align, right_align, left_align]
for idx, row_data in enumerate(spreadsheet_data): for idx, row_data in enumerate(spreadsheet_data):
data_row = data_start_row + idx data_row = data_start_row + idx
for col, value in enumerate(row_data, 1): for col, value in enumerate(row_data, 1):
cell = ws.cell(row=data_row, column=col, value=value if value != '' else None) cell = ws.cell(row=data_row, column=col, value=value if value != '' else None)
cell.border = thin_border cell.border = thin_border
cell.font = data_font
cell.alignment = col_aligns[col - 1] if col <= len(col_aligns) else left_align
data_end_row = data_start_row + len(spreadsheet_data) - 1 data_end_row = data_start_row + len(spreadsheet_data) - 1
@@ -2480,12 +2525,12 @@ async def generate_report_from_preview(
chart.title = f"{location_name or 'Sound Level Data'} - Background Noise Study" chart.title = f"{location_name or 'Sound Level Data'} - Background Noise Study"
chart.style = 10 chart.style = 10
chart.y_axis.title = "Sound Level (dBA)" chart.y_axis.title = "Sound Level (dBA)"
chart.x_axis.title = "Test Increment" chart.x_axis.title = "Time"
chart.height = 12 chart.height = 18
chart.width = 20 chart.width = 22
data_ref = Reference(ws, min_col=4, min_row=7, max_col=6, max_row=data_end_row) data_ref = Reference(ws, min_col=4, min_row=7, max_col=6, max_row=data_end_row)
categories = Reference(ws, min_col=1, min_row=data_start_row, max_row=data_end_row) categories = Reference(ws, min_col=3, min_row=data_start_row, max_row=data_end_row)
chart.add_data(data_ref, titles_from_data=True) chart.add_data(data_ref, titles_from_data=True)
chart.set_categories(categories) chart.set_categories(categories)
@@ -2495,7 +2540,14 @@ async def generate_report_from_preview(
chart.series[1].graphicalProperties.line.solidFill = "00B050" chart.series[1].graphicalProperties.line.solidFill = "00B050"
chart.series[2].graphicalProperties.line.solidFill = "0070C0" chart.series[2].graphicalProperties.line.solidFill = "0070C0"
ws.add_chart(chart, "I3") ws.add_chart(chart, "H3")
# Print layout: A-G fits one page width, landscape
from openpyxl.worksheet.properties import PageSetupProperties
ws.sheet_properties.pageSetUpPr = PageSetupProperties(fitToPage=True)
ws.page_setup.orientation = 'landscape'
ws.page_setup.fitToWidth = 1
ws.page_setup.fitToHeight = 0
# Save to buffer # Save to buffer
output = io.BytesIO() output = io.BytesIO()
@@ -2584,8 +2636,9 @@ async def generate_combined_excel_report(
raise HTTPException(status_code=404, detail="No Leq measurement files found in project. Reports require Leq data (files with '_Leq_' in the name).") raise HTTPException(status_code=404, detail="No Leq measurement files found in project. Reports require Leq data (files with '_Leq_' in the name).")
# Define styles # Define styles
title_font = Font(bold=True, size=14) title_font = Font(name='Arial', bold=True, size=12)
header_font = Font(bold=True, size=10) header_font = Font(name='Arial', bold=True, size=10)
data_font = Font(name='Arial', size=10)
thin_border = Border( thin_border = Border(
left=Side(style='thin'), left=Side(style='thin'),
right=Side(style='thin'), right=Side(style='thin'),
@@ -2593,6 +2646,9 @@ async def generate_combined_excel_report(
bottom=Side(style='thin') bottom=Side(style='thin')
) )
header_fill = PatternFill(start_color="DAEEF3", end_color="DAEEF3", fill_type="solid") header_fill = PatternFill(start_color="DAEEF3", end_color="DAEEF3", fill_type="solid")
center_align = Alignment(horizontal='center', vertical='center')
left_align = Alignment(horizontal='left', vertical='center')
right_align = Alignment(horizontal='right', vertical='center')
# Create Excel workbook # Create Excel workbook
wb = openpyxl.Workbook() wb = openpyxl.Workbook()
@@ -2613,11 +2669,16 @@ async def generate_combined_excel_report(
final_title = f"{report_title} - {project.name}" final_title = f"{report_title} - {project.name}"
ws['A1'] = final_title ws['A1'] = final_title
ws['A1'].font = title_font ws['A1'].font = title_font
ws['A1'].alignment = center_align
ws.merge_cells('A1:G1') ws.merge_cells('A1:G1')
ws.row_dimensions[1].height = 20
# Row 3: Location name # Row 3: Location name
ws['A3'] = location_name ws['A3'] = location_name
ws['A3'].font = Font(bold=True, size=11) ws['A3'].font = Font(name='Arial', bold=True, size=12)
ws['A3'].alignment = center_align
ws.merge_cells('A3:G3')
ws.row_dimensions[3].height = 20
# Row 7: Headers # Row 7: Headers
headers = ['Test Increment #', 'Date', 'Time', 'LAmax (dBA)', 'LA01 (dBA)', 'LA10 (dBA)', 'Comments'] headers = ['Test Increment #', 'Date', 'Time', 'LAmax (dBA)', 'LA01 (dBA)', 'LA10 (dBA)', 'Comments']
@@ -2626,10 +2687,11 @@ async def generate_combined_excel_report(
cell.font = header_font cell.font = header_font
cell.border = thin_border cell.border = thin_border
cell.fill = header_fill cell.fill = header_fill
cell.alignment = Alignment(horizontal='center') cell.alignment = center_align
ws.row_dimensions[7].height = 16
# Set column widths # Set column widths — A-G sized to fit one printed page width
column_widths = [16, 12, 10, 12, 12, 12, 40] column_widths = [12, 11, 9, 11, 11, 11, 20]
for i, width in enumerate(column_widths, 1): for i, width in enumerate(column_widths, 1):
ws.column_dimensions[get_column_letter(i)].width = width ws.column_dimensions[get_column_letter(i)].width = width
@@ -2712,12 +2774,12 @@ async def generate_combined_excel_report(
chart.title = f"{location_name}" chart.title = f"{location_name}"
chart.style = 10 chart.style = 10
chart.y_axis.title = "Sound Level (dBA)" chart.y_axis.title = "Sound Level (dBA)"
chart.x_axis.title = "Test Increment" chart.x_axis.title = "Time"
chart.height = 12 chart.height = 18
chart.width = 20 chart.width = 22
data_ref = Reference(ws, min_col=4, min_row=7, max_col=6, max_row=data_end_row) data_ref = Reference(ws, min_col=4, min_row=7, max_col=6, max_row=data_end_row)
categories = Reference(ws, min_col=1, min_row=data_start_row, max_row=data_end_row) categories = Reference(ws, min_col=3, min_row=data_start_row, max_row=data_end_row)
chart.add_data(data_ref, titles_from_data=True) chart.add_data(data_ref, titles_from_data=True)
chart.set_categories(categories) chart.set_categories(categories)
@@ -2727,7 +2789,14 @@ async def generate_combined_excel_report(
chart.series[1].graphicalProperties.line.solidFill = "00B050" chart.series[1].graphicalProperties.line.solidFill = "00B050"
chart.series[2].graphicalProperties.line.solidFill = "0070C0" chart.series[2].graphicalProperties.line.solidFill = "0070C0"
ws.add_chart(chart, "I3") ws.add_chart(chart, "H3")
# Print layout: A-G fits one page width, landscape
from openpyxl.worksheet.properties import PageSetupProperties
ws.sheet_properties.pageSetUpPr = PageSetupProperties(fitToPage=True)
ws.page_setup.orientation = 'landscape'
ws.page_setup.fitToWidth = 1
ws.page_setup.fitToHeight = 0
# Calculate summary for this location # Calculate summary for this location
all_lmax = [r.get('Lmax(Main)') for r in all_rnd_rows if isinstance(r.get('Lmax(Main)'), (int, float))] all_lmax = [r.get('Lmax(Main)') for r in all_rnd_rows if isinstance(r.get('Lmax(Main)'), (int, float))]