live-plotter


Namelive-plotter JSON
Version 4.1.0 PyPI version JSON
download
home_pagehttps://github.com/tylerlum/live_plotter
SummaryPlot live data that updates in real time using matplotlib backend
upload_time2024-09-21 17:08:13
maintainerNone
docs_urlNone
authorTyler Lum
requires_pythonNone
licenseNone
keywords python matplotlib plot live real time
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # live_plotter

Plot live data that updates in real time using matplotlib backend

# Installing

Install:

```
pip install live_plotter
```

# Usage

In this library, we have two axes of variation:

* The first axis of variation is using either `LivePlotter` or `LiveImagePlotter`. `LivePlotter` create line plots. `LiveImagePlotter` creates image plots.

* The second axis of variation is using either `LivePlotter` or `FastLivePlotter`. `LivePlotter` is more flexible and dynamic, but this results in slower updates. `FastLivePlotter` requires that the user specify the number of plots in the figure from the beginning, but this allows it to update faster by modifying an existing plot rather than creating a new plot from scratch.

Additionally, we have a wrapper `SeparateProcessLivePlotter` that takes in any of the above plotters and creates a separate process to update the plot. The above plotters run on the same process as the main process, but `SeparateProcessLivePlotter` is run on another process so there is much less performance overhead on the main process from plotting. Plotting takes time, so running the plotting code in the same process as the main process can significantly slow things down, especially as plots get larger. This must be done on a new process instead of a new thread because the GUI does not work on non-main threads.

Please refer to the associated example code for more details.

Options:

- `LivePlotter`

- `FastLivePlotter`

- `LiveImagePlotter`

- `FastLiveImagePlotter`

- `SeparateProcessLivePlotter`

TODO: Compare with https://igitugraz.github.io/live-plotter/liveplotter.html

## Live Plotter

