Metadata-Version: 2.4
Name: pydfig
Version: 0.1.0
Summary: Self-describing scientific figures (Figure-as-Data): embed exact data in SVG/PNG, decode losslessly to JSON (for AI) and HTML (for humans).
Author-email: Fenglong Li <15340666394@163.com>, Siyang Li <15340666394@163.com>
License: MIT
Project-URL: Homepage, https://pydfig.ai4c/schema
Keywords: scientific figures,Figure-as-Data,FAIR data,machine-readable,AI4Science,SVG,PNG,metadata
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
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 :: Scientific/Engineering :: Visualization
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: matplotlib
Requires-Dist: matplotlib; extra == "matplotlib"
Dynamic: license-file

# pydfig — Make your scientific figures carry their own data

A normal chart is just a **picture**. **pydfig** makes the same chart also
**contain its exact numbers** — so a computer can read them back perfectly,
without guessing from pixels (no OCR, no digitizing error).

> One sentence: pydfig hides a small JSON with your exact data *inside* the
> image file. The picture still looks identical; a parser reads the JSON back
> losslessly.

## Why does this matter?

Scientific figures in papers and PDFs are images. If an AI agent — or a
colleague — wants the real data points, they usually have to scrape the PDF
or eyeball the pixels, and both lose precision. pydfig embeds the **exact
data** inside the figure file itself, invisibly.

## How it works

| Carrier | Where the data lives | Still a normal file? |
|---------|----------------------|----------------------|
| **SVG** | the standard `<metadata>` element (renderers ignore it) | ✅ opens in any SVG viewer |
| **PNG** | a legal private chunk called `dDat` | ✅ opens in any image viewer |

## Two things pydfig does

1. **Encode** — export a PNG or SVG that carries your exact data (from a
   `payload` dict, or directly from a matplotlib figure).
2. **Decode** — read a pydfig PNG/SVG and write out:
   - a **`.json`** file — machine-readable, for AI / data pipelines
   - an **`.html`** file — human-readable, opens in any browser and shows the
     data plus a reconstructed plot

## Install

```bash
pip install pydfig
# optional: to export directly from a matplotlib figure
pip install "pydfig[matplotlib]"
```

The core encode/decode path is **pure Python standard library** — no heavy
dependencies required.

## Quick start

### Command line

```bash
# Encode: inject a data JSON into an existing SVG or PNG
python -m pydfig encode chart.png --payload payload.json -o chart_pydfig.png

# Decode: get back JSON (for AI) + HTML (for humans)
python -m pydfig decode chart_pydfig.png -o result
#   result.json  <- exact data, machine-readable
#   result.html  <- open in a browser to see the data and a reconstructed chart
```

### In Python

```python
from pydfig import build_payload, embed_in_svg, inject_png_ddat, decode_any

payload = build_payload(
    "scatter",
    points=[{"x": -1.95, "y": 0.42, "material": "NiO"}],
    axes={"x": {"label": "d-band", "unit": "eV"}},
    caption="My figure",
)

svg = embed_in_svg(open("chart.svg").read(), payload)        # data in <metadata>
png = inject_png_ddat(open("chart.png", "rb").read(), payload)  # data in dDat chunk

data = decode_any("chart_pydfig.png")   # exact, lossless
```

### From a matplotlib figure (needs the `matplotlib` extra)

```python
import matplotlib.pyplot as plt
from pydfig.matplotlib_converter import convert

fig, ax = plt.subplots()
ax.plot([1, 2, 3], [4, 5, 6])
ax.set_xlabel("d-band (eV)")
ax.set_ylabel("E_ads (eV)")

convert(fig, "out.svg", caption="experiment")   # -> out.svg
convert(fig, "out.png", caption="experiment")   # -> out.png
```

`convert()` chooses PNG vs SVG automatically from the output file extension.

### Decode to a readable HTML page

```python
from pydfig import decode_any, write_html

payload = decode_any("out.png")
write_html(payload, "out.html")   # self-contained, light-theme viewer
```

## What the embedded data looks like

```json
{
  "format": "pydfig",
  "version": "2.0",
  "figure_type": "xrd",
  "caption": "XRD pattern",
  "axes": {"x": {"label": "2θ", "unit": "degree"}, "y": {"label": "Intensity"}},
  "points": [{"x": 44.0, "y": 20.0}, {"x": 64.0, "y": 12.0}],
  "curves": [{"x": [0, 1, 2], "y": [10, 12, 11], "label": "intensity"}]
}
```

## Examples

The `examples/` folder ships `demo_volcano`, `demo_xrd`, and `demo_dband` as
both `.svg` and `.png` — each carrying its exact data. Regenerate them with:

```bash
python examples/gen_examples.py
```

## License

MIT — see [LICENSE](LICENSE).
