Metadata-Version: 2.4
Name: yorillow
Version: 1.0.1
Summary: Zero-dependency Python chart renderer — works offline, in APIs, and in serverless functions
Author: yorillow contributors
License: MIT
Project-URL: Homepage, https://github.com/harshi79/yorillow
Project-URL: Repository, https://github.com/harshi79/yorillow
Project-URL: Issues, https://github.com/harshi79/yorillow/issues
Keywords: charts,plotting,lightweight,png,svg,serverless,api
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Multimedia :: Graphics
Classifier: Framework :: Flask
Classifier: Framework :: FastAPI
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Dynamic: license-file

# Yorillow

**Lightweight, zero-dependency Python chart renderer that generates PNG and SVG charts entirely in Python.**

Runs offline, inside Python applications, behind APIs, in Docker, on VPS servers, or in serverless environments.

```python
from yorillow import render

png = render({
    "type": "line",
    "x": [1, 2, 3, 4],
    "y": [[10, 20, 15, 30]],
    "title": "Sales",
})

with open("sales.png", "wb") as f:
    f.write(png)
```

No Pillow. No NumPy. No matplotlib. No Chromium. No Node.js. No browser. No database.

---

## Why Yorillow?

| | Yorillow | matplotlib | Chart.js |
|---|---|---|---|
| Runtime dependencies | **0** | numpy, Pillow, … | Node/browser |
| Returns | **bytes directly** | figure objects | HTML/JS |
| Serverless | **native** | requires setup | needs browser |
| Import time | **~27 ms** | seconds | N/A |
| Memory (800×600) | **~1.8 MiB** | ~50 MiB | N/A |

---

## Installation

```bash
python -m pip install yorillow
```

Then:

```python
from yorillow import render
```

**Package name:** `yorillow` (PyPI) / **Import name:** `yorillow` (Python)

---

## Quick Start

### Render to bytes

```python
from yorillow import render

png = render(config, format="png")   # bytes
svg = render(config, format="svg")   # str
```

### Save to file

```python
from yorillow import render_to_file

render_to_file(config, "chart.png")
render_to_file(config, "chart.svg")
```

### HTTP response helper

```python
from yorillow import render_response

resp = render_response(config, format="png")
# resp["status_code"]  → 200
# resp["content_type"] → "image/png"
# resp["body"]         → bytes
```

---

## Offline Usage

After installation, rendering requires **no internet, no API key, no external service**.

```python
from yorillow import render

png = render({"type": "line", "x": [1, 2, 3], "y": [[10, 20, 30]]})
```

### Completely offline installation

On an internet-connected machine:

```bash
python -m pip download yorillow
```

Transfer the downloaded file to the offline machine, then:

```bash
python -m pip install --no-index --find-links . yorillow
```

Since yorillow has zero runtime dependencies, only the yorillow package itself needs to be transferred.

---

## Chart Types

### Line

```python
render({
    "type": "line",
    "x": [1, 2, 3, 4, 5],
    "y": [[10, 20, 15, 25, 30], [5, 15, 10, 20, 25]],
    "labels": ["Revenue", "Profit"],
    "title": "Monthly Performance",
    "legend": True,
    "fill": True,
})
```

### Bar

```python
render({
    "type": "bar",
    "categories": ["Q1", "Q2", "Q3", "Q4"],
    "values": [[120, 150, 170, 200], [90, 130, 140, 180]],
    "labels": ["Product A", "Product B"],
    "stacked": False,
})
```

### Scatter

```python
render({
    "type": "scatter",
    "x": [1.0, 2.5, 3.7, 4.2, 5.8],
    "y": [10.0, 20.5, 15.3, 25.1, 30.0],
    "sizes": [5, 8, 6, 10, 4],
})
```

### Pie / Donut

```python
render({
    "type": "pie",
    "values": [35, 25, 20, 12, 8],
    "labels": ["Chrome", "Firefox", "Safari", "Edge", "Other"],
    "donut": True,
})
```

### Area

```python
render({
    "type": "area",
    "x": [1, 2, 3, 4, 5],
    "y": [[10, 20, 15, 25, 30], [5, 10, 8, 12, 15]],
    "labels": ["Downloads", "Installs"],
    "stacked": True,
})
```

### Histogram

```python
render({
    "type": "histogram",
    "data": [12.5, 14.2, 15.0, 15.8, 16.1, 17.2, 18.0, 19.1, 20.5, 22.4, 25.0],
    "bins": 6,
    "title": "Latency Distribution (ms)",
})
```

