{"id":49960312,"url":"https://github.com/omarirfa/jetxl","last_synced_at":"2026-05-18T02:13:24.681Z","repository":{"id":332014474,"uuid":"1071865948","full_name":"omarirfa/Jetxl","owner":"omarirfa","description":"Blazing fast xlsx generator 🚀","archived":false,"fork":false,"pushed_at":"2026-01-12T02:02:03.000Z","size":277,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-01-12T06:07:02.541Z","etag":null,"topics":["arrow","excel","excel-writer","pandas","polars","pyarrow","python","rust","xlsx"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/omarirfa.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-07T23:31:25.000Z","updated_at":"2026-01-12T02:02:03.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/omarirfa/Jetxl","commit_stats":null,"previous_names":["omarirfa/jetxl"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/omarirfa/Jetxl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/omarirfa%2FJetxl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/omarirfa%2FJetxl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/omarirfa%2FJetxl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/omarirfa%2FJetxl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/omarirfa","download_url":"https://codeload.github.com/omarirfa/Jetxl/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/omarirfa%2FJetxl/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33162449,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-17T22:39:12.733Z","status":"online","status_checked_at":"2026-05-18T02:00:06.436Z","response_time":71,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arrow","excel","excel-writer","pandas","polars","pyarrow","python","rust","xlsx"],"created_at":"2026-05-18T02:13:23.362Z","updated_at":"2026-05-18T02:13:24.667Z","avatar_url":"https://github.com/omarirfa.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Jetxl ✈️\n**Blazingly fast Excel (XLSX) writer for Python, powered by Rust**\n\nJetxl is a high-performance library for creating Excel files from Python with native support for Arrow, Polars, and Pandas DataFrames. Built from the ground up in Rust for maximum speed and efficiency.\n\n## ✨ Features\n\n- 🚀 **Ultra-fast**: 5-40x faster than other Python Excel libraries\n- 🔄 **Zero-copy Arrow integration**: Direct DataFrame → Excel with no intermediate conversions\n- 🎨 **Rich formatting**: Fonts, colors, borders, alignment, number formats\n- 📊 **Advanced features**: Conditional formatting, data validation, formulas, hyperlinks, Excel tables, charts, images\n- 🧵 **Multi-threaded**: Parallel sheet generation for multi-sheet workbooks\n- 💾 **Memory efficient**: Streaming XML generation with minimal memory overhead\n- 🐻‍❄️🐼 **Framework agnostic**: Works seamlessly with Polars, Pandas, PyArrow, and native Python dicts\n\n\n\n## ⚡ Performance Comparison\n\n*Benchmark environment: Python 3.13, AMD Ryzen 9 7900x, 64 GB RAM*\n\nAt the time of the test, the following library versions were used:\n- Jetxl: 0.2.0\n- Polars: 1.40.1\n- Pandas: 3.0.3\n- Pyexcelerate: 0.13.0\n- Rustpy-xlsxwriter: 0.4.4\n- Openpyxl: 3.1.5\n- Xlsxwriter: 3.2.9\n\n\n### Library comparison summary\n| Library | 1M Rows | Speedup | Throughput | Memory |\n|---------|---------|---------|------------|--------|\n| **jetxl (arrow)** | **2.06s** | **1.0x** | **526K rows/s** | **~0 MB** |\n| jetxl (dict) | 3.57s | 1.7x slower | 286K rows/s | ~0 MB |\n| xlsxwriter | 10.05s | 4.9x slower | 96K rows/s | 0.4 MB |\n| rustpy_xlsxwriter | 11.27s | 5.5x slower | 89K rows/s | - |\n| pyexcelerate | 35.55s | 17x slower | 28K rows/s | - |\n| polars.write_excel | 40.85s | **20x slower** | 27K rows/s | 2.1 GB |\n| openpyxl | 56.25s | **27x slower** | 18K rows/s | 0.4 MB |\n| pandas+xlsxwriter | 56.30s | 27x slower | 18K rows/s | - |\n| pandas+openpyxl | 83.42s | **40x slower** | 12K rows/s | - |\n\n\n\nThe chart below shows the execution time comparison with popular libraries for a single sheet file against Jetxl. Performance will vary on different hardware.\n![exec_time_comparison](benchmark/execution_time.png)\n\n\n### Execution Time (seconds)\n\n| Library | 10K rows | 100K rows | 1M rows |\n|---------|----------|-----------|---------|\n| **jetxl (arrow)** | **0.022** | **0.19** | **2.06** |\n| jetxl (dict) | 0.032 | 0.31 | 3.57 |\n| rustpy_xlsxwriter | 0.107 | 1.06 | 11.27 |\n| xlsxwriter | 0.112 | 1.00 | 10.05 |\n| pyexcelerate | 0.333 | 3.86 | 35.55 |\n| polars.write_excel | 0.349 | 3.53 | 40.85 |\n| openpyxl | 0.516 | 5.10 | 56.25 |\n| pandas+xlsxwriter | 0.523 | 5.59 | 56.30 |\n| pandas+openpyxl | 0.756 | 8.33 | 83.42 |\n\n\n\n\n## 📦 Installation\n\n```bash\npip install jetxl\n\n# Install with uv (recommended)\n# uv pip install jetxl\n```\n\n## 🚀 Quick Start\n\n\n\u003e [!IMPORTANT]\n\u003e Jetxl is an **experimental xlsx writer** in its current state. There are still\n\u003e bugs and breaking changes that can happen. Existing \n\u003e functionality is subject to change.\n\n\n\n### Using Polars (Recommended)\n\n```python\nimport polars as pl\nimport jetxl as jet\n\n# Create a DataFrame\ndf = pl.DataFrame({\n    \"Name\": [\"Alice\", \"Bob\", \"Charlie\"],\n    \"Age\": [25, 30, 35],\n    \"Salary\": [50000.0, 60000.0, 75000.0]\n})\n\n# Write to Excel (requires to_arrow() conversion)\njet.write_sheet_arrow(df.to_arrow(), \"output.xlsx\")\n```\n\n### Using Pandas\n\n```python\nimport pandas as pd\nimport jetxl as jet\n\ndf = pd.DataFrame({\n    \"Name\": [\"Alice\", \"Bob\", \"Charlie\"],\n    \"Age\": [25, 30, 35],\n    \"Salary\": [50000.0, 60000.0, 75000.0]\n})\n\n# Convert to Arrow for zero-copy performance\njet.write_sheet_arrow(df.to_arrow(), \"output.xlsx\")\n```\n\n### Using PyArrow\n\n```python\nimport pyarrow as pa\nimport jetxl as jet\n\n# Create an Arrow table\ntable = pa.table({\n    \"Name\": [\"Alice\", \"Bob\", \"Charlie\"],\n    \"Age\": [25, 30, 35],\n    \"Salary\": [50000.0, 60000.0, 75000.0]\n})\n\n# Write directly from Arrow table\njet.write_sheet_arrow(table, \"output.xlsx\")\n```\n\n### Using Python Dicts (Legacy API)\n\n```python\nimport jetxl as jet\n\ndata = {\n    \"Name\": [\"Alice\", \"Bob\", \"Charlie\"],\n    \"Age\": [25, 30, 35],\n    \"Salary\": [50000.0, 60000.0, 75000.0]\n}\n\njet.write_sheet(data, \"output.xlsx\")\n```\n\n## 📚 API Reference\n\n### Arrow API (Recommended - Fastest)\n\n#### `write_sheet_arrow()`\n\nWrite a single sheet from Arrow-compatible data (Polars, PyArrow, Pandas).\n\n```python\njet.write_sheet_arrow(\n    arrow_data,                    # DataFrame or Arrow RecordBatch\n    filename,                       # Output file path\n    sheet_name=None,               # Sheet name (default: \"Sheet1\")\n    auto_filter=False,             # Enable autofilter on headers\n    freeze_rows=0,                 # Number of rows to freeze\n    freeze_cols=0,                 # Number of columns to freeze\n    auto_width=False,              # Auto-calculate column widths\n    styled_headers=False,          # Apply bold styling to headers\n    write_header_row=True,         # Write column names as first row\n    column_widths=None,            # Dict[str, float|str] - manual widths\n    column_formats=None,           # Dict[str, str] - number formats\n    merge_cells=None,              # List[(row, col, row, col)] - merge ranges\n    data_validations=None,         # List[dict] - validation rules\n    hyperlinks=None,               # List[(row, col, url, display)]\n    row_heights=None,              # Dict[int, float] - row heights\n    cell_styles=None,              # List[dict] - individual cell styles\n    formulas=None,                 # List[(row, col, formula, cached_value)]\n    conditional_formats=None,      # List[dict] - conditional formatting\n    tables=None,                   # List[dict] - Excel table definitions\n    charts=None,                   # List[dict] - Excel chart definitions\n    images=None,                   # List[dict] - Excel image definitions\n    gridlines_visible=True,        # Show worksheet gridlines\n    zoom_scale=None,               # Zoom percentage 10-400\n    tab_color=None,                # Sheet tab color (ARGB hex)\n    default_row_height=None,       # Default row height in points\n    hidden_columns=None,           # List[int] - column indices to hide\n    hidden_rows=None,              # List[int] - row indices to hide\n    right_to_left=False,           # Enable RTL layout\n    data_start_row=0,              # Skip rows for auto-width calculation\n    header_content=None            # List[(row, col, text)] - custom header rows\n)\n```\n\n#### `write_sheets_arrow()`\n\nWrite multiple sheets with parallel processing. **Full feature parity** with `write_sheet_arrow()` - each sheet supports all formatting options independently.\n```python\njet.write_sheets_arrow(\n    sheets,                         # List[dict] with data, name, and any formatting options\n    filename,                       # Output file path\n    num_threads                     # Parallel threads for XML generation\n)\n```\n\n**Each sheet dict supports all `write_sheet_arrow()` parameters:**\n```python\n{\n    \"data\": arrow_data,                         # Required: Arrow Table/RecordBatch\n    \"name\": \"Sheet1\",                           # Required: Sheet name\n    \n    # All write_sheet_arrow() options available:\n    \"auto_filter\": bool,\n    \"freeze_rows\": int,\n    \"freeze_cols\": int,\n    \"auto_width\": bool,\n    \"styled_headers\": bool,\n    \"write_header_row\": bool,\n    \"column_widths\": Dict[str, float|str],\n    \"column_formats\": Dict[str, str],\n    \"merge_cells\": List[Tuple[int, int, int, int]],\n    \"data_validations\": List[dict],\n    \"hyperlinks\": List[Tuple[int, int, str, str]],\n    \"row_heights\": Dict[int, float],\n    \"cell_styles\": List[dict],\n    \"formulas\": List[Tuple[int, int, str, str]],\n    \"conditional_formats\": List[dict],\n    \"tables\": List[dict],\n    \"charts\": List[dict],\n    \"images\": List[dict],\n    \"gridlines_visible\": bool,\n    \"zoom_scale\": int,\n    \"tab_color\": str,\n    \"default_row_height\": float,\n    \"hidden_columns\": List[int],\n    \"hidden_rows\": List[int],\n    \"right_to_left\": bool,\n    \"data_start_row\": int,\n    \"header_content\": List[Tuple[int, int, str]]\n}\n```\n\n**Example with independent sheet configurations:**\n```python\nsheets = [\n    {\n        \"data\": df_sales.to_arrow(),\n        \"name\": \"Sales\",\n        \"styled_headers\": True,\n        \"tables\": [{\"name\": \"SalesTable\", ...}],\n        \"charts\": [{\"chart_type\": \"column\", ...}],\n        \"tab_color\": \"FF00B050\"\n    },\n    {\n        \"data\": df_costs.to_arrow(),\n        \"name\": \"Costs\",\n        \"conditional_formats\": [{...}],\n        \"hidden_columns\": [2, 3],\n        \"tab_color\": \"FFFF0000\"\n    }\n]\n\njet.write_sheets_arrow(sheets, \"report.xlsx\", num_threads=4)\n```\n\n\n### In-Memory Bytes API (No File I/O)\n\n#### `write_sheet_arrow_to_bytes()`\n\nReturns Excel file as bytes instead of writing to disk. Identical parameters to `write_sheet_arrow()` except returns bytes instead of writing to a file.\n\n```python\nexcel_bytes = jet.write_sheet_arrow_to_bytes(\n    arrow_data,                    # DataFrame or Arrow RecordBatch\n    sheet_name=None,               # Sheet name (default: \"Sheet1\")\n    auto_filter=False,             # Enable autofilter on headers\n    freeze_rows=0,                 # Number of rows to freeze\n    freeze_cols=0,                 # Number of columns to freeze\n    auto_width=False,              # Auto-calculate column widths\n    styled_headers=False,          # Apply bold styling to headers\n    write_header_row=True,         # Write column names as first row\n    column_widths=None,            # Dict[str, float|str] - manual widths\n    column_formats=None,           # Dict[str, str] - number formats\n    merge_cells=None,              # List[(row, col, row, col)] - merge ranges\n    data_validations=None,         # List[dict] - validation rules\n    hyperlinks=None,               # List[(row, col, url, display)]\n    row_heights=None,              # Dict[int, float] - row heights\n    cell_styles=None,              # List[dict] - individual cell styles\n    formulas=None,                 # List[(row, col, formula, cached_value)]\n    conditional_formats=None,      # List[dict] - conditional formatting\n    tables=None,                   # List[dict] - Excel table definitions\n    charts=None,                   # List[dict] - Excel chart definitions\n    images=None,                   # List[dict] - Excel image definitions\n    gridlines_visible=True,        # Show worksheet gridlines\n    zoom_scale=None,               # Zoom percentage 10-400\n    tab_color=None,                # Sheet tab color (ARGB hex)\n    default_row_height=None,       # Default row height in points\n    hidden_columns=None,           # List[int] - column indices to hide\n    hidden_rows=None,              # List[int] - row indices to hide\n    right_to_left=False,           # Enable RTL layout\n    data_start_row=0,              # Skip rows for auto-width calculation\n    header_content=None            # List[(row, col, text)] - custom header rows\n)\n```\n\n**Use Cases:**\n- Web APIs and HTTP responses\n- Cloud functions (AWS Lambda, Google Cloud Functions)\n- Streaming scenarios\n- In-memory processing\n- Base64 encoding for JSON APIs\n\n**Examples:**\n\n```python\nimport polars as pl\nimport jetxl as jet\n\ndf = pl.DataFrame({\n    \"Name\": [\"Alice\", \"Bob\"],\n    \"Age\": [25, 30],\n    \"Salary\": [50000, 60000]\n})\n\n# Generate Excel in memory\nexcel_bytes = jet.write_sheet_arrow_to_bytes(\n    df.to_arrow(),\n    sheet_name=\"Employees\",\n    styled_headers=True,\n    auto_width=True\n)\n\n# Save to file\nwith open(\"output.xlsx\", \"wb\") as f:\n    f.write(excel_bytes)\n\n# Or use in web framework (Flask)\nfrom flask import Response\n\n@app.route('/download')\ndef download():\n    excel_bytes = jet.write_sheet_arrow_to_bytes(df.to_arrow())\n    return Response(\n        excel_bytes,\n        mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n        headers={'Content-Disposition': 'attachment;filename=data.xlsx'}\n    )\n\n# Or base64 encode for API\nimport base64\nencoded = base64.b64encode(excel_bytes).decode('utf-8')\n\n# Or return from Lambda\ndef lambda_handler(event, context):\n    excel_bytes = jet.write_sheet_arrow_to_bytes(df.to_arrow())\n    return {\n        'statusCode': 200,\n        'body': base64.b64encode(excel_bytes).decode('utf-8'),\n        'isBase64Encoded': True,\n        'headers': {\n            'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'\n        }\n    }\n```\n\n#### `write_sheets_arrow_to_bytes()`\n\nWrite multiple sheets to bytes. Identical to `write_sheets_arrow()` but returns bytes.\n\n```python\nexcel_bytes = jet.write_sheets_arrow_to_bytes(\n    sheets,        # List[dict] with data, name, and any formatting options\n    num_threads=1  # Parallel threads for XML generation\n)\n```\n\n**Example:**\n\n```python\nsheets = [\n    {\n        \"data\": df1.to_arrow(),\n        \"name\": \"Sales\",\n        \"styled_headers\": True,\n        \"freeze_rows\": 1\n    },\n    {\n        \"data\": df2.to_arrow(),\n        \"name\": \"Costs\",\n        \"auto_width\": True\n    }\n]\n\n# Generate multi-sheet Excel in memory\nexcel_bytes = jet.write_sheets_arrow_to_bytes(sheets, num_threads=2)\n\n# FastAPI example\nfrom fastapi.responses import Response\n\n@app.get(\"/report\")\nasync def generate_report():\n    excel_bytes = jet.write_sheets_arrow_to_bytes(sheets, num_threads=2)\n    return Response(\n        content=excel_bytes,\n        media_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n        headers={'Content-Disposition': 'attachment; filename=report.xlsx'}\n    )\n\n# S3 upload without local file\nimport boto3\ns3 = boto3.client('s3')\ns3.put_object(\n    Bucket='my-bucket',\n    Key='reports/monthly.xlsx',\n    Body=excel_bytes,\n    ContentType='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'\n)\n```\n\n### Dict API (Legacy - Backward Compatible)\n\n#### `write_sheet()`\n\n```python\njet.write_sheet(\n    columns,       # Dict[str, List] - column name to values\n    filename,      # Output file path\n    sheet_name=None,  # Sheet name\n    charts=None    # List[dict] - Excel chart definitions\n)\n```\n\n#### `write_sheets()`\n\n```python\nsheets = [\n    {\"name\": \"Sales\", \"columns\": sales_data},\n    {\"name\": \"Expenses\", \"columns\": expenses_data}\n]\njet.write_sheets(sheets, \"output.xlsx\", num_threads=4)\n```\n\n## 🎨 Formatting \u0026 Styling\n\n### Basic Formatting\n\n```python\nimport polars as pl\nimport jetxl as jet\n\ndf = pl.DataFrame({\n    \"Product\": [\"Apple\", \"Banana\", \"Cherry\"],\n    \"Price\": [1.50, 0.75, 2.25],\n    \"Quantity\": [100, 150, 80]\n})\n\njet.write_sheet_arrow(\n    df.to_arrow(),\n    \"formatted.xlsx\",\n    auto_filter=True,           # Add filter dropdowns\n    freeze_rows=1,              # Freeze header row\n    styled_headers=True,        # Bold headers\n    auto_width=True             # Auto-size columns\n)\n\n# Without headers (data only)\njet.write_sheet_arrow(\n    df.to_arrow(),\n    \"no_headers.xlsx\",\n    write_header_row=False  # Skip writing column names\n)\n\n```\n\n### Column Formats\n\nJetxl supports both built-in format shortcuts and custom Excel format codes for complete control over number display.\n\n#### Built-in Format Shortcuts\n\n```python\njet.write_sheet_arrow(\n    df.to_arrow(),\n    \"formatted.xlsx\",\n    column_formats={\n        \"Price\": \"currency\",           # $#,##0.00\n        \"Quantity\": \"integer\",         # 0\n        \"Growth\": \"percentage\",        # 0%\n        \"Timestamp\": \"datetime\",       # yyyy-mm-dd hh:mm:ss\n        \"Score\": \"decimal2\",           # 0.00\n        \"Rate\": \"scientific\",          # 0.00E+00\n        \"Measurement\": \"fraction\"      # # ?/?\n    }\n)\n```\n\n**Available built-in formats:**\n- `general` - Default formatting\n- `integer` - Whole numbers (0)\n- `decimal2` - Two decimal places (0.00)\n- `decimal4` - Four decimal places (0.0000)\n- `percentage` - Percentage (0%)\n- `percentage_decimal` - Percentage with decimal (0.00%)\n- `percentage_integer` - Percentage as integer (0%)\n- `currency` - Currency ($#,##0.00)\n- `currency_rounded` - Rounded currency ($#,##0)\n- `date` - Date (yyyy-mm-dd)\n- `datetime` - Date and time (yyyy-mm-dd hh:mm:ss)\n- `time` - Time (hh:mm:ss)\n- `scientific` - Scientific notation (0.00E+00)\n- `fraction` - Fraction (# ?/?)\n- `fraction_two_digits` - Fraction with 2 digits (# ??/??)\n- `thousands` - Thousands separator (#,##0)\n\n#### Custom Format Codes\n\nAny string not matching a built-in format becomes a custom Excel format code, giving you full control:\n\n```python\ncolumn_formats = {\n    # Accounting format with negative in parentheses\n    \"Amount\": \"$#,##0.00_);[Red]($#,##0.00)\",\n    \n    # Thousands with 'K' suffix\n    \"Visitors\": \"#,##0,\\\"K\\\"\",\n    \n    # Millions with 'M' suffix  \n    \"Revenue\": \"$#,##0.0,,\\\"M\\\"\",\n    \n    # Custom date format\n    \"Date\": \"dddd, mmmm dd, yyyy\",\n    \n    # Conditional coloring\n    \"Change\": \"[Green]#,##0;[Red]-#,##0;[Blue]0\",\n    \n    # Fractions in sixteenths\n    \"Measurement\": \"# ?/16\",\n    \n    # Phone numbers\n    \"Phone\": \"(###) ###-####\",\n    \n    # Zero-padded IDs\n    \"ID\": \"00000\",\n    \n    # Hide zeros\n    \"Optional\": \"#,##0;-#,##0;\\\"\\\"\"\n}\n```\n\n#### Custom Format Syntax\n\nExcel format codes use this structure:\n```\n[Positive];[Negative];[Zero];[Text]\n```\n\n**Format symbols:**\n- `0` - Digit placeholder (shows 0 if no digit)\n- `#` - Digit placeholder (shows nothing if no digit)  \n- `?` - Digit placeholder (adds space for alignment)\n- `.` - Decimal point\n- `,` - Thousands separator (or divider in millions/thousands)\n- `%` - Multiply by 100 and show percent sign\n- `E+` `E-` - Scientific notation\n- `\"text\"` - Literal text in quotes\n- `@` - Text placeholder\n- `[Color]` - Color code (Red, Blue, Green, etc.)\n- `[\u003e=100]` - Conditional formatting\n\n**Scaling numbers:**\n- One comma `,` after number divides by 1,000\n- Two commas `,,` divide by 1,000,000\n- Example: `#,##0,` shows 1500 as \"2\" (rounded thousands)\n- Example: `#,##0.0,,` shows 5000000 as \"5.0\" (millions)\n\n#### Complete Custom Format Examples\n\n```python\nimport polars as pl\nimport jetxl as jet\n\ndf = pl.DataFrame({\n    \"Revenue\": [1500000, 500000, 75000],\n    \"Change\": [150, -75, 0],\n    \"Ratio\": [0.333, 0.125, 0.875],\n    \"Code\": [1, 42, 999],\n    \"Date\": [\"2024-01-15\", \"2024-02-20\", \"2024-03-25\"]\n})\n\njet.write_sheet_arrow(\n    df.to_arrow(),\n    \"custom_formats.xlsx\",\n    column_formats={\n        # Show millions with conditional formatting\n        \"Revenue\": \"[\u003e=1000000]$#,##0.0,,\\\"M\\\";[\u003e=1000]$#,##0,\\\"K\\\";$#,##0\",\n        \n        # Color-coded changes with +/- indicators\n        \"Change\": \"[Green]+#,##0;[Red]-#,##0;[Blue]0\",\n        \n        # Fractions with fallback\n        \"Ratio\": \"# ?/?;-# ?/?;\\\"N/A\\\"\",\n        \n        # Zero-padded codes\n        \"Code\": \"000000\",\n        \n        # Custom date format\n        \"Date\": \"dddd, mmmm dd, yyyy\"\n    }\n)\n```\n\n#### Testing Custom Formats\n\nThe easiest way to create custom formats:\n\n1. Open Excel and format a cell manually\n2. Right-click → Format Cells → Custom\n3. Copy the format code from the \"Type:\" field\n4. Use that exact string in Jetxl\n\n#### Limitations\n\n- **No validation**: Custom format codes aren't validated client-side. Invalid codes may cause Excel errors when opening the file.\n- **XML escaping**: Special characters (`\u003c`, `\u003e`, `\u0026`, `\"`, `'`) are automatically escaped - you don't need to worry about them.\n- **Length limit**: Format codes are limited to ~255 characters (Excel limitation).\n- **Compatibility**: Some advanced features (locale codes, DBNum) may not work in all Excel versions.\n- **Color names**: Limited to Excel's built-in set: `[Red]`, `[Blue]`, `[Green]`, `[Yellow]`, `[Cyan]`, `[Magenta]`, `[White]`, `[Black]`, `[Color1]`-`[Color56]`.\n\n**Reference**: [Excel Number Format Codes - Microsoft](https://support.microsoft.com/en-us/office/number-format-codes-5026bbd6-04bc-48cd-bf33-80f18b4eae68)\n\n### Advanced Number Format Examples\n\n#### Dynamic Scaling\n\nAutomatically scale numbers based on magnitude:\n\n```python\n# Show millions, thousands, or regular numbers\ncolumn_formats = {\n    \"Value\": \"[\u003e=1000000]#,##0.0,,\\\"M\\\";[\u003e=1000]#,##0.0,\\\"K\\\";#,##0\"\n}\n# 5000000 → \"5.0M\"\n# 15000 → \"15.0K\"  \n# 500 → \"500\"\n```\n\n#### Conditional Text\n\nDisplay custom text based on values:\n\n```python\ncolumn_formats = {\n    \"Status\": \"[=1]\\\"✓ Complete\\\";[=0]\\\"✗ Pending\\\";\\\"Unknown\\\"\",\n    \"Grade\": \"[\u003e=90]\\\"A\\\";[\u003e=80]\\\"B\\\";[\u003e=70]\\\"C\\\";\\\"F\\\"\"\n}\n```\n\n#### Accounting Formats\n\nProfessional financial formatting:\n\n```python\ncolumn_formats = {\n    # Negative in parentheses, aligned decimals\n    \"P\u0026L\": \"_($* #,##0.00_);_($* (#,##0.00);_($* \\\"-\\\"??_);_(@_)\",\n    \n    # Simple accounting with red negatives\n    \"Balance\": \"$#,##0.00_);[Red]($#,##0.00)\"\n}\n```\n\n#### Custom Date/Time Formats\n\n```python\ncolumn_formats = {\n    \"FullDate\": \"dddd, mmmm dd, yyyy\",        # Monday, January 15, 2024\n    \"ShortDate\": \"mm/dd/yy\",                  # 01/15/24\n    \"MonthYear\": \"mmmm yyyy\",                 # January 2024\n    \"Quarter\": \"\\\"Q\\\"Q yyyy\",                 # Q1 2024\n    \"TimeOnly\": \"h:mm AM/PM\",                 # 3:45 PM\n    \"Timestamp\": \"yyyy-mm-dd hh:mm:ss\"       # 2024-01-15 15:45:30\n}\n```\n\n#### Fractions and Measurements\n\n```python\ncolumn_formats = {\n    \"Inches\": \"# ?/16\\\"\",           # Fractions in sixteenths with inch mark\n    \"Simple\": \"# ?/?\",              # Simplest fraction\n    \"Eighths\": \"# ?/8\",             # Fractions in eighths\n    \"Mixed\": \"# ??/??\",             # Up to two-digit fractions\n    \"Feet\": \"#' ?/16\\\"\",            # 5' 3/16\"\n}\n```\n\n#### Percentage Variations\n\n```python\ncolumn_formats = {\n    \"Basic\": \"0%\",                  # 15%\n    \"OneDecimal\": \"0.0%\",           # 15.7%\n    \"TwoDecimal\": \"0.00%\",          # 15.73%\n    \"WithSign\": \"+0.0%;-0.0%;0%\",   # +15.7%, -3.2%, 0%\n}\n```\n\n### Column Widths \u0026 Row Heights\n```python\n# Manual column widths\njet.write_sheet_arrow(\n    df.to_arrow(),\n    \"sized.xlsx\",\n    column_widths={\n        \"Product\": 20.0,      # 20 character units\n        \"Description\": 50.0,\n        \"Price\": 12.0\n    },\n    row_heights={\n        1: 25.0,    # Header row height\n        2: 18.0,    # First data row\n        5: 30.0     # Fifth row\n    }\n)\n\n# Column widths in pixels (converted automatically)\njet.write_sheet_arrow(\n    df.to_arrow(),\n    \"pixel_widths.xlsx\",\n    column_widths={\n        \"Name\": \"150px\",      # 150 pixels\n        \"Email\": \"200px\",\n        \"Status\": \"80px\"\n    }\n)\n\n# Mix of manual and auto\njet.write_sheet_arrow(\n    df.to_arrow(),\n    \"mixed_widths.xlsx\",\n    auto_width=True,          # Auto-calculate most columns\n    column_widths={\n        \"ID\": 8.0,            # Override: fixed width for ID\n        \"Notes\": 60.0         # Override: extra wide for notes\n    }\n)\n```\n\n**Column Width Units:**\n- Float (e.g., `20.0`) - Excel character units (width of '0' in standard font)\n- String with \"px\" (e.g., `\"150px\"`) - Pixels (converted to character units)\n- `\"auto\"` - Calculate from content (same as `auto_width=True`)\n\n### Cell Styles\n\n```python\ncell_styles = [\n    {\n        \"row\": 2,\n        \"col\": 1,\n        \"font\": {\n            \"bold\": True,\n            \"italic\": False,\n            \"size\": 14.0,\n            \"color\": \"FFFF0000\",  # Red (ARGB format: AA=alpha, RR=red, GG=green, BB=blue)\n            \"name\": \"Arial\"\n        },\n        \"fill\": {\n            \"pattern\": \"solid\",  # Options: \"solid\", \"gray125\", \"none\"\n            \"fg_color\": \"FFFFFF00\",  # Yellow\n            \"bg_color\": None\n        },\n        \"border\": {\n            \"left\": {\"style\": \"thin\", \"color\": \"FF000000\"},\n            \"right\": {\"style\": \"thick\", \"color\": \"FF000000\"},\n            \"top\": {\"style\": \"medium\", \"color\": \"FF000000\"},\n            \"bottom\": {\"style\": \"double\", \"color\": \"FF000000\"}\n        },\n        \"alignment\": {\n            \"horizontal\": \"center\",  # left, center, right, justify\n            \"vertical\": \"center\",    # top, center, bottom\n            \"wrap_text\": True,\n            \"text_rotation\": 45      # 0-180 degrees, 255 for vertical\n        },\n        \"number_format\": \"currency\"\n    }\n]\n\njet.write_sheet_arrow(df.to_arrow(), \"styled.xlsx\", cell_styles=cell_styles)\n```\n\n### Text Rotation\n\nRotate text in cells for compact headers or labels:\n```python\ncell_styles = [{\n    \"row\": 1,\n    \"col\": 0,\n    \"alignment\": {\n        \"horizontal\": \"center\",\n        \"vertical\": \"center\",\n        \"text_rotation\": 45  # 0-180 degrees, or 255 for vertical text\n    }\n}]\n\njet.write_sheet_arrow(df.to_arrow(), \"rotated.xlsx\", cell_styles=cell_styles)\n```\n\n**Rotation values:**\n- `0` - No rotation (default)\n- `1-90` - Counterclockwise rotation\n- `91-180` - Clockwise rotation (91 = -89°)\n- `255` - Vertical text (top to bottom)\n\n### Fill Patterns\n\nExcel supports different fill patterns:\n```python\n# Solid fill (most common)\ncell_styles = [{\n    \"row\": 2,\n    \"col\": 0,\n    \"fill\": {\n        \"pattern\": \"solid\",\n        \"fg_color\": \"FFFFFF00\"  # Yellow\n    }\n}]\n\n# Gray pattern (subtle shading)\ncell_styles = [{\n    \"row\": 2,\n    \"col\": 0,\n    \"fill\": {\n        \"pattern\": \"gray125\",\n        \"fg_color\": \"FFD9D9D9\"  # Light gray\n    }\n}]\n\n# No fill (transparent)\ncell_styles = [{\n    \"row\": 2,\n    \"col\": 0,\n    \"fill\": {\n        \"pattern\": \"none\"\n    }\n}]\n```\n\n### Complete Border Example\n\nApply different border styles to all four sides:\n```python\ncell_styles = [{\n    \"row\": 2,\n    \"col\": 0,\n    \"border\": {\n        \"left\": {\"style\": \"thin\", \"color\": \"FF000000\"},\n        \"right\": {\"style\": \"medium\", \"color\": \"FF000000\"},\n        \"top\": {\"style\": \"thick\", \"color\": \"FF0070C0\"},\n        \"bottom\": {\"style\": \"double\", \"color\": \"FF000000\"}\n    }\n}]\n\njet.write_sheet_arrow(df.to_arrow(), \"borders.xlsx\", cell_styles=cell_styles)\n```\n\n**Available border styles:**\n- `\"thin\"` - Standard thin line\n- `\"medium\"` - Medium weight line\n- `\"thick\"` - Thick line\n- `\"double\"` - Double line\n- `\"dotted\"` - Dotted line\n- `\"dashed\"` - Dashed line\n\n**Color Format Guide:**\n- Colors use ARGB hexadecimal format: `AARRGGBB`\n- `AA` = Alpha (transparency): `FF` = fully opaque, `00` = fully transparent\n- `RR` = Red component: `00` = no red, `FF` = maximum red\n- `GG` = Green component: `00` = no green, `FF` = maximum green\n- `BB` = Blue component: `00` = no blue, `FF` = maximum blue\n\nCommon colors: `FFFF0000` (red), `FF00FF00` (green), `FF0000FF` (blue), `FFFFFF00` (yellow), `FF000000` (black), `FFFFFFFF` (white)\n\nFor more colors and an interactive picker, see the [External Resources](#-external-resources--references) section below.\n\n### Excel Tables\n\nCreate formatted Excel tables with built-in styles, sorting, and filtering capabilities.\n\n### Basic Table\n```python\ntables = [{\n    \"name\": \"ProductTable\",\n    \"display_name\": \"Product Data\",\n    \"start_row\": 1,\n    \"start_col\": 0,\n    \"end_row\": 0,      # NEW: 0 means auto-calculate from data\n    \"end_col\": 0,      # NEW: 0 means auto-calculate from data\n    \"style\": \"TableStyleMedium2\"\n}]\n\njet.write_sheet_arrow(df.to_arrow(), \"table.xlsx\", tables=tables)\n```\n\n### Auto-Sizing Tables\n\nLet Jetxl automatically calculate table dimensions based on your DataFrame:\n```python\nimport polars as pl\nimport jetxl as jet\n\ndf = pl.DataFrame({\n    \"Product\": [\"A\", \"B\", \"C\", \"D\", \"E\"],  # 5 rows\n    \"Price\": [10, 20, 30, 40, 50],\n    \"Qty\": [100, 200, 150, 300, 250]       # 3 columns\n})\n\ntables = [{\n    \"name\": \"AutoTable\",\n    \"start_row\": 1,    # Table starts at row 1 (header)\n    \"start_col\": 0,    # Column A\n    \"end_row\": 0,      # Auto: becomes 6 (1 header + 5 data rows)\n    \"end_col\": 0,      # Auto: becomes 2 (columns A, B, C = indices 0, 1, 2)\n    \"style\": \"TableStyleMedium2\"\n}]\n\njet.write_sheet_arrow(df.to_arrow(), \"auto_table.xlsx\", tables=tables)\n```\n\n**Manual vs Auto-Sizing:**\n```python\n# Manual (explicit range)\ntable = {\n    \"name\": \"ManualTable\",\n    \"start_row\": 1,\n    \"start_col\": 0,\n    \"end_row\": 100,    # Exactly 100 rows\n    \"end_col\": 5       # Columns A-F\n}\n\n# Auto (adapts to DataFrame)\ntable = {\n    \"name\": \"AutoTable\", \n    \"start_row\": 1,\n    \"start_col\": 0,\n    \"end_row\": 0,      # Uses all DataFrame rows\n    \"end_col\": 0       # Uses all DataFrame columns\n}\n\n# Mixed (partial auto)\ntable = {\n    \"name\": \"MixedTable\",\n    \"start_row\": 1,\n    \"start_col\": 0,\n    \"end_row\": 50,     # Fixed 50 rows\n    \"end_col\": 0       # Auto-calculate columns\n}\n```\n\n**Auto-calculation rules:**\n- `end_row = 0` → calculated as `start_row + num_data_rows`\n- `end_col = 0` → calculated as `start_col + num_columns - 1`\n- If table starts after row 1, a header row is automatically inserted\n- Manual values (non-zero) are used as-is\n\n### Available Table Styles\n\nExcel provides many built-in table styles that you can use with Jetxl. The styles are organized into three categories:\n\n**Light Table Styles** (Minimal emphasis, subtle colors)\n- `TableStyleLight1` through `TableStyleLight21`\n- Best for: Professional reports, financial statements, clean presentations\n\n**Medium Table Styles** (Moderate emphasis, balanced design)\n- `TableStyleMedium1` through `TableStyleMedium28`\n- Best for: Data analysis, dashboards, general-purpose tables\n\n**Dark Table Styles** (Strong emphasis, high contrast)\n- `TableStyleDark1` through `TableStyleDark11`\n- Best for: Executive summaries, presentations, highlighting key data\n\n**Visual Reference**: To see examples of all table styles, visit [Microsoft's Format an Excel Table guide](https://support.microsoft.com/en-us/office/format-an-excel-table-6789619f-c889-495c-99c2-2f971c0e2370) which includes screenshots of each style.\n\n**Additional Resources**:\n- [Create and format Excel tables](https://support.microsoft.com/en-us/office/create-and-format-tables-e81aa349-b006-4f8a-9806-5af9df0ac664) - Official Microsoft documentation\n- [Excel table overview](https://support.microsoft.com/en-us/office/overview-of-excel-tables-7ab0bb7d-3a9e-4b56-a3c9-6c94334e492c) - Complete guide to table features\n\n### Multiple Tables in One Sheet\n\n```python\n# Create two separate tables in the same sheet\ntables = [\n    {\n        \"name\": \"SalesTable\",\n        \"start_row\": 1,\n        \"start_col\": 0,\n        \"end_row\": 10,\n        \"end_col\": 3,\n        \"style\": \"TableStyleMedium9\"\n    },\n    {\n        \"name\": \"SummaryTable\",\n        \"start_row\": 12,\n        \"start_col\": 0,\n        \"end_row\": 15,\n        \"end_col\": 2,\n        \"style\": \"TableStyleLight16\"\n    }\n]\n\njet.write_sheet_arrow(df.to_arrow(), \"multi_tables.xlsx\", tables=tables)\n```\n\n### Table Configuration Options\n\n```python\ntable = {\n    \"name\": \"MyTable\",                # Required: Unique table identifier\n    \"display_name\": \"My Data\",        # Optional: User-friendly name\n    \"start_row\": 1,                   # Required: First row (1-indexed)\n    \"start_col\": 0,                   # Required: First column (0-indexed)\n    \"end_row\": 100,                   # Required: Last row\n    \"end_col\": 5,                     # Required: Last column\n    \"style\": \"TableStyleMedium2\",     # Optional: Table style name\n    \"show_first_column\": False,       # Optional: Bold first column (default: False)\n    \"show_last_column\": False,        # Optional: Bold last column (default: False)\n    \"show_row_stripes\": True,         # Optional: Alternating rows (default: True)\n    \"show_column_stripes\": False      # Optional: Alternating columns (default: False)\n}\n```\n\n**Note:** Excel tables automatically include:\n- Header row with filter dropdowns\n- Structured references for formulas\n- Automatic formatting and styling\n- Sort and filter capabilities\n\n## 📊 Excel Charts\n\nCreate professional charts and visualizations directly in your Excel files. Jetxl supports six chart types with extensive customization options including stacked charts, data labels, styling, and advanced formatting.\n\n### Chart Types\n\nJetxl supports the following chart types:\n- **Column Chart** - Vertical bars, ideal for comparing values across categories\n- **Bar Chart** - Horizontal bars, good for comparing items\n- **Line Chart** - Shows trends over time or continuous data\n- **Pie Chart** - Displays proportions of a whole\n- **Scatter Chart** - Shows relationships between two numerical variables\n- **Area Chart** - Similar to line chart but with filled areas\n\n### Basic Column Chart\n\n```python\nimport polars as pl\nimport jetxl as jet\n\n# Create sample data\ndf = pl.DataFrame({\n    \"Month\": [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\"],\n    \"Sales\": [1000, 1500, 1200, 1800, 2000],\n    \"Costs\": [800, 900, 850, 1000, 1100]\n})\n\n# Define a column chart\ncharts = [{\n    \"chart_type\": \"column\",\n    \"start_row\": 1,           # Data starts at row 1 (header)\n    \"start_col\": 0,           # First column (Month)\n    \"end_row\": 5,             # Last data row\n    \"end_col\": 2,             # Last column (Costs)\n    \"from_col\": 4,            # Chart position: start column\n    \"from_row\": 1,            # Chart position: start row\n    \"to_col\": 12,             # Chart position: end column\n    \"to_row\": 15,             # Chart position: end row\n    \"title\": \"Monthly Sales and Costs\",\n    \"category_col\": 0,        # Use first column (Month) for X-axis\n    \"show_legend\": True,\n    \"x_axis_title\": \"Month\",\n    \"y_axis_title\": \"Amount ($)\"\n}]\n\njet.write_sheet_arrow(\n    df.to_arrow(),\n    \"chart_example.xlsx\",\n    charts=charts\n)\n```\n\n### Chart Configuration\n\nEvery chart requires these basic parameters:\n\n```python\nchart = {\n    # Required: Chart type\n    \"chart_type\": \"column\",  # column, bar, line, pie, scatter, area\n    \n    # Required: Data range (1-indexed for rows, 0-indexed for columns)\n    # Option 1: Individual parameters\n    \"start_row\": 1,          # First data row (including header)\n    \"start_col\": 0,          # First data column\n    \"end_row\": 10,           # Last data row\n    \"end_col\": 3,            # Last data column\n    \n    # Option 2: Tuple format (alternative to above)\n    \"data_range\": (0, 0, 9, 3),  # (start_row, start_col, end_row, end_col)\n    \n    # Required: Chart position on worksheet\n    \"from_col\": 5,           # Starting column for chart\n    \"from_row\": 1,           # Starting row for chart\n    \"to_col\": 15,            # Ending column for chart\n    \"to_row\": 20,            # Ending row for chart\n    \n    # Optional: Chart customization\n    \"title\": \"My Chart\",                # Chart title\n    \"category_col\": 0,                  # Column to use for category axis (X-axis)\n    \"series_names\": [\"Series 1\", \"Series 2\"],  # Custom series names\n    \"show_legend\": True,                # Show/hide legend\n    \"legend_position\": \"right\",         # Legend position: \"right\", \"left\", \"top\", \"bottom\", \"none\"\n    \"x_axis_title\": \"Categories\",       # X-axis label\n    \"y_axis_title\": \"Values\",           # Y-axis label\n    \n    # Optional: Advanced styling\n    \"stacked\": True,                    # Stack series (column, bar, line, area)\n    \"percent_stacked\": True,            # Stack as 100% (column, bar, line, area)\n    \"show_data_labels\": True,           # Show data labels on chart\n    \"chart_style\": 104,                 # Excel chart style (1-48)\n    \n    # Optional: Axis scaling\n    \"axis_min\": 0.0,                    # Minimum Y-axis value\n    \"axis_max\": 100.0,                  # Maximum Y-axis value\n    \n    # Optional: Title styling\n    \"title_bold\": True,                 # Bold title text\n    \"title_font_size\": 1800,            # Title font size (hundredths of point, e.g., 1800 = 18pt)\n    \"title_color\": \"FF0000\",            # Title color (ARGB hex)\n    \n    # Optional: Axis title styling\n    \"axis_title_bold\": True,            # Bold axis title text\n    \"axis_title_font_size\": 1200,       # Axis title font size (hundredths of point)\n    \"axis_title_color\": \"00B050\",       # Axis title color (ARGB hex)\n    \n    # Optional: Legend styling\n    \"legend_bold\": True,                # Bold legend text\n    \"legend_font_size\": 1000,           # Legend font size (hundredths of point)\n}\n```\n\n### Stacked Charts\n\nCreate stacked charts to show composition or percent stacked to show proportions:\n\n```python\nimport polars as pl\nimport jetxl as jet\n\ndf = pl.DataFrame({\n    \"Quarter\": [\"Q1\", \"Q2\", \"Q3\", \"Q4\"],\n    \"Revenue\": [25000, 28000, 31000, 35000],\n    \"Profit\": [5000, 6500, 7200, 8500],\n    \"Expenses\": [20000, 21500, 23800, 26500]\n})\n\n# Regular stacked column chart\nstacked_chart = [{\n    \"chart_type\": \"column\",\n    \"data_range\": (0, 0, 3, 3),\n    \"from_col\": 5,\n    \"from_row\": 0,\n    \"to_col\": 15,\n    \"to_row\": 20,\n    \"title\": \"Stacked Revenue Components\",\n    \"category_col\": 0,\n    \"series_names\": [\"Revenue\", \"Profit\", \"Expenses\"],\n    \"stacked\": True,  # Stack the series\n    \"show_data_labels\": True,\n    \"x_axis_title\": \"Quarter\",\n    \"y_axis_title\": \"Amount ($)\"\n}]\n\n# Percent stacked column chart\npercent_chart = [{\n    \"chart_type\": \"column\",\n    \"data_range\": (0, 0, 3, 3),\n    \"from_col\": 5,\n    \"from_row\": 22,\n    \"to_col\": 15,\n    \"to_row\": 42,\n    \"title\": \"Percentage Distribution\",\n    \"category_col\": 0,\n    \"series_names\": [\"Revenue\", \"Profit\", \"Expenses\"],\n    \"percent_stacked\": True,  # Stack as 100%\n    \"show_data_labels\": True,\n    \"x_axis_title\": \"Quarter\",\n    \"y_axis_title\": \"Percentage\"\n}]\n\njet.write_sheet_arrow(\n    df.to_arrow(),\n    \"stacked_charts.xlsx\",\n    charts=[*stacked_chart, *percent_chart]\n)\n```\n\n**Note:** `stacked` and `percent_stacked` work with column, bar, line, and area charts.\n\n### Understanding Chart Styles\n\nExcel provides 48 pre-defined chart styles that apply coordinated colors, effects, and formatting. Each chart type interprets these styles differently.\n\n**Chart Style Numbers (1-48):**\n\nChart styles are organized into categories:\n- **1-10**: Colorful variations with different color schemes\n- **11-16**: Monochrome styles (black, white, gray variations)\n- **17-32**: Colorful outlined styles with borders\n- **33-40**: Soft color palettes\n- **41-48**: Modern gradient and flat design styles\n\n**Popular Styles by Use Case:**\n```python\n# Professional/Corporate\n\"chart_style\": 2    # Blue colorful\n\"chart_style\": 11   # Monochrome gray\n\"chart_style\": 26   # Dark professional\n\n# Modern/Vibrant\n\"chart_style\": 42   # Gradient modern\n\"chart_style\": 102  # Contemporary (if available)\n\"chart_style\": 104  # Bright modern\n\n# Print-Friendly\n\"chart_style\": 11   # Black and white\n\"chart_style\": 15   # High contrast\n```\n\n**How to Find Your Preferred Style:**\n\nThe best way to discover chart styles is to test them in Excel:\n1. Create a chart in Excel manually\n2. Click the chart and go to Chart Design → Chart Styles\n3. Preview different styles in the gallery\n4. Note the style you like - styles are numbered in the gallery order\n5. Use that number in Jetxl's `chart_style` parameter\n\n**Example - Testing Multiple Styles:**\n```python\n# Create the same chart with different styles to compare\nfor style_num in [2, 11, 26, 42, 104]:\n    charts = [{\n        \"chart_type\": \"column\",\n        \"data_range\": (0, 0, 3, 2),\n        \"from_col\": 5,\n        \"from_row\": 0,\n        \"to_col\": 15,\n        \"to_row\": 20,\n        \"title\": f\"Chart Style {style_num}\",\n        \"chart_style\": style_num,\n        \"category_col\": 0\n    }]\n    jet.write_sheet_arrow(df.to_arrow(), f\"style_{style_num}.xlsx\", charts=charts)\n```\n\n**Chart Style Reference:**\n- [Excel Chart Styles Gallery](https://support.microsoft.com/en-us/office/available-chart-types-in-office-a6187218-807e-4103-9e0a-27cdb19afb90) - Microsoft's official guide\n- Styles are part of the Office Open XML standard\n- Different Excel versions may render styles slightly differently\n- Not all style numbers work with all chart types\n\n### Understanding Font Sizes\n\nFont sizes in charts use Excel's internal unit system based on the Office Open XML (OOXML) standard.\n\n**Font Size Format:**\n- Values are in **hundredths of a point**\n- 1 point = 100 units\n- Standard Excel points = units ÷ 100\n\n**Common Font Size Conversions:**\n```python\n# Title Sizes\n\"title_font_size\": 800   # 8pt  - Small title\n\"title_font_size\": 1000  # 10pt - Compact title\n\"title_font_size\": 1200  # 12pt - Standard title\n\"title_font_size\": 1400  # 14pt - Medium title\n\"title_font_size\": 1600  # 16pt - Large title\n\"title_font_size\": 1800  # 18pt - Extra large title\n\"title_font_size\": 2400  # 24pt - Presentation title\n\"title_font_size\": 3200  # 32pt - Header/banner\n\n# Axis Title Sizes\n\"axis_title_font_size\": 900   # 9pt  - Small\n\"axis_title_font_size\": 1000  # 10pt - Standard\n\"axis_title_font_size\": 1100  # 11pt - Medium\n\"axis_title_font_size\": 1200  # 12pt - Large\n\n# Legend Sizes\n\"legend_font_size\": 800   # 8pt  - Compact\n\"legend_font_size\": 900   # 9pt  - Small\n\"legend_font_size\": 1000  # 10pt - Standard\n\"legend_font_size\": 1100  # 11pt - Medium\n```\n\n**Why Hundredths of a Point?**\n- Precise control over text sizing\n- Matches Excel's internal OOXML format\n- Allows fractional point sizes (e.g., 1050 = 10.5pt)\n- Same system used throughout Microsoft Office\n\n**Quick Conversion Formula:**\n```python\n# Points to hundredths\nhundredths = points * 100\n\n# Hundredths to points\npoints = hundredths / 100\n\n# Example: 14pt title\ntitle_font_size = 14 * 100  # = 1400\n```\n\n### Understanding Axis Scaling\n\nControl the Y-axis range to focus on relevant data ranges or maintain consistent scales across charts.\n\n**Basic Axis Scaling:**\n```python\ncharts = [{\n    \"chart_type\": \"line\",\n    \"data_range\": (0, 0, 3, 1),\n    \"from_col\": 5, \"from_row\": 0,\n    \"to_col\": 15, \"to_row\": 20,\n    \"title\": \"Test Scores\",\n    \"category_col\": 0,\n    \"axis_min\": 0.0,      # Y-axis starts at 0\n    \"axis_max\": 100.0,    # Y-axis ends at 100\n}]\n```\n\n**When to Use Axis Scaling:**\n\n1. **Percentage Data (0-100%):**\n```python\n\"axis_min\": 0.0,\n\"axis_max\": 100.0,  # Perfect for showing 0-100% range\n```\n\n2. **Normalized Data (0-1):**\n```python\n\"axis_min\": 0.0,\n\"axis_max\": 1.0,  # For decimal percentages (use with percent_stacked)\n```\n\n3. **Focus on Variance:**\n```python\n# Data ranges from 85-95, default would show 0-100\n\"axis_min\": 80.0,\n\"axis_max\": 100.0,  # Zoom in to show meaningful differences\n```\n\n4. **Compare Multiple Charts:**\n```python\n# Use same scale across all charts for fair comparison\n\"axis_min\": 0.0,\n\"axis_max\": 50000.0,  # All revenue charts use same scale\n```\n\n5. **Symmetric Ranges:**\n```python\n# For profit/loss or change data\n\"axis_min\": -10000.0,\n\"axis_max\": 10000.0,  # Symmetric around zero\n```\n\n**Special Case - Percent Stacked Charts:**\n```python\n# When using percent_stacked, values are 0.0 to 1.0\ncharts = [{\n    \"chart_type\": \"column\",\n    \"data_range\": (0, 0, 3, 3),\n    \"percent_stacked\": True,\n    \"axis_min\": 0.0,    # 0% = 0.0\n    \"axis_max\": 1.0,    # 100% = 1.0\n    \"y_axis_title\": \"Percentage\"\n}]\n```\n\n**Axis Scaling Best Practices:**\n- Always start at 0.0 for bar/column charts to avoid misleading visuals\n- Use axis_min \u003e 0 only for line charts showing trends\n- For percent_stacked, always use axis_min=0.0 and axis_max=1.0\n- Omit axis_min/axis_max to let Excel auto-scale\n- Use consistent scales when comparing multiple charts\n\n### Advanced Chart Styling\n\nCustomize chart appearance with styling options:\n\n```python\nimport polars as pl\nimport jetxl as jet\n\ndf = pl.DataFrame({\n    \"Month\": [\"Jan\", \"Feb\", \"Mar\", \"Apr\"],\n    \"Sales\": [10000, 12000, 11000, 13000],\n    \"Target\": [9000, 10000, 12000, 14000]\n})\n\ncharts = [{\n    \"chart_type\": \"bar\",\n    \"data_range\": (0, 0, 3, 2),\n    \"from_col\": 5,\n    \"from_row\": 0,\n    \"to_col\": 15,\n    \"to_row\": 20,\n    \n    # Title styling\n    \"title\": \"Sales vs Target\",\n    \"title_bold\": True,\n    \"title_font_size\": 1800,      # 18pt (in hundredths of point)\n    \"title_color\": \"0070C0\",      # Blue (ARGB hex without alpha)\n    \n    # Axis titles with styling\n    \"x_axis_title\": \"Amount ($)\",\n    \"y_axis_title\": \"Month\",\n    \"axis_title_bold\": True,\n    \"axis_title_font_size\": 1200,  # 12pt\n    \"axis_title_color\": \"00B050\",  # Green\n    \n    # Legend styling\n    \"show_legend\": True,\n    \"legend_position\": \"bottom\",\n    \"legend_bold\": True,\n    \"legend_font_size\": 1000,      # 10pt\n    \n    # Chart style and data labels\n    \"chart_style\": 104,             # Apply Excel chart style\n    \"show_data_labels\": True,\n    \n    # Axis scaling\n    \"axis_min\": 0.0,\n    \"axis_max\": 15000.0,\n    \n    \"category_col\": 0\n}]\n\njet.write_sheet_arrow(df.to_arrow(), \"styled_chart.xlsx\", charts=charts)\n```\n\n**Chart Style Numbers:**\n- Excel supports chart styles numbered 1-48\n- Each chart type has different style variations\n- Common styles: 2 (colorful), 11 (monochrome), 26 (dark), 42 (gradient)\n- Experiment with different numbers to find your preferred style\n\n**Font Sizes:**\n- Font sizes are specified in hundredths of a point\n- Examples: 800 = 8pt, 1000 = 10pt, 1200 = 12pt, 1800 = 18pt\n\n### Data Labels on Charts\n\nAdd data labels to show values directly on chart elements:\n\n```python\ndf = pl.DataFrame({\n    \"Product\": [\"A\", \"B\", \"C\", \"D\"],\n    \"Sales\": [250, 380, 420, 290]\n})\n\ncharts = [{\n    \"chart_type\": \"column\",\n    \"data_range\": (0, 0, 3, 1),\n    \"from_col\": 3,\n    \"from_row\": 0,\n    \"to_col\": 11,\n    \"to_row\": 15,\n    \"title\": \"Product Sales\",\n    \"category_col\": 0,\n    \"show_data_labels\": True,  # Display values on bars\n    \"x_axis_title\": \"Product\",\n    \"y_axis_title\": \"Units Sold\"\n}]\n\njet.write_sheet_arrow(df.to_arrow(), \"chart_with_labels.xlsx\", charts=charts)\n```\n\n### Axis Scaling\n\nControl the Y-axis range for better visualization:\n\n```python\ndf = pl.DataFrame({\n    \"Month\": [\"Jan\", \"Feb\", \"Mar\", \"Apr\"],\n    \"Score\": [92, 88, 95, 91]\n})\n\ncharts = [{\n    \"chart_type\": \"line\",\n    \"data_range\": (0, 0, 3, 1),\n    \"from_col\": 3,\n    \"from_row\": 0,\n    \"to_col\": 11,\n    \"to_row\": 15,\n    \"title\": \"Test Scores\",\n    \"category_col\": 0,\n    \"axis_min\": 80.0,     # Start Y-axis at 80\n    \"axis_max\": 100.0,    # End Y-axis at 100\n    \"x_axis_title\": \"Month\",\n    \"y_axis_title\": \"Score\",\n    \"show_data_labels\": True\n}]\n\njet.write_sheet_arrow(df.to_arrow(), \"scaled_chart.xlsx\", charts=charts)\n```\n\n### Pie Chart with Styling\n\n```python\ndf = pl.DataFrame({\n    \"Category\": [\"North\", \"South\", \"East\", \"West\"],\n    \"Sales\": [2500, 1800, 2200, 1500]\n})\n\ncharts = [{\n    \"chart_type\": \"pie\",\n    \"data_range\": (0, 0, 3, 1),\n    \"from_col\": 3,\n    \"from_row\": 0,\n    \"to_col\": 10,\n    \"to_row\": 15,\n    \"title\": \"Regional Distribution\",\n    \"title_bold\": True,\n    \"title_font_size\": 1800,\n    \"category_col\": 0,\n    \"show_data_labels\": True,  # Show percentages/values\n    \"legend_font_size\": 1100\n}]\n\njet.write_sheet_arrow(df.to_arrow(), \"pie_chart.xlsx\", charts=charts)\n```\n\n### Scatter Chart with Axis Control\n\n```python\ndf = pl.DataFrame({\n    \"X\": [1, 2, 3, 4, 5],\n    \"Y1\": [10, 25, 30, 45, 60],\n    \"Y2\": [15, 20, 35, 40, 55]\n})\n\ncharts = [{\n    \"chart_type\": \"scatter\",\n    \"data_range\": (0, 0, 4, 2),\n    \"from_col\": 5,\n    \"from_row\": 0,\n    \"to_col\": 15,\n    \"to_row\": 20,\n    \"title\": \"Correlation Analysis\",\n    \"axis_min\": 0.0,\n    \"axis_max\": 70.0,\n    \"x_axis_title\": \"X Values\",\n    \"y_axis_title\": \"Y Values\",\n    \"show_data_labels\": False,\n    \"series_names\": [\"Series 1\", \"Series 2\"]\n}]\n\njet.write_sheet_arrow(df.to_arrow(), \"scatter_chart.xlsx\", charts=charts)\n```\n\n### Multiple Charts in One Sheet\n\nYou can add multiple charts to the same worksheet:\n\n```python\ndf = pl.DataFrame({\n    \"Month\": [\"Jan\", \"Feb\", \"Mar\", \"Apr\"],\n    \"Revenue\": [10000, 12000, 11000, 13000],\n    \"Expenses\": [7000, 8000, 7500, 8500],\n    \"Profit\": [3000, 4000, 3500, 4500]\n})\n\ncharts = [\n    {\n        # Column chart for Revenue and Expenses\n        \"chart_type\": \"column\",\n        \"data_range\": (0, 0, 3, 2),\n        \"from_col\": 5,\n        \"from_row\": 0,\n        \"to_col\": 13,\n        \"to_row\": 15,\n        \"title\": \"Revenue \u0026 Expenses\",\n        \"title_bold\": True,\n        \"category_col\": 0,\n        \"series_names\": [\"Revenue\", \"Expenses\"],\n        \"show_data_labels\": True,\n        \"x_axis_title\": \"Month\",\n        \"y_axis_title\": \"Amount ($)\"\n    },\n    {\n        # Line chart for Profit trend\n        \"chart_type\": \"line\",\n        \"data_range\": (0, 0, 3, 3),\n        \"from_col\": 5,\n        \"from_row\": 17,\n        \"to_col\": 13,\n        \"to_row\": 32,\n        \"title\": \"Profit Trend\",\n        \"title_color\": \"00B050\",\n        \"category_col\": 0,\n        \"series_names\": [\"Profit\"],\n        \"x_axis_title\": \"Month\",\n        \"y_axis_title\": \"Profit ($)\",\n        \"chart_style\": 26\n    }\n]\n\njet.write_sheet_arrow(df.to_arrow(), \"multiple_charts.xlsx\", charts=charts)\n```\n\n### Complete Advanced Chart Example\n\nHere's a comprehensive example using all available chart features:\n\n```python\nimport polars as pl\nimport jetxl as jet\n\ndf = pl.DataFrame({\n    \"Quarter\": [\"Q1\", \"Q2\", \"Q3\", \"Q4\"],\n    \"Revenue\": [25000, 28000, 31000, 35000],\n    \"Profit\": [5000, 6500, 7200, 8500],\n    \"Expenses\": [20000, 21500, 23800, 26500]\n})\n\ncharts = [{\n    \"chart_type\": \"column\",\n    \n    # Data range - use tuple or individual parameters\n    \"data_range\": (0, 0, 3, 3),\n    # OR: \"start_row\": 1, \"start_col\": 0, \"end_row\": 4, \"end_col\": 3,\n    \n    # Chart position\n    \"from_col\": 5,\n    \"from_row\": 0,\n    \"to_col\": 15,\n    \"to_row\": 20,\n    \n    # Basic settings\n    \"title\": \"Quarterly Financial Performance\",\n    \"category_col\": 0,\n    \"series_names\": [\"Revenue\", \"Profit\", \"Expenses\"],\n    \n    # Stacking\n    \"percent_stacked\": True,  # Show as percentages\n    \n    # Title styling\n    \"title_bold\": True,\n    \"title_font_size\": 1600,\n    \"title_color\": \"0070C0\",\n    \n    # Axis configuration\n    \"x_axis_title\": \"Quarter\",\n    \"y_axis_title\": \"Percentage\",\n    \"axis_title_bold\": True,\n    \"axis_title_font_size\": 1200,\n    \"axis_title_color\": \"00B050\",\n    \"axis_min\": 0.0,\n    \"axis_max\": 1.0,\n    \n    # Legend\n    \"show_legend\": True,\n    \"legend_position\": \"bottom\",\n    \"legend_bold\": True,\n    \"legend_font_size\": 1000,\n    \n    # Visual enhancements\n    \"show_data_labels\": True,\n    \"chart_style\": 102\n}]\n\njet.write_sheet_arrow(\n    df.to_arrow(),\n    \"complete_chart.xlsx\",\n    charts=charts\n)\n```\n\n## 🖼️ Excel Images\n\nAdd images (logos, charts, diagrams) to your Excel sheets with precise positioning control.\n\n### Supported Image Formats\n\n| Format | Extensions | Best For | Notes |\n|--------|------------|----------|-------|\n| PNG | `.png` | Logos, screenshots | Lossless, supports transparency |\n| JPEG | `.jpg`, `.jpeg` | Photos | Smaller file size, no transparency |\n| GIF | `.gif` | Simple graphics | Limited colors, supports animation |\n| BMP | `.bmp` | Windows bitmaps | Large file size, uncompressed |\n| TIFF | `.tiff`, `.tif` | High-quality images | Professional printing |\n\n### Adding Images from Files\n\n### Adding Images from Files\n\nThe simplest way to add images is from file paths:\n\n```python\nimport polars as pl\nimport jetxl as jet\n\ndf = pl.DataFrame({\n    \"Product\": [\"Widget A\", \"Widget B\", \"Widget C\"],\n    \"Sales\": [1000, 1500, 1200]\n})\n\nimages = [{\n    \"path\": \"company_logo.png\",\n    \"from_col\": 0,   # Column A (0-based)\n    \"from_row\": 0,   # Row 1 (0-based)\n    \"to_col\": 2,     # Column C\n    \"to_row\": 5      # Row 6\n}]\n\njet.write_sheet_arrow(\n    df.to_arrow(),\n    \"report_with_logo.xlsx\",\n    images=images\n)\n```\n\n### Adding Images from Bytes\n\nLoad images from memory (useful for API responses, databases, or generated images):\n\n```python\nimport requests\nimport jetxl as jet\n\n# Download image from URL\nresponse = requests.get(\"https://example.com/chart.png\")\nimage_bytes = response.content\n\n# Or read from file\nwith open(\"logo.png\", \"rb\") as f:\n    image_bytes = f.read()\n\nimages = [{\n    \"data\": image_bytes,\n    \"extension\": \"png\",  # Required when using bytes\n    \"from_col\": 5,\n    \"from_row\": 1,\n    \"to_col\": 12,\n    \"to_row\": 15\n}]\n\njet.write_sheet_arrow(\n    df.to_arrow(),\n    \"report.xlsx\",\n    images=images\n)\n```\n\n### Multiple Images\n\nAdd multiple images to the same sheet:\n\n```python\nimages = [\n    {\n        # Company logo in top-left\n        \"path\": \"company_logo.png\",\n        \"from_col\": 0,\n        \"from_row\": 0,\n        \"to_col\": 2,\n        \"to_row\": 4\n    },\n    {\n        # Product image on the right\n        \"path\": \"product_photo.jpg\",\n        \"from_col\": 8,\n        \"from_row\": 2,\n        \"to_col\": 12,\n        \"to_row\": 10\n    },\n    {\n        # Chart at the bottom\n        \"path\": \"sales_chart.png\",\n        \"from_col\": 0,\n        \"from_row\": 15,\n        \"to_col\": 10,\n        \"to_row\": 30\n    }\n]\n\njet.write_sheet_arrow(\n    df.to_arrow(),\n    \"multi_image_report.xlsx\",\n    images=images\n)\n```\n\n### Image Positioning Guide\n\nImages are positioned using Excel's column/row coordinates:\n- **Columns** are 0-indexed: A=0, B=1, C=2, etc.\n- **Rows** are 0-indexed: 0=row 1, 1=row 2, etc.\n\n```python\n# Position image from B3 to F10\nimage = {\n    \"path\": \"image.png\",\n    \"from_col\": 1,   # Column B (0-based)\n    \"from_row\": 2,   # Row 3 (0-based)\n    \"to_col\": 5,     # Column F\n    \"to_row\": 9      # Row 10\n}\n```\n\n**Size Recommendations:**\n- **Small**: 2-4 columns × 5-8 rows (logos, icons)\n- **Medium**: 4-6 columns × 8-12 rows (product photos)\n- **Large**: 6-10 columns × 12-20 rows (charts, diagrams)\n\n### Combining Images with Data\n\nCreate professional reports with logos, data, and visualizations:\n\n```python\nimport polars as pl\nimport jetxl as jet\n\n# Sample data\ndf = pl.DataFrame({\n    \"Month\": [\"Jan\", \"Feb\", \"Mar\", \"Apr\"],\n    \"Revenue\": [10000, 12000, 11000, 13000],\n    \"Costs\": [7000, 8000, 7500, 8500]\n})\n\n# Add company logo, data table, and chart image\njet.write_sheet_arrow(\n    df.to_arrow(),\n    \"monthly_report.xlsx\",\n    sheet_name=\"Financial Report\",\n    styled_headers=True,\n    freeze_rows=1,\n    column_formats={\n        \"Revenue\": \"currency\",\n        \"Costs\": \"currency\"\n    },\n    images=[\n        {\n            # Logo at top\n            \"path\": \"company_logo.png\",\n            \"from_col\": 0,\n            \"from_row\": 0,\n            \"to_col\": 2,\n            \"to_row\": 3\n        },\n        {\n            # Visualization chart\n            \"path\": \"revenue_chart.png\",\n            \"from_col\": 5,\n            \"from_row\": 5,\n            \"to_col\": 15,\n            \"to_row\": 25\n        }\n    ]\n)\n```\n\n### Images with Charts and Tables\n\nCombine all visualization features:\n\n```python\ndf = pl.DataFrame({\n    \"Product\": [\"A\", \"B\", \"C\", \"D\"],\n    \"Q1\": [100, 150, 120, 180],\n    \"Q2\": [110, 160, 130, 190],\n    \"Q3\": [120, 170, 140, 200]\n})\n\njet.write_sheet_arrow(\n    df.to_arrow(),\n    \"complete_dashboard.xlsx\",\n    tables=[{\n        \"name\": \"SalesTable\",\n        \"start_row\": 1,\n        \"start_col\": 0,\n        \"end_row\": 4,\n        \"end_col\": 3,\n        \"style\": \"TableStyleMedium2\"\n    }],\n    charts=[{\n        \"chart_type\": \"column\",\n        \"start_row\": 1,\n        \"start_col\": 0,\n        \"end_row\": 4,\n        \"end_col\": 3,\n        \"from_col\": 5,\n        \"from_row\": 5,\n        \"to_col\": 13,\n        \"to_row\": 20,\n        \"title\": \"Quarterly Sales\"\n    }],\n    images=[{\n        \"path\": \"company_logo.png\",\n        \"from_col\": 0,\n        \"from_row\": 0,\n        \"to_col\": 2,\n        \"to_row\": 3\n    }]\n)\n```\n\n### Images Across Multiple Sheets\n\nEach sheet can have its own images:\n\n```python\ndf_summary = pl.DataFrame({\"Metric\": [\"Total Sales\"], \"Value\": [50000]})\ndf_details = pl.DataFrame({\"Product\": [\"A\", \"B\"], \"Sales\": [30000, 20000]})\n\nsheets = [\n    {\n        \"data\": df_summary.to_arrow(),\n        \"name\": \"Summary\",\n        \"images\": [{\n            \"path\": \"company_logo.png\",\n            \"from_col\": 0,\n            \"from_row\": 0,\n            \"to_col\": 2,\n            \"to_row\": 4\n        }]\n    },\n    {\n        \"data\": df_details.to_arrow(),\n        \"name\": \"Details\",\n        \"images\": [{\n            \"path\": \"product_breakdown.png\",\n            \"from_col\": 4,\n            \"from_row\": 1,\n            \"to_col\": 12,\n            \"to_row\": 15\n        }]\n    }\n]\n\njet.write_sheets_arrow(sheets, \"multi_sheet_report.xlsx\", num_threads=2)\n```\n\n### Working with Generated Images\n\nCombine with image generation libraries:\n\n```python\nimport matplotlib.pyplot as plt\nimport io\nimport jetxl as jet\n\n# Generate a chart with matplotlib\nfig, ax = plt.subplots()\nax.plot([1, 2, 3, 4], [10, 20, 15, 25])\nax.set_title(\"Sales Trend\")\n\n# Save to bytes\nimg_buffer = io.BytesIO()\nfig.savefig(img_buffer, format='png', dpi=150, bbox_inches='tight')\nimg_bytes = img_buffer.getvalue()\nplt.close(fig)\n\n# Add to Excel\njet.write_sheet_arrow(\n    df.to_arrow(),\n    \"report_with_chart.xlsx\",\n    images=[{\n        \"data\": img_bytes,\n        \"extension\": \"png\",\n        \"from_col\": 5,\n        \"from_row\": 1,\n        \"to_col\": 15,\n        \"to_row\": 20\n    }]\n)\n```\n\n### Image Best Practices\n\n1. **File Formats**\n   - Use PNG for logos and screenshots (lossless, supports transparency)\n   - Use JPEG for photos (smaller file size)\n   - Use GIF for simple animations (limited color palette)\n\n2. **Image Size**\n   - Optimize images before embedding to reduce file size\n   - Use appropriate dimensions for your target (don't embed 4K images for small displays)\n   - Consider using PIL/Pillow to resize images programmatically\n\n3. **Performance**\n   - Large images increase Excel file size\n   - Multiple large images can slow down Excel opening time\n   - Compress images before embedding when possible\n\n4. **Positioning**\n   - Leave space around images for readability\n   - Align images with data columns when possible\n   - Use consistent sizing for professional appearance\n\n## 🔗 Hyperlinks\n\n```python\nhyperlinks = [\n    (2, 0, \"https://example.com\", \"Visit Example\"),  # Row 2, Col 0\n    (3, 0, \"https://google.com\", None),              # Display URL as text\n    (4, 2, \"mailto:user@example.com\", \"Email Us\")\n]\n\njet.write_sheet_arrow(df.to_arrow(), \"links.xlsx\", hyperlinks=hyperlinks)\n```\n\n## 📢 Formulas\n```python\nformulas = [\n    (2, 3, \"=SUM(A2:C2)\", None),           # Simple formula\n    (5, 3, \"=AVERAGE(D2:D4)\", \"45.5\"),     # Formula with cached value\n    (6, 3, \"=IF(D5\u003e50,\\\"High\\\",\\\"Low\\\")\", None)\n]\n\njet.write_sheet_arrow(df.to_arrow(), \"formulas.xlsx\", formulas=formulas)\n```\n\n### Understanding Cached Values\n\nThe cached value is the pre-calculated result shown before Excel recalculates the formula:\n```python\nformulas = [\n    # No cached value - Excel calculates on open\n    (2, 3, \"=SUM(A2:C2)\", None),\n    \n    # With cached value - shows \"45.5\" until Excel recalculates\n    (5, 3, \"=AVERAGE(D2:D4)\", \"45.5\"),\n]\n```\n\n**When to use cached values:**\n- Formulas that reference external data sources\n- Complex calculations that take time to compute\n- When you want to show a result before Excel opens\n- Cross-workbook references that may not be available\n\n**When to use None:**\n- Simple formulas (SUM, AVERAGE of local cells)\n- When you want Excel to always calculate fresh\n- Formulas with volatile functions (NOW, RAND)\n\n## 🔀 Merge Cells\n\n```python\nmerge_cells = [\n    (1, 0, 1, 3),  # Merge A1:D1 (start_row, start_col, end_row, end_col)\n    (2, 0, 5, 0),  # Merge A2:A5\n]\n\njet.write_sheet_arrow(df.to_arrow(), \"merged.xlsx\", merge_cells=merge_cells)\n```\n\n## ✅ Data Validation\n\n### Dropdown Lists\n\n```python\nvalidations = [{\n    \"start_row\": 2,\n    \"start_col\": 0,\n    \"end_row\": 100,\n    \"end_col\": 0,\n    \"type\": \"list\",\n    \"items\": [\"Option A\", \"Option B\", \"Option C\"],\n    \"show_dropdown\": True,\n    \"error_title\": \"Invalid Selection\",\n    \"error_message\": \"Please select from the dropdown\"\n}]\n\njet.write_sheet_arrow(df.to_arrow(), \"validation.xlsx\", data_validations=validations)\n```\n\n### Number Ranges\n\n```python\nvalidations = [{\n    \"start_row\": 2,\n    \"start_col\": 1,\n    \"end_row\": 100,\n    \"end_col\": 1,\n    \"type\": \"whole_number\",\n    \"min\": 1,\n    \"max\": 100,\n    \"error_title\": \"Out of Range\",\n    \"error_message\": \"Value must be between 1 and 100\"\n}]\n```\n\n### Decimal Ranges\n\n```python\nvalidations = [{\n    \"start_row\": 2,\n    \"start_col\": 2,\n    \"end_row\": 100,\n    \"end_col\": 2,\n    \"type\": \"decimal\",\n    \"min\": 0.0,\n    \"max\": 100.0\n}]\n```\n\n### Text Length\n\nValidate text input length:\n```python\nvalidations = [{\n    \"start_row\": 2,\n    \"start_col\": 0,\n    \"end_row\": 100,\n    \"end_col\": 0,\n    \"type\": \"text_length\",\n    \"min\": 3,\n    \"max\": 20,\n    \"error_title\": \"Invalid Username\",\n    \"error_message\": \"Username must be 3-20 characters long\"\n}]\n\njet.write_sheet_arrow(df.to_arrow(), \"validation.xlsx\", data_validations=validations)\n```\n\n## 🎨 Conditional Formatting\n\n### Cell Value Rules\n\n```python\nconditional_formats = [{\n    \"start_row\": 2,\n    \"start_col\": 2,\n    \"end_row\": 100,\n    \"end_col\": 2,\n    \"rule_type\": \"cell_value\",\n    \"operator\": \"greater_than\",  # less_than, equal, not_equal, etc.\n    \"value\": \"50\",\n    \"priority\": 1,\n    \"style\": {\n        \"font\": {\n            \"bold\": True,\n            \"color\": \"FFFF0000\"  # Red text\n        },\n        \"fill\": {\n            \"pattern\": \"solid\",\n            \"fg_color\": \"FFFFFF00\"  # Yellow background\n        }\n    }\n}]\n\njet.write_sheet_arrow(df.to_arrow(), \"conditional.xlsx\", conditional_formats=conditional_formats)\n```\n### All Comparison Operators\n\nThe `cell_value` rule type supports these operators:\n```python\n# Greater than\n\"operator\": \"greater_than\",  \"value\": \"100\"\n\n# Less than\n\"operator\": \"less_than\",  \"value\": \"50\"\n\n# Equal to\n\"operator\": \"equal\",  \"value\": \"0\"\n\n# Not equal to\n\"operator\": \"not_equal\",  \"value\": \"0\"\n\n# Greater than or equal\n\"operator\": \"greater_than_or_equal\",  \"value\": \"100\"\n\n# Less than or equal\n\"operator\": \"less_than_or_equal\",  \"value\": \"50\"\n\n# Between (use comma-separated values)\n\"operator\": \"between\",  \"value\": \"10,100\"\n```\n\n### Color Scale Variations\n```python\n# Two-color scale (min to max)\nconditional_formats = [{\n    \"start_row\": 2,\n    \"start_col\": 2,\n    \"end_row\": 100,\n    \"end_col\": 2,\n    \"rule_type\": \"color_scale\",\n    \"min_color\": \"FFF8696B\",  # Red\n    \"max_color\": \"FF63BE7B\",  # Green\n    \"priority\": 1\n}]\n\n# Three-color scale (min to mid to max)\n# Better for showing deviation from average/target\nconditional_formats = [{\n    \"start_row\": 2,\n    \"start_col\": 2,\n    \"end_row\": 100,\n    \"end_col\": 2,\n    \"rule_type\": \"color_scale\",\n    \"min_color\": \"FFF8696B\",  # Red for low values\n    \"mid_color\": \"FFFFEB84\",  # Yellow for medium values\n    \"max_color\": \"FF63BE7B\",  # Green for high values\n    \"priority\": 1\n}]\n```\n\n### Top/Bottom N Values\n\nHighlight the highest or lowest values in a range:\n```python\n# Highlight top 10 values\nconditional_formats = [{\n    \"start_row\": 2,\n    \"start_col\": 2,\n    \"end_row\": 100,\n    \"end_col\": 2,\n    \"rule_type\": \"top10\",\n    \"rank\": 10,\n    \"bottom\": False,  # Top 10 (set to True for bottom 10)\n    \"priority\": 1,\n    \"style\": {\n        \"font\": {\"bold\": True, \"color\": \"FF00B050\"},\n        \"fill\": {\"pattern\": \"solid\", \"fg_color\": \"FFC6EFCE\"}\n    }\n}]\n\n# Highlight bottom 5 values\nconditional_formats = [{\n    \"start_row\": 2,\n    \"start_col\": 2,\n    \"end_row\": 100,\n    \"end_col\": 2,\n    \"rule_type\": \"top10\",\n    \"rank\": 5,\n    \"bottom\": True,  # Bottom 5\n    \"priority\": 1,\n    \"style\": {\n        \"font\": {\"bold\": True, \"color\": \"FFFF0000\"},\n        \"fill\": {\"pattern\": \"solid\", \"fg_color\": \"FFFFC7CE\"}\n    }\n}]\n```\n\n## 📊 Multiple Sheets\n\nCreate multi-sheet workbooks with full independent formatting per sheet. Each sheet supports **all features** from `write_sheet_arrow()` including tables, charts, images, conditional formatting, data validation, formulas, cell styles, and more.\n\n### Basic Multi-Sheet\n```python\nimport polars as pl\nimport jetxl as jet\n\ndf_sales = pl.DataFrame({\"Product\": [\"A\", \"B\"], \"Revenue\": [100, 200]})\ndf_costs = pl.DataFrame({\"Product\": [\"A\", \"B\"], \"Cost\": [50, 80]})\ndf_profit = pl.DataFrame({\"Product\": [\"A\", \"B\"], \"Profit\": [50, 120]})\n\nsheets = [\n    {\n        \"data\": df_sales.to_arrow(),\n        \"name\": \"Sales\",\n        \"auto_filter\": True\n    },\n    {\n        \"data\": df_costs.to_arrow(),\n        \"name\": \"Costs\",\n        \"freeze_rows\": 1\n    },\n    {\n        \"data\": df_profit.to_arrow(),\n        \"name\": \"Profit\",\n        \"styled_headers\": True\n    }\n]\n\njet.write_sheets_arrow(\n    sheets,\n    \"report.xlsx\",\n    num_threads=4  # Use 4 threads for parallel generation\n)\n```\n\n### Independent Formatting Per Sheet\n\nEach sheet can have completely different formatting:\n```python\nsheets = [\n    {\n        \"data\": df_sales.to_arrow(),\n        \"name\": \"Sales\",\n        \"styled_headers\": True,\n        \"auto_filter\": True,\n        \"freeze_rows\": 1,\n        \"column_formats\": {\n            \"Date\": \"date\",\n            \"Revenue\": \"currency\",\n            \"Tax\": \"percentage\"\n        },\n        \"tables\": [{\n            \"name\": \"SalesTable\",\n            \"start_row\": 1,\n            \"start_col\": 0,\n            \"end_row\": 100,\n            \"end_col\": 5,\n            \"style\": \"TableStyleMedium2\"\n        }],\n        \"tab_color\": \"FF00B050\"  # Green tab\n    },\n    {\n        \"data\": df_costs.to_arrow(),\n        \"name\": \"Costs\",\n        \"auto_width\": True,\n        \"conditional_formats\": [{\n            \"start_row\": 2,\n            \"start_col\": 2,\n            \"end_row\": 100,\n            \"end_col\": 2,\n            \"rule_type\": \"data_bar\",\n            \"color\": \"FFFF0000\",\n            \"show_value\": True,\n            \"priority\": 1\n        }],\n        \"tab_color\": \"FFFF0000\"  # Red tab\n    },\n    {\n        \"data\": df_profit.to_arrow(),\n        \"name\": \"Profit\",\n        \"write_header_row\": False,  # Data only, no headers\n        \"hidden_columns\": [2, 3],\n        \"gridlines_visible\": False,\n        \"zoom_scale\": 150\n    }\n]\n\njet.write_sheets_arrow(sheets, \"advanced.xlsx\", num_threads=3)\n```\n\n### Multi-Sheet with Charts, Tables, and Images\n```python\nsheets = [\n    {\n        \"data\": df_monthly.to_arrow(),\n        \"name\": \"Monthly Sales\",\n        \"styled_headers\": True,\n        \"freeze_rows\": 1,\n        \n        # Excel table\n        \"tables\": [{\n            \"name\": \"MonthlySales\",\n            \"start_row\": 1,\n            \"start_col\": 0,\n            \"end_row\": 12,\n            \"end_col\": 3,\n            \"style\": \"TableStyleMedium9\"\n        }],\n        \n        # Chart\n        \"charts\": [{\n            \"chart_type\": \"column\",\n            \"start_row\": 1,\n            \"start_col\": 0,\n            \"end_row\": 12,\n            \"end_col\": 2,\n            \"from_col\": 5,\n            \"from_row\": 1,\n            \"to_col\": 13,\n            \"to_row\": 16,\n            \"title\": \"Monthly Sales Trend\",\n            \"category_col\": 0,\n            \"x_axis_title\": \"Month\",\n            \"y_axis_title\": \"Revenue ($)\"\n        }],\n        \n        # Logo\n        \"images\": [{\n            \"path\": \"company_logo.png\",\n            \"from_col\": 0,\n            \"from_row\": 0,\n            \"to_col\": 2,\n            \"to_row\": 4\n        }]\n    },\n    {\n        \"data\": df_quarterly.to_arrow(),\n        \"name\": \"Quarterly\",\n        \"auto_filter\": True,\n        \n        # Different chart type\n        \"charts\": [{\n            \"chart_type\": \"pie\",\n            \"start_row\": 1,\n            \"start_col\": 0,\n            \"end_row\": 4,\n            \"end_col\": 1,\n            \"from_col\": 3,\n            \"from_row\": 1,\n            \"to_col\": 10,\n            \"to_row\": 15,\n            \"title\": \"Market Share\"\n        }]\n    }\n]\n\njet.write_sheets_arrow(sheets, \"dashboard.xlsx\", num_threads=2)\n```\n\n### All Features Per Sheet\n\nEvery sheet supports the full API from `write_sheet_arrow()`:\n```python\nsheets = [\n    {\n        \"data\": df.to_arrow(),\n        \"name\": \"Complete Example\",\n        \n        # Basic formatting\n        \"auto_filter\": True,\n        \"freeze_rows\": 1,\n        \"freeze_cols\": 0,\n        \"auto_width\": True,\n        \"styled_headers\": True,\n        \"write_header_row\": True,\n        \n        # Column formatting\n        \"column_widths\": {\"Name\": 25.0, \"Email\": \"200px\", \"Notes\": \"auto\"},\n        \"column_formats\": {\"Date\": \"date\", \"Amount\": \"currency\", \"Rate\": \"percentage\"},\n        \n        # Cell operations\n        \"merge_cells\": [(1, 0, 1, 3), (5, 0, 8, 0)],\n        \"row_heights\": {1: 30.0, 5: 25.0},\n        \n        # Cell styles\n        \"cell_styles\": [{\n            \"row\": 2,\n            \"col\": 0,\n            \"font\": {\"bold\": True, \"color\": \"FFFF0000\", \"size\": 14.0},\n            \"fill\": {\"pattern\": \"solid\", \"fg_color\": \"FFFFFF00\"},\n            \"alignment\": {\"horizontal\": \"center\", \"vertical\": \"center\"}\n        }],\n        \n        # Data validation\n        \"data_validations\": [{\n            \"start_row\": 2, \"start_col\": 4,\n            \"end_row\": 100, \"end_col\": 4,\n            \"type\": \"list\",\n            \"items\": [\"Active\", \"Pending\", \"Closed\"],\n            \"show_dropdown\": True\n        }],\n        \n        # Hyperlinks\n        \"hyperlinks\": [(2, 0, \"https://example.com\", \"Visit Site\")],\n        \n        # Formulas\n        \"formulas\": [(5, 5, \"=SUM(A2:A4)\", None)],\n        \n        # Conditional formatting\n        \"conditional_formats\": [{\n            \"start_row\": 2, \"start_col\": 3,\n            \"end_row\": 100, \"end_col\": 3,\n            \"rule_type\": \"color_scale\",\n            \"min_color\": \"FFF8696B\",\n            \"mid_color\": \"FFFFEB84\",\n            \"max_color\": \"FF63BE7B\",\n            \"priority\": 1\n        }],\n        \n        # Excel tables\n        \"tables\": [{\n            \"name\": \"DataTable\",\n            \"start_row\": 1, \"start_col\": 0,\n            \"end_row\": 100, \"end_col\": 5,\n            \"style\": \"TableStyleMedium2\"\n        }],\n        \n        # Charts\n        \"charts\": [{\n            \"chart_type\": \"column\",\n            \"start_row\": 1, \"start_col\": 0,\n            \"end_row\": 12, \"end_col\": 2,\n            \"from_col\": 7, \"from_row\": 1,\n            \"to_col\": 15, \"to_row\": 18,\n            \"title\": \"Sales Chart\"\n        }],\n        \n        # Images\n        \"images\": [{\n            \"path\": \"logo.png\",\n            \"from_col\": 0, \"from_row\": 0,\n            \"to_col\": 2, \"to_row\": 4\n        }],\n        \n        # Appearance\n        \"gridlines_visible\": False,\n        \"zoom_scale\": 120,\n        \"tab_color\": \"FF4472C4\",\n        \"default_row_height\": 18.0,\n        \"hidden_columns\": [2],\n        \"hidden_rows\": [5, 6],\n        \"right_to_left\": False,\n        \"data_start_row\": 0\n    }\n]\n\njet.write_sheets_arrow(sheets, \"everything.xlsx\", num_threads=1)\n```\n\n**Performance Notes:**\n- XML generation is fully parallel across `num_threads`\n- Each sheet can have independent formatting with minimal overhead (\u003c1%)\n- Style registry is shared for deduplication\n- Recommended: `num_threads = min(cpu_count, len(sheets))`\n\n## 🎨 Sheet Appearance \u0026 Layout\n\n### Gridlines and Zoom\n\nControl worksheet visibility settings:\n```python\nimport polars as pl\nimport jetxl as jet\n\ndf = pl.DataFrame({\n    \"Product\": [\"A\", \"B\", \"C\"],\n    \"Price\": [10.0, 20.0, 30.0]\n})\n\n# Hide gridlines and set zoom\njet.write_sheet_arrow(\n    df.to_arrow(),\n    \"clean_view.xlsx\",\n    gridlines_visible=False,  # Hide gridlines for cleaner look\n    zoom_scale=150            # Zoom to 150% (range: 10-400)\n)\n```\n\n### Sheet Tab Colors\n\nColor-code your sheets for better organization:\n```python\n# Single sheet with colored tab\njet.write_sheet_arrow(\n    df.to_arrow(),\n    \"colored_tab.xlsx\",\n    tab_color=\"FFFF0000\"  # Red tab (ARGB format)\n)\n\n# Multiple sheets with different colors\nsheets = [\n    {\n        \"data\": df_sales.to_arrow(),\n        \"name\": \"Sales\",\n        \"tab_color\": \"FF00B050\"  # Green\n    },\n    {\n        \"data\": df_costs.to_arrow(),\n        \"name\": \"Costs\",\n        \"tab_color\": \"FFFF0000\"  # Red\n    },\n    {\n        \"data\": df_profit.to_arrow(),\n        \"name\": \"Profit\",\n        \"tab_color\": \"FF0070C0\"  # Blue\n    }\n]\n\njet.write_sheets_arrow(sheets, \"colored_tabs.xlsx\", num_threads=2)\n```\n\n**Common Tab Colors:**\n- `\"FF4472C4\"` - Blue\n- `\"FF00B050\"` - Green\n- `\"FFFF0000\"` - Red\n- `\"FFFFC000\"` - Orange\n- `\"FF7030A0\"` - Purple\n\n### Default Row Height\n\nSet a consistent row height for all rows:\n```python\njet.write_sheet_arrow(\n    df.to_arrow(),\n    \"tall_rows.xlsx\",\n    default_row_height=25.0,  # 25 points (default is 15)\n    row_heights={\n        1: 35.0,  # Override: make header taller\n        5: 20.0   # Override: specific row\n    }\n)\n```\n\n### Hidden Rows and Columns\n\nHide sensitive or intermediate data:\n```python\ndf = pl.DataFrame({\n    \"ID\": [1, 2, 3],\n    \"Name\": [\"Alice\", \"Bob\", \"Charlie\"],\n    \"Secret\": [\"X\", \"Y\", \"Z\"],\n    \"Salary\": [50000, 60000, 75000],\n    \"Bonus\": [5000, 6000, 7500]\n})\n\njet.write_sheet_arrow(\n    df.to_arrow(),\n    \"hidden_data.xlsx\",\n    hidden_columns=[2, 4],  # Hide \"Secret\" (col 2) and \"Bonus\" (col 4)\n    hidden_rows=[3]         # Hide row 3\n)\n```\n\n**Note:** Hidden data is still in the file - it's just not visible by default. Users can unhide it in Excel.\n\n### Right-to-Left Layout\n\nFor languages like Arabic, Hebrew, Persian, etc.:\n```python\ndf = pl.DataFrame({\n    \"שם\": [\"אליס\", \"בוב\", \"צ'רלי\"],\n    \"גיל\": [25, 30, 35]\n})\n\njet.write_sheet_arrow(\n    df.to_arrow(),\n    \"hebrew.xlsx\",\n    right_to_left=True  # Sheet flows from right to left\n)\n```\n\n### Auto-Width with Complex Headers\n\nWhen your Excel file has multiple header rows, dummy rows, or template rows, exclude them from width calculation:\n```python\n# Scenario: Your file structure is:\n# Row 1: Company logo (merged cells with long text)\n# Row 2: Report title \"Q4 2024 Financial Summary - Confidential\"\n# Row 3: Date range\n# Row 4: Empty spacing row\n# Row 5: Column headers (Name, Amount, Status)\n# Row 6+: Actual data\n\n# Without data_start_row, auto_width uses ALL rows including dummy rows\n# This makes columns unnecessarily wide to fit the title text\n\njet.write_sheet_arrow(\n    df.to_arrow(),\n    \"complex_report.xlsx\",\n    auto_width=True,\n    data_start_row=5  # Start width calculation from row 5 (actual data)\n    # Now columns are sized based on data + headers only\n)\n```\n\n**Common use cases:**\n- Reports with title rows, logos, or metadata at the top\n- Templates with pre-existing formatting rows\n- Multi-section reports where only one section should determine width\n- Files with merged header rows that contain long text\n\n### Header Content (Template Rows)\n\nWrite arbitrary content above your DataFrame data - perfect for report titles, metadata, logos in merged cells, or template headers:\n```python\nimport polars as pl\nimport jetxl as jet\n\ndf = pl.DataFrame({\n    \"Name\": [\"Alice\", \"Bob\"],\n    \"Sales\": [1000, 1500]\n})\n\n# Add title rows, metadata, spacing before DataFrame\njet.write_sheet_arrow(\n    df.to_arrow(),\n    \"report.xlsx\",\n    header_content=[\n        (1, 0, \"ACME Corporation\"),           # Row 1, Col A\n        (1, 2, \"Confidential\"),               # Row 1, Col C\n        (2, 0, \"Q4 2024 Sales Report\"),       # Row 2, Col A\n        (3, 0, \"Generated: 2024-10-17\"),      # Row 3, Col A\n        # Row 4 is empty (spacing)\n    ],\n    data_start_row=5,  # DataFrame starts at row 5\n    write_header_row=True,  # Row 5 will have column headers\n    # Actual data starts at row 6\n    merge_cells=[\n        (1, 0, 1, 1),  # Merge A1:B1 for company name\n    ]\n)\n```\n\n**Common use cases:**\n- Report headers with company name, logo placeholder, dates\n- Multi-line titles with merged cells\n- Metadata rows (author, generated date, version)\n- Template text that shouldn't come from DataFrame\n- Section dividers in complex reports\n\n**Coordinates:**\n- Row numbers are 1-based (row 1 is first row)\n- Column numbers are 0-based (0=A, 1=B, 2=C, etc.)\n- `header_content` rows are written BEFORE DataFrame data\n- Use `data_start_row` to position DataFrame below header content\n\n\n\n\n### Professional Dashboard Example\n\nCombine appearance settings for a polished look:\n```python\nimport polars as pl\nimport jetxl as jet\n\ndf = pl.DataFrame({\n    \"Quarter\": [\"Q1\", \"Q2\", \"Q3\", \"Q4\"],\n    \"Revenue\": [100000, 120000, 115000, 140000],\n    \"Target\": [95000, 110000, 120000, 135000]\n})\n\njet.write_sheet_arrow(\n    df.to_arrow(),\n    \"executive_dashboard.xlsx\",\n    sheet_name=\"Performance\",\n    \n    # Clean appearance\n    gridlines_visible=False,\n    zoom_scale=120,\n    tab_color=\"FF0070C0\",\n    default_row_height=20.0,\n    \n    # Formatting\n    styled_headers=True,\n    freeze_rows=1,\n    auto_width=True,\n    column_formats={\n        \"Revenue\": \"currency\",\n        \"Target\": \"currency\"\n    },\n    \n    # Visualization\n    charts=[{\n        \"chart_type\": \"column\",\n        \"start_row\": 1,\n        \"start_col\": 0,\n        \"end_row\": 4,\n        \"end_col\": 2,\n        \"from_col\": 4,\n        \"from_row\": 1,\n        \"to_col\": 12,\n        \"to_row\": 18,\n        \"title\": \"Revenue vs Target\",\n        \"category_col\": 0,\n        \"x_axis_title\": \"Quarter\",\n        \"y_axis_title\": \"Amount ($)\"\n    }]\n)\n```\n\n\n\n\n## 📋 Complete Example\n\nHere's a comprehensive example using multiple features:\n\n```python\nimport polars as pl\nimport jetxl as jet\n\n# Create sample data\ndf = pl.DataFrame({\n    \"Date\": [\"2024-01-01\", \"2024-01-02\", \"2024-01-03\"],\n    \"Product\": [\"Widget A\", \"Widget B\", \"Widget C\"],\n    \"Quantity\": [100, 150, 75],\n    \"Price\": [19.99, 29.99, 39.99],\n    \"Revenue\": [1999.0, 4498.5, 2999.25]\n})\n\n# Tables auto-size to data\ntables = [{\n    \"name\": \"SalesData\",\n    \"display_name\": \"Q1 Sales\",\n    \"start_row\": 1,\n    \"start_col\": 0,\n    \"end_row\": 0,      # Auto-calculate from DataFrame rows\n    \"end_col\": 0,      # Auto-calculate from DataFrame columns\n    \"style\": \"TableStyleMedium9\",\n    \"show_row_stripes\": True\n}]\n\n# Add conditional formatting\nconditional_formats = [{\n    \"start_row\": 2,\n    \"start_col\": 4,\n    \"end_row\": 4,\n    \"end_col\": 4,\n    \"rule_type\": \"data_bar\",\n    \"color\": \"FF638EC6\",\n    \"show_value\": True,\n    \"priority\": 1\n}]\n\n# Add chart\ncharts = [{\n    \"chart_type\": \"column\",\n    \"start_row\": 1,\n    \"start_col\": 0,\n    \"end_row\": 4,\n    \"end_col\": 4,\n    \"from_col\": 6,\n    \"from_row\": 1,\n    \"to_col\": 14,\n    \"to_row\": 18,\n    \"title\": \"Revenue by Product\",\n    \"category_col\": 1,  # Product column\n    \"x_axis_title\": \"Product\",\n    \"y_axis_title\": \"Revenue ($)\",\n    \"show_legend\": False\n}]\n\n# Add logo image\nimages = [{\n    \"path\": \"company_logo.png\",\n    \"from_col\": 0,\n    \"from_row\": 0,\n    \"to_col\": 2,\n    \"to_row\": 3\n}]\n\n# Write to Excel\njet.write_sheet_arrow(\n    df.to_arrow(),\n    \"sales_report.xlsx\",\n    sheet_name=\"Q1 Sales\",\n    styled_headers=True,\n    freeze_rows=1,\n    auto_width=True,\n    column_formats={\n        \"Date\": \"date\",\n        \"Price\": \"currency\",\n        \"Revenue\": \"currency\"\n    },\n    tables=tables,\n    conditional_formats=conditional_formats,\n    charts=charts,\n    images=images\n)\n```\n\n\n\n## 🗃️ Architecture\n\nJetxl achieves its performance through several key optimizations:\n\n1. **Zero-copy Arrow Integration**: Direct memory access to DataFrame buffers without copying\n2. **SIMD XML Escaping**: Hardware-accelerated string processing\n3. **Pre-calculated Buffer Sizing**: Single allocation per sheet with exact size calculation\n4. **Parallel Sheet Generation**: Multi-threaded XML generation for multiple sheets\n5. **Optimized Number Formatting**: Fast integer/float detection and conversion\n6. **Streaming Compression**: On-the-fly ZIP compression with minimal memory overhead\n\n## 🔧 Advanced Usage\n\n### Working with Large Datasets\n\n```python\nimport polars as pl\nimport jetxl as jet\n\n# For very large datasets, use batched reading\ndf = pl.scan_csv(\"huge_file.csv\").collect()\n\n# Jetxl handles large datasets efficiently\njet.write_sheet_arrow(\n    df.to_arrow(),\n    \"large_output.xlsx\",\n    auto_width=False  # Disable auto-width for faster generation\n)\n```\n\n### Custom Styling Templates\n\n```python\ndef create_report_style():\n    return {\n        \"styled_headers\": True,\n        \"auto_filter\": True,\n        \"freeze_rows\": 1,\n        \"column_formats\": {\n            \"Date\": \"date\",\n            \"Amount\": \"currency\",\n            \"Percentage\": \"percentage\"\n        }\n    }\n\n# Apply consistent styling across reports\njet.write_sheet_arrow(df.to_arrow(), \"report.xlsx\", **create_report_style())\n```\n\n### Error Handling\n\n```python\ntry:\n    jet.write_sheet_arrow(df.to_arrow(), \"output.xlsx\")\nexcept IOError as e:\n    print(f\"Failed to write file: {e}\")\nexcept ValueError as e:\n    print(f\"Invalid data: {e}\")\n```\n\n## 🤝 Comparison with Other Libraries\n\n### vs xlsxwriter\n- ✅ **5x faster** (1M rows: 2.06s vs 10.05s)\n- ✅ Near-zero Python memory overhead\n- ✅ Zero-copy DataFrame integration\n- ✅ Multi-threaded sheet generation\n- ✅ Modern Python API with type hints\n- ❌ Larger output files (less aggressive compression)\n- ❌ Fewer advanced chart customizations\n\n### vs openpyxl\n- ✅ **27x faster** (1M rows: 2.06s vs 56.25s)\n- ✅ Dramatically lower memory usage\n- ✅ Native Arrow/Polars/Pandas support\n- ❌ Write-only (openpyxl supports reading)\n- ❌ Fewer cell-level features\n\n### vs polars.write_excel\n- ✅ **20x faster** (1M rows: 2.06s vs 40.85s)\n- ✅ **2000x lower memory** (~0 MB vs 2.1 GB at 1M rows)\n- ✅ More formatting options (conditional formatting, tables, charts)\n- ✅ Multi-sheet threading support\n- ❌ Requires `.to_arrow()` conversion\n\n### vs pandas.to_excel\n- ✅ **27-40x faster** depending on engine\n- ✅ Direct Polars support (no pandas dependency)\n- ✅ Richer formatting options\n- ✅ Multi-threading support\n- ✅ Dramatically lower memory footprint\n\n### vs rustpy_xlsxwriter\n- ✅ **5.5x faster** (1M rows: 2.06s vs 11.27s)\n- ✅ Native Arrow support (no data conversion needed)\n- ✅ More formatting options\n- ✅ Multi-threaded sheet generation\n\n\n## 📋 Supported Data Types\n\n### Arrow/Polars Types\n\n- Numeric: `Int8/16/32/64`, `UInt8/16/32/64`, `Float32/64`\n- String: `Utf8`, `LargeUtf8`\n- Boolean: `Bool`\n- Temporal: `Date32/64`, `Timestamp` (all units), `Time32/64`\n\n### Python Types (Dict API)\n\n- `str`, `int`, `float`, `bool`, `datetime`, `None`\n\n## 📚 External Resources \u0026 References\n\n### Official Microsoft Documentation\n\n**Excel Tables**\n- [Format an Excel Table](https://support.microsoft.com/en-us/office/format-an-excel-table-6789619f-c889-495c-99c2-2f971c0e2370) - Complete guide with visual examples of all table styles\n- [Overview of Excel Tables](https://support.microsoft.com/en-us/office/overview-of-excel-tables-7ab0bb7d-3a9e-4b56-a3c9-6c94334e492c) - Features and capabilities\n- [Using Structured References](https://support.microsoft.com/en-us/office/using-structured-references-with-excel-tables-f5ed2452-2337-4f71-bed3-c8ae6d2b276e) - Advanced table formulas\n\n**Excel Charts**\n- [Available Chart Types in Office](https://support.microsoft.com/en-us/office/available-chart-types-in-office-a6187218-807e-4103-9e0a-27cdb19afb90) - Complete reference for all chart types\n- [Create a Chart from Start to Finish](https://support.microsoft.com/en-us/office/create-a-chart-from-start-to-finish-0baf399e-dd61-4e18-8a73-b3fd5d5680c2) - Step-by-step guide\n\n**Number Formats**\n- [Excel Number Format Codes](https://support.microsoft.com/en-us/office/number-format-codes-5026bbd6-04bc-48cd-bf33-80f18b4eae68) - Complete reference for custom format codes\n- [Available Number Formats](https://support.microsoft.com/en-us/office/available-number-formats-in-excel-0afe8f52-97db-41f1-b972-4b46e9f1e8d2) - Built-in format options\n- [Custom Number Format Guidelines](https://support.microsoft.com/en-us/office/review-guidelines-for-customizing-a-number-format-c0a1d1fa-d3f4-4018-96b7-9c9354dd99f5) - Creating custom formats\n- [Create Custom Number Formats](https://support.microsoft.com/en-us/office/create-a-custom-number-format-78f2a361-936b-4c03-8772-09fab54be7f4) - Detailed tutorial\n\n### Color Resources\n\n**Understanding Excel Colors**\n- Excel uses **ARGB format** for colors: `AARRGGBB` where:\n  - `AA` = Alpha channel (transparency) - usually `FF` for fully opaque\n  - `RR` = Red component (00-FF in hexadecimal)\n  - `GG` = Green component (00-FF in hexadecimal)  \n  - `BB` = Blue component (00-FF in hexadecimal)\n\n**Example Colors**:\n```python\n\"FFFF0000\"  # Red (FF = opaque, FF0000 = red)\n\"FF00FF00\"  # Green (FF = opaque, 00FF00 = green)\n\"FF0000FF\"  # Blue (FF = opaque, 0000FF = blue)\n\"FFFFFF00\"  # Yellow (red + green)\n\"FFFF00FF\"  # Magenta (red + blue)\n\"FF00FFFF\"  # Cyan (green + blue)\n\"FF000000\"  # Black\n\"FFFFFFFF\"  # White\n```\n\n**Common Conditional Formatting Colors**:\n```python\n# Red-Yellow-Green color scale (default Excel)\n\"FFF8696B\"  # Red for low values\n\"FFFFEB84\"  # Yellow for middle values\n\"FF63BE7B\"  # Green for high values\n\n# Data bar colors\n\"FF638EC6\"  # Blue (Excel default data bar)\n\"FF5687C5\"  # Dark blue\n\"FFFF6347\"  # Tomato red\n```\n\n**Color Picker Tools**:\n- [RapidTables RGB Color Picker](https://www.rapidtables.com/web/color/RGB_Color.html) - Interactive color selection with RGB/hex codes\n- [W3Schools Color Picker](https://www.w3schools.com/colors/colors_picker.asp) - Simple online color chooser\n- [Microsoft RGB Function](https://support.microsoft.com/en-us/office/rgb-function-aa04db19-fb8a-4f58-9ad6-71a1f5a43e94) - Excel's RGB function documentation\n\n### Community Resources\n\n**Tutorials \u0026 Guides**\n- [ExcelJet Custom Number Formats](https://exceljet.net/articles/custom-number-formats) - Comprehensive formatting guide\n- [Ablebits Excel Tables Guide](https://www.ablebits.com/office-addins-blog/excel-tables-styles/) - Advanced table formatting\n- [W3Schools Excel Tutorial](https://www.w3schools.com/excel/) - Beginner-friendly Excel basics\n\n---\n\n\nMade with ❤️ and 🦀 by the Jetxl team\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fomarirfa%2Fjetxl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fomarirfa%2Fjetxl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fomarirfa%2Fjetxl/lists"}