diff --git a/README.md b/README.md index 00968b4..a13da98 100644 --- a/README.md +++ b/README.md @@ -2,19 +2,31 @@ A python library for identifying bubbles/droplets based on volume of fluid (VOF) simulation data. -For documentation, see [dgaylo.github.io/blobid-python](https://dgaylo.github.io/blobid-python). +# Installation -# Example +It is suggested to install the library with [Numba](https://numba.pydata.org/) enabled: +``` +pip install blobid[numba] +``` -![vof and label field](doc/example.svg) +# Documentation + +For the latest release: [dgaylo.github.io/blobid-python](https://dgaylo.github.io/blobid-python) -Here we use the following code to calculate the labels of the air bubbles in water near the surface, +# Example + +Here we load a 2D slice from a simulation of air bubbles in water near the surface, +and then use this library to identify and label all the air bubble. ```Python Console >>> import numpy as np >>> from blobid import get_labels >>> vof = 1.0 - np.load("tests/resources/fs_vof.npy")[:, 0, :] >>> labels = get_labels(vof, periodic=[True, False]) ``` -and then render the `vof` field and the `labels` field using Matplotlib (see [doc/example.py](doc/example.py)). -For illustration we use a 2D slice for the `vof` field, but the library supports 1D, 2D, or 3D. + +Below is a rendering of the `vof` field (air is white, water is black) and the `labels` field calculated using `get_labels()` + +![vof and label field](doc/example.svg) + +The full script, including creating these graphics using [Matplotlib](https://matplotlib.org/), is [doc/example.py](doc/example.py). diff --git a/doc/example.py b/doc/example.py index bf290a7..f5d3e9c 100644 --- a/doc/example.py +++ b/doc/example.py @@ -9,10 +9,17 @@ # make the plots import matplotlib.pyplot as plt +from matplotlib.colors import ListedColormap + +# create a nice coloring for the labels +base = plt.colormaps["tab20"] +colors = [base(i % base.N) for i in np.unique(labels)] +colors[0] = (0, 0, 0, 1) # unlabeled cells +labels_cmap = ListedColormap(colors) fig, ax = plt.subplots(nrows=2) ax[0].pcolormesh(1.0-vof.transpose(), cmap='binary', shading='gouraud', rasterized=True) -ax[1].pcolormesh(labels.transpose(), cmap='nipy_spectral', shading='nearest', rasterized=True) +ax[1].pcolormesh(labels.transpose(), cmap=labels_cmap, shading='nearest', rasterized=True) for a in ax: a.set_xticks([]) @@ -23,4 +30,4 @@ plt.rcParams['svg.hashsalt']="blobid-python" plt.subplots_adjust(hspace=0) -plt.savefig("doc/example.svg", transparent=True, bbox_inches='tight', pad_inches=0) +plt.savefig("doc/example.svg", transparent=True, bbox_inches='tight', pad_inches=0, metadata={'Date': None}) diff --git a/doc/example.svg b/doc/example.svg index f7a54c4..72f18f1 100644 --- a/doc/example.svg +++ b/doc/example.svg @@ -6,7 +6,6 @@ - 2025-07-11T18:31:46.689483 image/svg+xml @@ -75,7 +74,7 @@ z " style="fill: none"/> +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" id="imagedc9d6deb28" transform="scale(1 -1) translate(0 -89.28)" x="0" y="-132.48" width="357.12" height="89.28"/>