### Heatmap

```python
render({
    "type": "heatmap",
    "values": [
        [22.4, 25.1, 28.3, 30.2],
        [18.2, 21.0, 24.5, 27.8],
        [15.1, 17.5, 20.2, 22.9],
    ],
    "x_labels": ["Q1", "Q2", "Q3", "Q4"],
    "y_labels": ["North", "Central", "South"],
    "color_scale": "viridis",
    "show_values": True,
    "title": "Regional Temperature Matrix",
})
```

### Box Plot

```python
render({
    "type": "box_plot",
    "data": [
        [15, 18, 20, 22, 23, 24, 25, 27, 29, 32, 45],
        [10, 14, 16, 17, 19, 20, 21, 22, 24, 26, 28],
    ],
    "categories": ["Algorithm A", "Algorithm B"],
    "show_outliers": True,
    "title": "Execution Time (ms)",
})
```

### Candlestick

```python
render({
    "type": "candlestick",
    "open": [150.0, 153.2, 151.8, 156.4],
    "high": [155.0, 156.0, 158.5, 161.0],
    "low": [148.5, 150.1, 150.0, 153.8],
    "close": [153.2, 151.8, 156.4, 154.0],
    "dates": ["Mon", "Tue", "Wed", "Thu"],
    "title": "Daily Price Action",
})
```

### Radar / Spider

```python
render({
    "type": "radar",
    "categories": ["Attack", "Defense", "Speed", "Tactics", "Stamina"],
    "values": [
        [88, 72, 94, 85, 90],
        [75, 92, 78, 88, 82],
    ],
    "labels": ["Player Alpha", "Player Beta"],
    "fill": True,
    "legend": True,
    "title": "Skill Radar",
})
```

### Step

```python
render({
    "type": "step",
    "x": [0, 1, 2, 3, 4, 5, 6, 7],
    "y": [[0, 1, 1, 2, 3, 5, 8, 13]],
    "step_where": "post",
    "fill": True,
    "title": "State Progression",
})
```

---

## Themes

Built-in: `default`, `dark`, `minimal`, `neon`

```python
render({**config, "theme": "dark"})
```

---

## JSON Configuration

Chart configurations are plain JSON — no Python objects required.

```json
{
    "type": "line",
    "x": [1, 2, 3, 4],
    "y": [[10, 20, 15, 30]],
    "title": "Sales"
}
```

```python
import json
from yorillow import render

with open("chart.json") as f:
    config = json.load(f)

png = render(config)
```

This makes Yorillow useful when configuration comes from another program, a database, an API, or another language.

---

## CLI

```bash
yorillow chart.json -o chart.png          # render PNG
yorillow chart.json -o chart.svg          # render SVG
cat chart.json | yorillow -o chart.png    # stdin
yorillow chart.json --base64              # JSON with base64 data
yorillow chart.json --validate-only       # validate only
yorillow chart.json -o out.png --bench    # show timing
yorillow --version
yorillow --help
```

PowerShell:

```powershell
Get-Content chart.json -Raw | yorillow -o chart.png
```

---

## Build an API

Yorillow is the renderer, not the server.

```
Client → JSON → HTTP Server → yorillow.render() → PNG/SVG → HTTP Response
```

### stdlib (zero dependencies)

```bash
python examples/api/simple_http_server.py
```

```bash
curl -X POST http://localhost:8080/chart \
  -H "Content-Type: application/json" \
  -d '{"type":"line","x":[1,2,3],"y":[[10,20,30]]}' \
  --output chart.png
```

### Flask

```bash
pip install flask yorillow
python examples/api/flask_app.py
```

### FastAPI

```bash
pip install fastapi uvicorn yorillow
python -m uvicorn examples.api.fastapi_app:app
```

---

## Deploy