![2023-11-23_16-55-40_live_plot](https://github.com/tylerlum/live_plotter/assets/26510814/5481f062-743a-40f9-8e1a-31a2d8dee24e)

## Fast Live Plotter

![2023-11-23_16-55-46_fast_live_plot](https://github.com/tylerlum/live_plotter/assets/26510814/133093bc-6503-470d-b531-ab1b7948f13a)

## Live Image Plotter

![2023-11-23_16-55-54_live_image_plot](https://github.com/tylerlum/live_plotter/assets/26510814/6051c114-d537-4e1a-8889-34bc0c067fe5)

## Example Usage of `LivePlotter`

```
import numpy as np
from live_plotter import LivePlotter

live_plotter = LivePlotter()
x_data = []
for i in range(25):
    x_data.append(i)
    live_plotter.plot(
        y_data_list=[np.sin(x_data), np.cos(x_data)],
        titles=["sin", "cos"],
    )
```

## Example Usage of `LivePlotter` (mult-line plot)

```
import numpy as np
from live_plotter import LivePlotter

live_plotter = LivePlotter()

new_x_data = []
for i in range(25):
    new_x_data.append(i)
    y_data = np.stack([np.sin(new_x_data), np.cos(new_x_data)], axis=1)
    live_plotter.plot(
        y_data_list=[y_data],
        titles=["sin and cos"],
        xlabels=["x"],
        ylabels=["y"],
        ylims=[(-2, 2)],
        legends=[["sin", "cos"]],
    )
```

## Example Usage of `FastLivePlotter`

```
import numpy as np
from live_plotter import FastLivePlotter

live_plotter = FastLivePlotter(titles=["sin", "cos"], n_plots=2, n_rows=2, n_cols=1)
x_data = []
for i in range(25):
    x_data.append(i)
    live_plotter.plot(
        y_data_list=[np.sin(x_data), np.cos(x_data)],
    )
```

## Example Usage of `FastLivePlotter` (multi-line plot)

```
import numpy as np

from live_plotter import FastLivePlotter

new_x_data = []
live_plotter = FastLivePlotter(
    n_plots=1,
    titles=["sin and cos"],
    xlabels=["x"],
    ylabels=["y"],
    ylims=[(-2, 2)],
    legends=[["sin", "cos"]],
)
for i in range(25):
    new_x_data.append(i)
    y_data = np.stack([np.sin(new_x_data), np.cos(new_x_data)], axis=1)
    live_plotter.plot(
        y_data_list=[y_data],
    )
```

## Example Usage of `FastLivePlotter` (complex example)

```
import numpy as np

from live_plotter import FastLivePlotter

y_data_dict = {
    "exp(-x/10)": [],
    "ln(x + 1)": [],
    "x^2": [],
    "4x^4": [],
    "ln(2^x)": [],
}
plot_names = list(y_data_dict.keys())
live_plotter = FastLivePlotter(
    titles=plot_names, n_plots=len(plot_names)
)
for i in range(25):
    y_data_dict["exp(-x/10)"].append(np.exp(-i / 10))
    y_data_dict["ln(x + 1)"].append(np.log(i + 1))
    y_data_dict["x^2"].append(np.power(i, 2))
    y_data_dict["4x^4"].append(4 * np.power(i, 4))
    y_data_dict["ln(2^x)"].append(np.log(np.power(2, i)))

    live_plotter.plot(
        y_data_list=[np.array(y_data_dict[plot_name]) for plot_name in plot_names],
    )
```

## Example Usage of `SeparateProcessLivePlotter` (recommended method to minimize plotting time impacting main code performance)

```
import numpy as np
import time

from live_plotter import SeparateProcessLivePlotter, FastLivePlotter

N_ITERS = 100
SIMULATED_COMPUTATION_TIME_S = 0.1
OPTIMAL_TIME_S = N_ITERS * SIMULATED_COMPUTATION_TIME_S

# Slower when plotting is on same process
live_plotter = FastLivePlotter(
    n_plots=2, titles=["sin", "cos"]
)
x_data = []
start_time_same_process = time.time()
for i in range(N_ITERS):
    x_data.append(i)
    time.sleep(SIMULATED_COMPUTATION_TIME_S)
    live_plotter.plot(
        y_data_list=[np.sin(x_data), np.cos(x_data)],
    )
time_taken_same_process = time.time() - start_time_same_process

# Faster when plotting is on separate process
live_plotter_separate_process = SeparateProcessLivePlotter(
    live_plotter=live_plotter, plot_names=["sin", "cos"]
)
live_plotter_separate_process.start()
start_time_separate_process = time.time()
for i in range(N_ITERS):
    time.sleep(SIMULATED_COMPUTATION_TIME_S)
    live_plotter_separate_process.data_dict["sin"].append(np.sin(i))
    live_plotter_separate_process.data_dict["cos"].append(np.cos(i))
    live_plotter_separate_process.update()
time_taken_separate_process = time.time() - start_time_separate_process

print(f"Time taken same process: {round(time_taken_same_process, 1)} s")
print(f"Time taken separate process: {round(time_taken_separate_process, 1)} s")
print(f"OPTIMAL_TIME_S: {round(OPTIMAL_TIME_S, 1)} s")

assert time_taken_separate_process < time_taken_same_process
```
Output:
```
Time taken same process: 19.0 s
Time taken separate process: 10.4 s
OPTIMAL_TIME_S: 10.0 s
```

Note how this runs much faster than the same process code

## Example Usage of `LiveImagePlotter`

Note:

* images must be (M, N) or (M, N, 3) or (M, N, 4)

* Typically images must either be floats in [0, 1] or ints in [0, 255]. If not in this range, we will automatically scale it and print a warning. We recommend using the scale_image function as shown below.

```
import numpy as np
from live_plotter import LiveImagePlotter, scale_image

N = 25
DEFAULT_IMAGE_HEIGHT = 100
DEFAULT_IMAGE_WIDTH = 100

live_plotter = LiveImagePlotter()

x_data = []
for i in range(N):
    x_data.append(0.5 * i)
    image_data = (
        np.sin(x_data)[None, ...]
        .repeat(DEFAULT_IMAGE_HEIGHT, 0)
        .repeat(DEFAULT_IMAGE_WIDTH // N, 1)
    )
    live_plotter.plot(image_data_list=[scale_image(image_data, min_val=-1.0, max_val=1.0)])
```

## Example Usage of `FastLiveImagePlotter`

```
import numpy as np
from live_plotter import FastLiveImagePlotter, scale_image

N = 25
DEFAULT_IMAGE_HEIGHT = 100
DEFAULT_IMAGE_WIDTH = 100

live_plotter = FastLiveImagePlotter(
    titles=["sin", "cos"], n_plots=2, n_rows=2, n_cols=1
)
x_data = []
for i in range(N):
    x_data.append(i)
    image_data_1 = (
        np.sin(x_data)[None, ...]
        .repeat(DEFAULT_IMAGE_HEIGHT, 0)
        .repeat(DEFAULT_IMAGE_WIDTH // N, 1)
    )
    image_data_2 = (
        np.cos(x_data)[None, ...]
        .repeat(DEFAULT_IMAGE_HEIGHT, 0)
        .repeat(DEFAULT_IMAGE_WIDTH // N, 1)
    )
    live_plotter.plot(
        image_data_list=[
            scale_image(image_data_1, min_val=-1.0, max_val=1.0),
            scale_image(image_data_2),
        ],
    )
```


            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/tylerlum/live_plotter",
    "name": "live-plotter",
    "maintainer": null,
    "docs_url": null,
    "requires_python": null,
    "maintainer_email": null,
    "keywords": "python, matplotlib, plot, live, real time",
    "author": "Tyler Lum",
    "author_email": "tylergwlum@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/88/98/4595aeab97b38a2e28c78b4e1ad142d2dcb48725430addc47018d04e5829/live_plotter-4.1.0.tar.gz",
    "platform": null,
    "description": "# live_plotter\n\nPlot live data that updates in real time using matplotlib backend\n\n# Installing\n\nInstall:\n\n```\npip install live_plotter\n```\n\n# Usage\n\nIn this library, we have two axes of variation:\n\n* The first axis of variation is using either `LivePlotter` or `LiveImagePlotter`. `LivePlotter` create line plots. `LiveImagePlotter` creates image plots.\n\n* The second axis of variation is using either `LivePlotter` or `FastLivePlotter`. `LivePlotter` is more flexible and dynamic, but this results in slower updates. `FastLivePlotter` requires that the user specify the number of plots in the figure from the beginning, but this allows it to update faster by modifying an existing plot rather than creating a new plot from scratch.\n\nAdditionally, we have a wrapper `SeparateProcessLivePlotter` that takes in any of the above plotters and creates a separate process to update the plot. The above plotters run on the same process as the main process, but `SeparateProcessLivePlotter` is run on another process so there is much less performance overhead on the main process from plotting. Plotting takes time, so running the plotting code in the same process as the main process can significantly slow things down, especially as plots get larger. This must be done on a new process instead of a new thread because the GUI does not work on non-main threads.\n\nPlease refer to the associated example code for more details.\n\nOptions:\n\n- `LivePlotter`\n\n- `FastLivePlotter`\n\n- `LiveImagePlotter`\n\n- `FastLiveImagePlotter`\n\n- `SeparateProcessLivePlotter`\n\nTODO: Compare with https://igitugraz.github.io/live-plotter/liveplotter.html\n\n## Live Plotter\n\n![2023-11-23_16-55-40_live_plot](https://github.com/tylerlum/live_plotter/assets/26510814/5481f062-743a-40f9-8e1a-31a2d8dee24e)\n\n## Fast Live Plotter\n\n![2023-11-23_16-55-46_fast_live_plot](https://github.com/tylerlum/live_plotter/assets/26510814/133093bc-6503-470d-b531-ab1b7948f13a)\n\n## Live Image Plotter\n\n![2023-11-23_16-55-54_live_image_plot](https://github.com/tylerlum/live_plotter/assets/26510814/6051c114-d537-4e1a-8889-34bc0c067fe5)\n\n## Example Usage of `LivePlotter`\n\n```\nimport numpy as np\nfrom live_plotter import LivePlotter\n\nlive_plotter = LivePlotter()\nx_data = []\nfor i in range(25):\n    x_data.append(i)\n    live_plotter.plot(\n        y_data_list=[np.sin(x_data), np.cos(x_data)],\n        titles=[\"sin\", \"cos\"],\n    )\n```\n\n## Example Usage of `LivePlotter` (mult-line plot)\n\n```\nimport numpy as np\nfrom live_plotter import LivePlotter\n\nlive_plotter = LivePlotter()\n\nnew_x_data = []\nfor i in range(25):\n    new_x_data.append(i)\n    y_data = np.stack([np.sin(new_x_data), np.cos(new_x_data)], axis=1)\n    live_plotter.plot(\n        y_data_list=[y_data],\n        titles=[\"sin and cos\"],\n        xlabels=[\"x\"],\n        ylabels=[\"y\"],\n        ylims=[(-2, 2)],\n        legends=[[\"sin\", \"cos\"]],\n    )\n```\n\n## Example Usage of `FastLivePlotter`\n\n```\nimport numpy as np\nfrom live_plotter import FastLivePlotter\n\nlive_plotter = FastLivePlotter(titles=[\"sin\", \"cos\"], n_plots=2, n_rows=2, n_cols=1)\nx_data = []\nfor i in range(25):\n    x_data.append(i)\n    live_plotter.plot(\n        y_data_list=[np.sin(x_data), np.cos(x_data)],\n    )\n```\n\n## Example Usage of `FastLivePlotter` (multi-line plot)\n\n```\nimport numpy as np\n\nfrom live_plotter import FastLivePlotter\n\nnew_x_data = []\nlive_plotter = FastLivePlotter(\n    n_plots=1,\n    titles=[\"sin and cos\"],\n    xlabels=[\"x\"],\n    ylabels=[\"y\"],\n    ylims=[(-2, 2)],\n    legends=[[\"sin\", \"cos\"]],\n)\nfor i in range(25):\n    new_x_data.append(i)\n    y_data = np.stack([np.sin(new_x_data), np.cos(new_x_data)], axis=1)\n    live_plotter.plot(\n        y_data_list=[y_data],\n    )\n```\n\n## Example Usage of `FastLivePlotter` (complex example)\n\n```\nimport numpy as np\n\nfrom live_plotter import FastLivePlotter\n\ny_data_dict = {\n    \"exp(-x/10)\": [],\n    \"ln(x + 1)\": [],\n    \"x^2\": [],\n    \"4x^4\": [],\n    \"ln(2^x)\": [],\n}\nplot_names = list(y_data_dict.keys())\nlive_plotter = FastLivePlotter(\n    titles=plot_names, n_plots=len(plot_names)\n)\nfor i in range(25):\n    y_data_dict[\"exp(-x/10)\"].append(np.exp(-i / 10))\n    y_data_dict[\"ln(x + 1)\"].append(np.log(i + 1))\n    y_data_dict[\"x^2\"].append(np.power(i, 2))\n    y_data_dict[\"4x^4\"].append(4 * np.power(i, 4))\n    y_data_dict[\"ln(2^x)\"].append(np.log(np.power(2, i)))\n\n    live_plotter.plot(\n        y_data_list=[np.array(y_data_dict[plot_name]) for plot_name in plot_names],\n    )\n```\n\n## Example Usage of `SeparateProcessLivePlotter` (recommended method to minimize plotting time impacting main code performance)\n\n```\nimport numpy as np\nimport time\n\nfrom live_plotter import SeparateProcessLivePlotter, FastLivePlotter\n\nN_ITERS = 100\nSIMULATED_COMPUTATION_TIME_S = 0.1\nOPTIMAL_TIME_S = N_ITERS * SIMULATED_COMPUTATION_TIME_S\n\n# Slower when plotting is on same process\nlive_plotter = FastLivePlotter(\n    n_plots=2, titles=[\"sin\", \"cos\"]\n)\nx_data = []\nstart_time_same_process = time.time()\nfor i in range(N_ITERS):\n    x_data.append(i)\n    time.sleep(SIMULATED_COMPUTATION_TIME_S)\n    live_plotter.plot(\n        y_data_list=[np.sin(x_data), np.cos(x_data)],\n    )\ntime_taken_same_process = time.time() - start_time_same_process\n\n# Faster when plotting is on separate process\nlive_plotter_separate_process = SeparateProcessLivePlotter(\n    live_plotter=live_plotter, plot_names=[\"sin\", \"cos\"]\n)\nlive_plotter_separate_process.start()\nstart_time_separate_process = time.time()\nfor i in range(N_ITERS):\n    time.sleep(SIMULATED_COMPUTATION_TIME_S)\n    live_plotter_separate_process.data_dict[\"sin\"].append(np.sin(i))\n    live_plotter_separate_process.data_dict[\"cos\"].append(np.cos(i))\n    live_plotter_separate_process.update()\ntime_taken_separate_process = time.time() - start_time_separate_process\n\nprint(f\"Time taken same process: {round(time_taken_same_process, 1)} s\")\nprint(f\"Time taken separate process: {round(time_taken_separate_process, 1)} s\")\nprint(f\"OPTIMAL_TIME_S: {round(OPTIMAL_TIME_S, 1)} s\")\n\nassert time_taken_separate_process < time_taken_same_process\n```\nOutput:\n```\nTime taken same process: 19.0 s\nTime taken separate process: 10.4 s\nOPTIMAL_TIME_S: 10.0 s\n```\n\nNote how this runs much faster than the same process code\n\n## Example Usage of `LiveImagePlotter`\n\nNote:\n\n* images must be (M, N) or (M, N, 3) or (M, N, 4)\n\n* Typically images must either be floats in [0, 1] or ints in [0, 255]. If not in this range, we will automatically scale it and print a warning. We recommend using the scale_image function as shown below.\n\n```\nimport numpy as np\nfrom live_plotter import LiveImagePlotter, scale_image\n\nN = 25\nDEFAULT_IMAGE_HEIGHT = 100\nDEFAULT_IMAGE_WIDTH = 100\n\nlive_plotter = LiveImagePlotter()\n\nx_data = []\nfor i in range(N):\n    x_data.append(0.5 * i)\n    image_data = (\n        np.sin(x_data)[None, ...]\n        .repeat(DEFAULT_IMAGE_HEIGHT, 0)\n        .repeat(DEFAULT_IMAGE_WIDTH // N, 1)\n    )\n    live_plotter.plot(image_data_list=[scale_image(image_data, min_val=-1.0, max_val=1.0)])\n```\n\n## Example Usage of `FastLiveImagePlotter`\n\n```\nimport numpy as np\nfrom live_plotter import FastLiveImagePlotter, scale_image\n\nN = 25\nDEFAULT_IMAGE_HEIGHT = 100\nDEFAULT_IMAGE_WIDTH = 100\n\nlive_plotter = FastLiveImagePlotter(\n    titles=[\"sin\", \"cos\"], n_plots=2, n_rows=2, n_cols=1\n)\nx_data = []\nfor i in range(N):\n    x_data.append(i)\n    image_data_1 = (\n        np.sin(x_data)[None, ...]\n        .repeat(DEFAULT_IMAGE_HEIGHT, 0)\n        .repeat(DEFAULT_IMAGE_WIDTH // N, 1)\n    )\n    image_data_2 = (\n        np.cos(x_data)[None, ...]\n        .repeat(DEFAULT_IMAGE_HEIGHT, 0)\n        .repeat(DEFAULT_IMAGE_WIDTH // N, 1)\n    )\n    live_plotter.plot(\n        image_data_list=[\n            scale_image(image_data_1, min_val=-1.0, max_val=1.0),\n            scale_image(image_data_2),\n        ],\n    )\n```\n\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "Plot live data that updates in real time using matplotlib backend",
    "version": "4.1.0",
    "project_urls": {
        "Homepage": "https://github.com/tylerlum/live_plotter"
    },
    "split_keywords": [
        "python",
        " matplotlib",
        " plot",
        " live",
        " real time"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "9f04b89f42b784e97942233c379035f34c2b9d6d0cab870601160e12ca79433c",
                "md5": "1d420780df60f82f242cf3632bc68bd8",
                "sha256": "2c39c22ba809155fcb20191e7ebec66801817ce1b84225d3ae4b1e4ddf802b8f"
            },
            "downloads": -1,
            "filename": "live_plotter-4.1.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "1d420780df60f82f242cf3632bc68bd8",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": null,
            "size": 24410,
            "upload_time": "2024-09-21T17:08:10",
            "upload_time_iso_8601": "2024-09-21T17:08:10.888073Z",
            "url": "https://files.pythonhosted.org/packages/9f/04/b89f42b784e97942233c379035f34c2b9d6d0cab870601160e12ca79433c/live_plotter-4.1.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "88984595aeab97b38a2e28c78b4e1ad142d2dcb48725430addc47018d04e5829",
                "md5": "c051e5d859149c8fb3531db14b715d23",
                "sha256": "46a8c1c722975f5f891516fcc163e884abecc27251d8d92d995c9a6fed79a0dd"
            },
            "downloads": -1,
            "filename": "live_plotter-4.1.0.tar.gz",
            "has_sig": false,
            "md5_digest": "c051e5d859149c8fb3531db14b715d23",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 11645,
            "upload_time": "2024-09-21T17:08:13",
            "upload_time_iso_8601": "2024-09-21T17:08:13.606129Z",
            "url": "https://files.pythonhosted.org/packages/88/98/4595aeab97b38a2e28c78b4e1ad142d2dcb48725430addc47018d04e5829/live_plotter-4.1.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-09-21 17:08:13",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "tylerlum",
    "github_project": "live_plotter",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "live-plotter"
}
        
Elapsed time: 0.56068s