xlsx-processing-manus

Professional Excel spreadsheet creation with a focus on aesthetics and data analysis. Use when creating spreadsheets for organizing, analyzing, and presenting structured data in a clear and professional format.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "xlsx-processing-manus" with this command: npx skills add lawvable/awesome-legal-skills/lawvable-awesome-legal-skills-xlsx-processing-manus

Excel Generator Skill

Goal

Make the user able to use the Excel immediately and gain insights upon opening.

Core Principle

Enrich visuals as much as possible, while ensuring content clarity and not adding cognitive burden. Every visual element should be meaningful and purposeful—serving the content, not decorating it.


Part 1: User Needs & Feature Matching

Before creating any Excel, think through:

  1. What does the user need? — Not "an Excel file", but what problem are they solving?
  2. What can I provide? — Which features will help them?
  3. How to match? — Select the right combination for this specific scenario.

Feature ↔ User Value Pairs

Help Users「Understand Data」

FeatureUser ValueWhen to Use
Bar/Column ChartSee comparisons at a glanceComparing values across categories
Line ChartSee trends at a glanceTime series data
Pie ChartSee proportions at a glancePart-to-whole (≤6 categories)
Data BarsCompare magnitude without leaving the cellNumeric columns needing quick comparison
Color ScaleHeatmap effect, patterns pop outMatrices, ranges, distributions
SparklinesSee trend within a single cellSummary rows with historical context

Help Users「Find What Matters」

FeatureUser ValueWhen to Use
Pre-sortingMost important data comes firstRankings, Top N, priorities
Conditional HighlightingKey data stands out automaticallyOutliers, thresholds, Top/Bottom N
Icon SetsStatus visible at a glanceKPI status, categorical states (use sparingly)
Bold/Color EmphasisVisual distinction between primary and secondarySummary rows, key metrics
KEY INSIGHTS SectionConclusions delivered directlyAnalytical reports

Help Users「Save Time」

FeatureUser ValueWhen to Use
Overview SheetSummary on first page, no huntingAll multi-sheet files
Pre-calculated SummariesResults ready, no manual calculationData requiring statistics
Consistent Number FormatsNo format adjustments neededAll numeric data
Freeze PanesHeaders visible while scrollingTables with >10 rows
Sheet Index with LinksQuick navigation, no guessingFiles with >3 sheets

Help Users「Use Directly」

FeatureUser ValueWhen to Use
FiltersUsers can explore data themselvesExploratory analysis needs
HyperlinksClick to navigate, no manual switchingCross-sheet references, external sources
Print-friendly LayoutReady to print or export to PDFReports for sharing
Formulas (not hardcoded)Change parameters, results updateModels, forecasts, adjustable scenarios
Data Validation DropdownsPrevent input errorsTemplates requiring user input

Help Users「Trust the Data」

FeatureUser ValueWhen to Use
Data Source AttributionKnow where data comes fromAll external data
Generation DateKnow data freshnessTime-sensitive reports
Data Time RangeKnow what period is coveredTime series data
Professional FormattingLooks reliableAll external-facing files
Consistent PrecisionNo doubts about accuracyAll numeric values

Help Users「Gain Insights」

FeatureUser ValueWhen to Use
Comparison Columns (Δ, %)No manual calculation for comparisonsYoY, MoM, A vs B
Rank ColumnPosition visible directlyCompetitive analysis, performance
Grouped SummariesAggregated results by dimensionSegmented analysis
Trend Indicators (↑↓)Direction clear at a glanceChange direction matters
Insight TextThe "so what" is stated explicitlyAnalytical reports

Part 2: Four-Layer Implementation