| Environment | Guide | Status |
|---|---|---|
| Local Python | [Offline Usage](#offline-usage) | ✓ Tested |
| CLI | [CLI](#cli) | ✓ Tested |
| VPS | [docs/deployment/vps.md](docs/deployment/vps.md) | ✓ Tested |
| Docker | [docs/deployment/docker.md](docs/deployment/docker.md) | ✓ Tested |
| Flask | [examples/api/flask_app.py](examples/api/flask_app.py) | Example |
| FastAPI | [examples/api/fastapi_app.py](examples/api/fastapi_app.py) | Example |
| Render | [docs/deployment/render.md](docs/deployment/render.md) | Example |
| Railway | [docs/deployment/railway.md](docs/deployment/railway.md) | Example |
| Vercel | [docs/deployment/vercel.md](docs/deployment/vercel.md) | Example |
| Netlify | [docs/deployment/netlify.md](docs/deployment/netlify.md) | Example |
| AWS Lambda | [docs/deployment/aws-lambda.md](docs/deployment/aws-lambda.md) | Example |

---

## Serverless Architecture

The core renderer is stateless and dependency-free, making it suitable for Python-compatible serverless runtimes.

```
Request → render() → PNG/SVG → Response
```

No persistent process. No database. No filesystem. No browser.

See [docs/architecture/serverless.md](docs/architecture/serverless.md).

---

## Performance

| Metric | Value |
|---|---|
| Import | ~27 ms |
| PNG 800×600 | ~15–60 ms |
| SVG 800×600 | <0.4 ms |
| PNG 1920×1080 | ~60 ms |
| Canvas 800×600 | 1.8 MiB |

Run `python benchmarks/bench.py` to reproduce.

See [docs/performance.md](docs/performance.md).

---

## Security

Yorillow validates all inputs: max dimensions, data point limits, NaN/Infinity rejection, type checking.

When exposing publicly, add authentication, rate limiting, and request size limits at the HTTP layer.

See [docs/security.md](docs/security.md).

---

## API Reference

| Function | Returns | Description |
|---|---|---|
| `render(config, format, encoding)` | `bytes`/`str` | Stateless chart renderer |
| `render_to_file(config, path)` | `None` | Render and save to file |
| `render_response(config, format)` | `dict` | HTTP response helper |

| Class | Description |
|---|---|
| `Canvas` | Low-level drawing surface |
| `LineChart` | Line chart |
| `BarChart` | Bar chart |
| `ScatterChart` | Scatter plot |
| `PieChart` | Pie / donut chart |
| `AreaChart` | Area chart |
| `HistogramChart` (`Histogram`) | Histogram chart |
| `HeatmapChart` (`Heatmap`) | Heatmap matrix |
| `BoxPlotChart` (`BoxPlot`) | Box plot (whisker plot) |
| `CandlestickChart` (`Candlestick`) | Candlestick OHLC chart |
| `RadarChart` (`Radar`, `SpiderChart`) | Radar / spider chart |
| `StepChart` (`Step`) | Step-wise line chart |

| Exception | Description |
|---|---|
| `YorillowError` | Base exception |
| `ValidationError` | Invalid input |
| `RenderError` | Internal error |

Full reference: [docs/api/](docs/api/)

---

## Examples

| Example | Description |
|---|---|
| [examples/python/basic_png.py](examples/python/basic_png.py) | Basic PNG |
| [examples/python/basic_svg.py](examples/python/basic_svg.py) | Basic SVG |
| [examples/python/multiple_series.py](examples/python/multiple_series.py) | Multiple series |
| [examples/python/histogram_example.py](examples/python/histogram_example.py) | Histogram chart |
| [examples/python/heatmap_example.py](examples/python/heatmap_example.py) | Heatmap matrix |
| [examples/python/box_plot_example.py](examples/python/box_plot_example.py) | Box plot |
| [examples/python/candlestick_example.py](examples/python/candlestick_example.py) | Candlestick OHLC |
| [examples/python/radar_example.py](examples/python/radar_example.py) | Radar / spider chart |
| [examples/python/step_example.py](examples/python/step_example.py) | Step chart |
| [examples/python/themes.py](examples/python/themes.py) | Theme demo |
| [examples/python/save_to_file.py](examples/python/save_to_file.py) | Save to file |
| [examples/python/json_config.py](examples/python/json_config.py) | JSON config |
| [examples/demo.py](examples/demo.py) | Full gallery generation |
| [examples/api/simple_http_server.py](examples/api/simple_http_server.py) | stdlib HTTP API |
| [examples/api/flask_app.py](examples/api/flask_app.py) | Flask API |
| [examples/api/fastapi_app.py](examples/api/fastapi_app.py) | FastAPI API |
| [examples/client/remote_client.py](examples/client/remote_client.py) | Python HTTP client |
| [examples/serverless/](examples/serverless/) | Serverless handlers |
| [examples/docker/](examples/docker/) | Docker |

---

## Development

```bash
git clone https://github.com/harshi79/yorillow.git
cd yorillow
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
python -m pytest tests/ -v
```

See [CONTRIBUTING.md](CONTRIBUTING.md).

---

## License

[MIT](LICENSE)
