streamjoy 0.0.10
Enjoy animating images into GIFs and MP4s!
Requires Python: >=3.9

# 🌈 StreamJoy 😊

---

[![build](https://github.com/ahuang11/streamjoy/workflows/Build/badge.svg)](https://github.com/ahuang11/streamjoy/actions) [![codecov](https://codecov.io/gh/ahuang11/streamjoy/branch/master/graph/badge.svg)](https://codecov.io/gh/ahuang11/streamjoy) [![PyPI version](https://badge.fury.io/py/streamjoy.svg)](https://badge.fury.io/py/streamjoy)

[![Downloads](https://pepy.tech/badge/streamjoy)](https://pepy.tech/project/streamjoy) [![GitHub stars](https://img.shields.io/github/stars/ahuang11/streamjoy?style=flat-square)](https://img.shields.io/github/stars/ahuang11/streamjoy?style=flat-square)

---

## 🔥 Enjoy animating!

Streamjoy turns your images into animations using sensible defaults for fun, hassle-free creation.

It cuts down the boilerplate and time to work on animations, and it's simple to start with just a few lines of code.

Install it with just pip to start, blazingly fast!

```python
pip install streamjoy
```

<img src="https://github.com/ahuang11/streamjoy/assets/15331990/7c5db7fe-498d-4282-b082-d7f8b36eb915" width="500">

Or, try out a basic web app version here:

https://huggingface.co/spaces/ahuang11/streamjoy

<img src="https://github.com/ahuang11/streamjoy/assets/15331990/b2e62e5a-b6ba-48a5-863f-6a8c5d4c2887" width="500">

## 🛠️ Built-in features

- 🌐 Animate from URLs, files, and datasets
- 🎨 Render images with default or custom renderers
- 🎬 Provide context with a short intro splash
- ⏸ Add pauses at the beginning, end, or between frames
- ⚡ Execute read, render, and write in parallel
- 🔗 Connect multiple animations together

## 🚀 Quick start

### 🐤 Absolute basics

Stream from a list of images--local files work too!

```python
from streamjoy import stream

if __name__ == "__main__":
    URL_FMT = "https://www.goes.noaa.gov/dimg/jma/fd/vis/{i}.gif"
    resources = [URL_FMT.format(i=i) for i in range(1, 11)]
    stream(resources, uri="goes.gif")  # .gif, .mp4, and .html supported
```

<img src="https://github.com/ahuang11/streamjoy/assets/15331990/190ab753-00cf-4a0d-b8be-8a0b9b9e4443" width="500" height="500">

### 💅 Polish up

Specify a few more keywords to:

1. add an intro title and subtitle
2. adjust the pauses
3. optimize the GIF thru pygifsicle

```python
from streamjoy import stream

if __name__ == "__main__":
    URL_FMT = "https://www.goes.noaa.gov/dimg/jma/fd/vis/{i}.gif"
    resources = [URL_FMT.format(i=i) for i in range(1, 11)]
    himawari_stream = stream(
        resources,
        uri="goes_custom.gif",
        intro_title="Himawari Visible",
        intro_subtitle="10 Hours Loop",
        intro_pause=1,
        ending_pause=1,
        optimize=True,
    )
```

<img src="https://github.com/ahuang11/streamjoy/assets/15331990/f69eb289-8074-4b49-9d9e-26f2c47c1a51" width="500" height="500">

### 👀 Preview inputs

If you'd like to preview the `repr` before writing, drop `uri`.

Output:
```yaml
<AnyStream>
---
Output:
  max_frames: 50
  fps: 10
  display: True
  scratch_dir: streamjoy_scratch
  in_memory: False
---
Intro:
  intro_title: Himawari Visible
  intro_subtitle: 10 Hours Loop
  intro_watermark: made with streamjoy
  intro_pause: 1
  intro_background: black
---
Client:
  batch_size: 10
  processes: True
  threads_per_worker: None
---
Resources: (10 frames to stream)
  https://www.goes.noaa.gov/dimg/jma/fd/vis/1.gif
  ...
  https://www.goes.noaa.gov/dimg/jma/fd/vis/10.gif
---
```

Then, when ready, call the `write` method to save the animation!

```python
himawari_stream.write()
```

### 🖇️ Connect streams

Connect multiple streams together to provide further context.

```python
from streamjoy import stream, connect

URL_FMTS = {
    "visible": "https://www.goes.noaa.gov/dimg/jma/fd/vis/{i}.gif",
    "infrared": "https://www.goes.noaa.gov/dimg/jma/fd/rbtop/{i}.gif",
}

if __name__ == "__main__":
    visible_stream = stream(
        [URL_FMTS["visible"].format(i=i) for i in range(1, 11)],
        intro_title="Himawari Visible",
        intro_subtitle="10 Hours Loop",
    )
    infrared_stream = stream(
        [URL_FMTS["infrared"].format(i=i) for i in range(1, 11)],
        intro_title="Himawari Infrared",
        intro_subtitle="10 Hours Loop",
    )
    connect([visible_stream, infrared_stream], uri="goes_connected.gif")
```

<img src="https://github.com/ahuang11/streamjoy/assets/15331990/5f6e0435-f2c2-4c3e-bcf9-4c84d4d060e9" width="500" height="500">

### 📷 Render datasets

You can also render images directly from datasets, either through a custom renderer or a built-in one, and they'll also run in parallel!

The following example requires xarray, cartopy, matplotlib, and netcdf4.

```bash
pip install xarray cartopy matplotlib netcdf4
```

```python
import numpy as np
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
from streamjoy import stream, wrap_matplotlib

@wrap_matplotlib()
def plot(da, central_longitude, **plot_kwargs):
    time = da["time"].dt.strftime("%b %d %Y").values.item()
    projection = ccrs.Orthographic(central_longitude=central_longitude)
    subplot_kw = dict(projection=projection, facecolor="gray")
    fig, ax = plt.subplots(figsize=(6, 6), subplot_kw=subplot_kw)
    im = da.plot(ax=ax, transform=ccrs.PlateCarree(), add_colorbar=False, **plot_kwargs)
    ax.set_title(f"Sea Surface Temperature Anomaly\n{time}", loc="left", transform=ax.transAxes)
    ax.set_title("Source: NOAA OISST v2.1", loc="right", size=5, y=-0.01)
    ax.set_title("", loc="center")  # suppress default title
    plt.colorbar(im, ax=ax, label="°C", shrink=0.8)
    return fig

if __name__ == "__main__":
    url = (
      "https://www.ncei.noaa.gov/data/sea-surface-temperature-"
      "optimum-interpolation/v2.1/access/avhrr/201008/"
    )
    pattern = "oisst-avhrr-v02r01.*.nc"
    stream(
        url,
        uri="oisst.gif",
        pattern=pattern,  # GifStream.from_url kwargs
        max_files=30,
        renderer=plot,  # renderer related kwargs
        renderer_iterables=[np.linspace(-140, -150, 30)],  # iterables; central longitude per frame (30 frames)
        renderer_kwargs=dict(cmap="RdBu_r", vmin=-5, vmax=5),  # renderer kwargs
        # cmap="RdBu_r", # renderer_kwargs can also be propagated for convenience
        # vmin=-5,
        # vmax=5,
    )
```

<img src="https://github.com/ahuang11/streamjoy/assets/15331990/3db0ae48-d7d5-4e00-a4a4-50bbe4bb3d19" width="500" height="500">

Check out all the supported formats [here](https://ahuang11.github.io/streamjoy/supported_formats/) or best practices [here](https://ahuang11.github.io/streamjoy/best_practices/). (Or maybe you're interested in the design--[here](https://ahuang11.github.io/streamjoy/package_design/))

---

❤️ Made with considerable passion.

🌟 Appreciate the project? Consider giving a star!