Layer 1: Structure (How It's Organized)

Goal: Logical, easy to navigate, user finds what they need immediately.

Sheet Organization

GuidelineRecommendation
Sheet count3-5 ideal, max 7
First sheetAlways "Overview" with summary and navigation
Sheet orderGeneral → Specific (Overview → Data → Analysis)
NamingClear, concise (e.g., "Revenue Data", not "Sheet1")

Information Architecture

  • Overview sheet must stand alone: User should understand the main message without opening other sheets
  • Progressive disclosure: Summary first, details available for those who want to dig deeper
  • Consistent structure across sheets: Same layout patterns, same starting positions

Layout Rules

ElementPosition
Left marginColumn A empty (width 3)
Top marginRow 1 empty
Content startCell B2
Section spacing1 empty row between sections
Table spacing2 empty rows between tables
ChartsBelow all tables (2 rows gap), or right of related table

Chart placement:

  • Default: below all tables, left-aligned with content
  • Alternative: right of a single related table
  • Charts must never overlap each other or tables

Standalone Text Rows

For rows with a single text cell (titles, descriptions, notes, bullet points), text will naturally extend into empty cells to the right. However, text is clipped if right cells contain any content (including spaces).

Decision logic:

ConditionAction
Right cells guaranteed emptyNo action needed—text extends naturally
Right cells may have contentMerge cells to content width, or wrap text
Text exceeds content area widthWrap text + set row height manually

Technical note: Fill and border alone do NOT block text overflow—only actual cell content (including space characters) blocks it.

Navigation

For files with 3+ sheets, include a Sheet Index on Overview:

# Sheet Index with hyperlinks
ws['B5'] = "CONTENTS"
ws['B5'].font = Font(name=SERIF_FONT, size=14, bold=True, color=THEME['accent'])

sheets = ["Overview", "Data", "Analysis"]
for i, sheet_name in enumerate(sheets, start=6):
    cell = ws.cell(row=i, column=2, value=sheet_name)
    cell.hyperlink = f"#'{sheet_name}'!A1"
    cell.font = Font(color=THEME['accent'], underline='single')

Layer 2: Information (What They Learn)

Goal: Accurate, complete, insightful—user gains knowledge, not just data.

Number Formats

Critical rules:

  1. Every numeric cell must have number_format set — both input values AND formula results
  2. Same column = same precision — never mix 0.1074 and 1.0 in one column
  3. Formula results have no default format — they display raw precision unless explicitly formatted
Data TypeFormat CodeExample
Integer#,##01,234,567
Decimal (1)#,##0.01,234.6
Decimal (2)#,##0.001,234.56
Percentage0.0%12.3%
Currency$#,##0.00$1,234.56

Common mistake: Setting format only for input cells, forgetting formula cells.

# WRONG: Formula cell without number_format
ws['C10'] = '=C7-C9'  # Will display raw precision like 14.123456789

# CORRECT: Always set number_format for formula cells
ws['C10'] = '=C7-C9'
ws['C10'].number_format = '#,##0.0'  # Displays as 14.1

# Best practice: Define format by column/data type, apply to ALL cells
for row in range(data_start, data_end + 1):
    cell = ws.cell(row=row, column=value_col)
    cell.number_format = '#,##0.0'  # Applies to both values and formulas

Data Context

Every data set needs context:

ElementLocationExample
Data sourceOverview or sheet footer"Source: Company Annual Report 2024"
Time rangeNear title or in subtitle"Data from Jan 2020 - Dec 2024"
Generation dateOverview footer"Generated: 2024-01-15"
DefinitionsNotes section or separate sheet"Revenue = Net sales excluding returns"

Key Insights

For analytical content, don't just present data—tell the user what it means:

ws['B20'] = "KEY INSIGHTS"
ws['B20'].font = Font(name=SERIF_FONT, size=14, bold=True, color=THEME['accent'])

insights = [
    "• Revenue grew 23% YoY, driven primarily by APAC expansion",
    "• Top 3 customers account for 45% of total revenue",
    "• Q4 showed strongest performance across all metrics"
]
for i, insight in enumerate(insights, start=21):
    ws.cell(row=i, column=2, value=insight)

Content Completeness

CheckAction
Missing valuesShow as blank or "N/A", never 0 unless actually zero
Calculated fieldsInclude formula or note explaining calculation
AbbreviationsDefine on first use or in notes
UnitsInclude in header (e.g., "Revenue ($M)")

Layer 3: Visual (What They See)

Goal: Professional appearance, immediate sense of value, visuals serve content.

Essential Setup

from openpyxl.styles import Font, PatternFill, Alignment, Border, Side

# Hide gridlines for cleaner look
ws.sheet_view.showGridLines = False

# Left margin
ws.column_dimensions['A'].width = 3

Theme System

Choose ONE theme per workbook. All visual elements derive from the theme color.

Available Themes (select based on context, or let user specify):

ThemePrimaryLightUse Case
Elegant Black2D2D2DE5E5E5Luxury, fashion, premium reports (recommended default)
Corporate Blue1F4E79D6E3F0Finance, corporate analysis
Forest Green2E5A4CD4E5DESustainability, environmental
Burgundy722F37E8D5D7Luxury brands, wine industry
Slate Gray4A5568E2E8F0Tech, modern, minimalist
Navy1E3A5FD3DCE6Government, maritime, institutional
Charcoal36454FDDE1E4Professional, executive
Deep Purple4A235AE1D5E7Creative, innovation, premium tech
Teal1A5F5FD3E5E5Healthcare, wellness
Warm Brown5D4037E6DDD9Natural, organic, artisan
Royal Blue1A237ED3D5E8Academic, institutional
Olive556B2FE0E5D5Military, outdoor

Theme Configuration:

# === THEME CONFIGURATION ===
THEMES = {
    'elegant_black': {
        'primary': '2D2D2D',
        'light': 'E5E5E5',
        'accent': '2D2D2D',
        'chart_colors': ['2D2D2D', '4A4A4A', '6B6B6B', '8C8C8C', 'ADADAD', 'CFCFCF'],
    },
    'corporate_blue': {
        'primary': '1F4E79',
        'light': 'D6E3F0',
        'accent': '1F4E79',
        'chart_colors': ['1F4E79', '2E75B6', '5B9BD5', '9DC3E6', 'BDD7EE', 'DEEBF7'],
    },
    # ... other themes follow same pattern
}

THEME = THEMES['elegant_black']  # Default
SERIF_FONT = 'Source Serif Pro'   # or 'Georgia' as fallback
SANS_FONT = 'Source Sans Pro'     # or 'Calibri' as fallback

How Theme Colors Apply:

ElementColorBackground
Document titleTHEME['primary']None
Section headerTHEME['primary']None or THEME['light']
Table headerWhiteTHEME['primary']
Data cellsBlackNone or alternating F9F9F9
Chart elementsTHEME['chart_colors']

Semantic Colors

For data meaning (independent of theme):

SemanticColorUse
Positive2E7D32Growth, profit, success
NegativeC62828Decline, loss, failure
WarningF57C00Caution, attention

Row Highlight Colors

For row-level emphasis. Use high-lightness tints (85-95% lightness) for subtle distinction.

SemanticHexHueUse
EmphasisE6F3FF209°Top rated, important data
SectionFFF3E037°Section dividers
InputFFFDE755°Editable cells
SpecialFFF9C455°Base case, benchmarks
SuccessE8F5E9125°Passed, completed
WarningFFCCBC14°Needs attention

Rule: Same semantic = same color. Different semantic = different color.

HIGHLIGHT = {
    'emphasis': 'E6F3FF',
    'section': 'FFF3E0',
    'input': 'FFFDE7',
    'special': 'FFF9C4',
    'success': 'E8F5E9',
    'warning': 'FFCCBC',
}

Typography

Use serif + sans-serif pairing. Serif for hierarchy (titles, headers); sans-serif for data (tabular figures).

Font Pairings (in preference order):

Serif (Titles)Sans-Serif (Data)Notes
Source Serif ProSource Sans ProAdobe superfamily, recommended
IBM Plex SerifIBM Plex SansModern, corporate
GeorgiaCalibriPre-installed fallback

Hierarchy:

ElementFontSizeStyle
Document titleSerif18-22Bold, Primary color
Section headerSerif12-14Bold, Primary color
Table headerSerif10-11Bold, White
Data cellsSans-Serif11Regular, Black
NotesSans-Serif9-10Italic, 666666
# Document title
ws['B2'].font = Font(name=SERIF_FONT, size=18, bold=True, color=THEME['primary'])

# Section header
ws['B6'].font = Font(name=SERIF_FONT, size=14, bold=True, color=THEME['primary'])

# Table header
header_font = Font(name=SERIF_FONT, size=10, bold=True, color='FFFFFF')

# Data cells
data_font = Font(name=SANS_FONT, size=11)

# Notes
notes_font = Font(name=SANS_FONT, size=10, italic=True, color='666666')

Data Block Definition

A Data Block is a group of continuous, non-empty rows that form a visual unit requiring borders. Data Blocks are separated by empty rows.

Identification rules:

  1. Scan from Section Header downward
  2. Non-empty row starts a Data Block
  3. Empty row ends the current Data Block
  4. Each Data Block gets its own outer frame

Data Block types:

TypeStructureExample
With HeaderHeader row + data rowsTable with column titles
Without HeaderData rows onlyContinuation data, sub-tables

Example recognition:

Row 5: Section Header "INCOME STATEMENT"   → No border (not a Data Block)
Row 6: Empty                               → Separator
Row 7: Header (Item, Year1, Year2...)      → Data Block 1 starts
Row 8: Revenue, 47061, 48943...            
Row 9: Growth Rate, 4.0%, 3.5%...          → Data Block 1 ends
Row 10: Empty                              → Separator
Row 11: EBITDA, 12121, 12627...            → Data Block 2 starts (no header)
Row 12: EBITDA Margin, 25.8%, 25.8%...     → Data Block 2 ends
Row 13: Empty                              → Separator
Row 14: D&A, 1200, 1224...                 → Data Block 3 starts (no header)
Row 15: EBIT, 10921, 11404...              
Row 16: EBIT Margin, 23.2%, 23.3%...       → Data Block 3 ends

Result: 3 separate Data Blocks, each with its own outer frame.

Border Rules

Recommended style: Horizontal-only — cleaner, more modern.

Each Data Block must have:

Border TypeWhere
Outer frameAll 4 sides of Data Block (top, bottom, left, right)
Header bottomMedium weight, theme primary color (if has header)
Internal horizontalThin, between all rows
Internal verticalNone (omit for cleaner look)

Critical: Every cell in the Data Block must have its border set. Do not only set header and label cells—data cells need borders too.

# Border definitions
outer_border = Side(style='thin', color='D1D1D1')
header_bottom = Side(style='medium', color=THEME['primary'])
inner_horizontal = Side(style='thin', color='D1D1D1')
no_border = Side(style=None)

def apply_data_block_borders(ws, start_row, end_row, start_col, end_col, has_header=True):
    """
    Apply borders to a Data Block.
    Every cell must be processed—not just headers and labels.
    """
    for row in range(start_row, end_row + 1):
        for col in range(start_col, end_col + 1):
            cell = ws.cell(row=row, column=col)
            
            # Left/Right: outer frame
            left = outer_border if col == start_col else no_border
            right = outer_border if col == end_col else no_border
            
            # Top: outer for first row, inner horizontal for others
            top = outer_border if row == start_row else inner_horizontal
            
            # Bottom: header_bottom for header, outer for last row, inner for middle
            if has_header and row == start_row:
                bottom = header_bottom
            elif row == end_row:
                bottom = outer_border
            else:
                bottom = inner_horizontal
            
            cell.border = Border(left=left, right=right, top=top, bottom=bottom)

Non-Data-Block elements (titles, section headers, standalone text, notes): No border.

Alignment

Headers: Center.

Data cells:

ContentHorizontal
Short text (words)Center
Long text (sentences)Left + indent=1
NumbersRight
Dates, StatusCenter

Vertical: Always center (including wrapped text).

# Left-aligned text with padding
cell.alignment = Alignment(horizontal='left', vertical='center', indent=1)

# Numbers
cell.alignment = Alignment(horizontal='right', vertical='center')

# Wrapped text
cell.alignment = Alignment(horizontal='left', vertical='center', wrap_text=True, indent=1)

Column Width

Calculation scope: Only Data Block cells. Exclude standalone text rows, section headers, and notes.

Formula: max(max_content_length_in_data_blocks + padding, minimum)

Column TypePaddingMinimumNotes
Label/Text+415First column usually
Numbers+614Extra space for formatted numbers (negative signs, commas)
Long text+420, max 40Wrap if exceeds max

Design constraint: Same column across different Data Blocks should serve similar roles. Column width is determined by the widest content across all Data Blocks in that column.

Standalone text rows: Do NOT include in column width calculation. Let text extend naturally or use wrap/merge.

def calculate_column_width(ws, col, data_block_ranges):
    """
    Calculate column width based only on Data Block content.
    Standalone text rows are excluded.
    
    data_block_ranges: list of (start_row, end_row) tuples
    """
    max_len = 0
    is_numeric = True
    
    for start_row, end_row in data_block_ranges:
        for row in range(start_row, end_row + 1):
            cell = ws.cell(row=row, column=col)
            if cell.value:
                # Get formatted display length
                display_value = str(cell.value)
                max_len = max(max_len, len(display_value))
                if not isinstance(cell.value, (int, float)):
                    is_numeric = False
    
    padding = 6 if is_numeric else 4
    minimum = 14 if is_numeric else 15
    
    return max(max_len + padding, minimum)

Row Height

Must set manually—openpyxl does not auto-adjust.

Row TypeHeight
Document title35
Section header25
Table header30
Standard data18
Wrapped textlines × 15 + 10
ws.row_dimensions[2].height = 35   # Title
ws.row_dimensions[5].height = 25   # Section header
ws.row_dimensions[7].height = 30   # Table header
ws.row_dimensions[8].height = 18   # Data row

Merge Cells

ElementMerge?Span
Document/Sheet titleYesWidth of content below
Section headerYesWidth of related table
Multi-level header (parent)YesSpan child columns
Long text rowYesWidth of content area

When to merge: Merge when text would otherwise be clipped at the column boundary. If text fits within a single column, merging is optional.

Common cases requiring merge:

  • Titles and subtitles (usually span full content width)
  • Section headers (span width of related table)
  • KEY INSIGHTS bullet points (long sentences)
  • Notes and disclaimers (multi-sentence text)

Section header with background — merge width must match table width:

# Section header spans same width as table below
last_col = 8  # Must match table's last column
ws.merge_cells(f'B6:{get_column_letter(last_col)}6')
ws['B6'] = "KEY METRICS"
ws['B6'].font = Font(name=SERIF_FONT, size=14, bold=True, color=THEME['primary'])
ws['B6'].fill = PatternFill(start_color=THEME['light'], end_color=THEME['light'], fill_type='solid')
ws['B6'].alignment = Alignment(horizontal='left', vertical='center')

Data Visualization

Data Bars:

from openpyxl.formatting.rule import DataBarRule

rule = DataBarRule(start_type='min', end_type='max', color=THEME['primary'])
ws.conditional_formatting.add('C5:C50', rule)

Color Scale:

from openpyxl.formatting.rule import ColorScaleRule

rule = ColorScaleRule(
    start_type='min', start_color='FFFFFF',
    end_type='max', end_color=THEME['primary']
)
ws.conditional_formatting.add('D5:D50', rule)

Charts:

from openpyxl.chart import BarChart, Reference

chart = BarChart()
chart.title = "Revenue by Region"
data = Reference(ws, min_col=3, min_row=4, max_row=10)
cats = Reference(ws, min_col=2, min_row=5, max_row=10)
chart.add_data(data, titles_from_data=True)
chart.set_categories(cats)

# Apply theme colors to chart series
for i, series in enumerate(chart.series):
    series.graphicalProperties.solidFill = THEME['chart_colors'][i % len(THEME['chart_colors'])]

ws.add_chart(chart, "F5")

Layer 4: Interaction (How They Interact)

Goal: Usable, flexible, user can explore and work with the data.

Freeze Panes

For tables with >10 rows:

ws.freeze_panes = 'B5'  # Freeze below header row

Filters

For tables with >20 rows:

ws.auto_filter.ref = f"B4:{get_column_letter(last_col)}{last_row}"

Hyperlinks

# Internal link
cell.hyperlink = "#'Data'!A1"
cell.font = Font(color=THEME['accent'], underline='single')

# External link
cell.hyperlink = "https://example.com"
cell.font = Font(color=THEME['accent'], underline='single')

Sorting

Pre-sort by most meaningful dimension:

  • Rankings → by value descending
  • Time series → by date ascending
  • Alphabetical → when no clear priority
df = df.sort_values('revenue', ascending=False)

Editability

  • Use formulas when users may update inputs
  • Use hardcoded values when data is final
  • Keep formulas simple; document complex ones

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Research

statute-analysis-rafal-fryc

No summary provided by upstream source.

Repository SourceNeeds Review
Research

mediation-dispute-analysis

No summary provided by upstream source.

Repository SourceNeeds Review
Research

nil-contract-analysis-samir-patel

No summary provided by upstream source.

Repository SourceNeeds Review
General

contract-review-anthropic

No summary provided by upstream source.

Repository SourceNeeds Review
xlsx-processing-manus | V50.AI