Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation of ImageStack #5751

Merged
merged 44 commits into from
Sep 14, 2023
Merged
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
5d17862
Add notes about ImageStack
hoxbro Jun 7, 2023
31f9cc7
Simple working example
hoxbro Jun 9, 2023
e97f9f5
clean up
hoxbro Jun 9, 2023
8de6530
Improve ImageStack plot handling
philippjfr Aug 23, 2023
9fc878d
Return ImageStack for categorical datashader aggregates
philippjfr Aug 23, 2023
c227f2c
Define ImageStack.group
philippjfr Aug 28, 2023
19a10af
Implement invert_*
ahuang11 Aug 28, 2023
a13bed3
Actually implement invert
ahuang11 Aug 29, 2023
c877ca3
Undo black
ahuang11 Aug 29, 2023
fbed39d
Implement shade
ahuang11 Aug 29, 2023
2f092f0
Remove duplicate logic clause
ahuang11 Aug 29, 2023
970fdd9
add flatten operation
ahuang11 Aug 29, 2023
8c0304d
Add reference notebooks
ahuang11 Aug 29, 2023
9c1babf
Add tests
ahuang11 Aug 29, 2023
196ec8b
Inline datashader
ahuang11 Aug 30, 2023
9c750e4
Support 3D by default
ahuang11 Aug 30, 2023
a7b19e4
Fix datashader test
ahuang11 Aug 30, 2023
3d5eada
Fix to array
ahuang11 Aug 31, 2023
f280a26
Fix tests
ahuang11 Aug 31, 2023
65e5148
Remove bokeh 2 from test matrix and pin pandas < 2.1
ahuang11 Aug 31, 2023
04199e2
Update setup.py
ahuang11 Sep 8, 2023
57a0cf3
Pin Pandas<2.1 (#5877)
hoxbro Sep 5, 2023
2411cfb
support python3-only systems (#5874)
MeggyCal Sep 5, 2023
9003a93
Support Numpy 1.25 (#5870)
hoxbro Sep 6, 2023
72473c7
Try/except get_extents without dimension and add kwargs to all get_ex…
hoxbro Sep 6, 2023
58e4a20
Unpin pandas dependency (#5880)
hoxbro Sep 8, 2023
5c34336
Fix selection of palette
ahuang11 Sep 9, 2023
55777aa
Fix issue with detecting xarray
ahuang11 Sep 12, 2023
f73753f
Remove print
ahuang11 Sep 12, 2023
2a38812
Update holoviews/core/data/__init__.py
ahuang11 Sep 12, 2023
9a48b49
Merge branch 'main' into categorical
hoxbro Sep 12, 2023
18abf6d
Address comments
ahuang11 Sep 12, 2023
c6ca549
Cleanup and remove hover cols
ahuang11 Sep 12, 2023
25efbd2
Fix test
ahuang11 Sep 12, 2023
d088080
Add tests
ahuang11 Sep 12, 2023
23af53d
Move xarray tests
ahuang11 Sep 12, 2023
f2da257
Fix core tests
ahuang11 Sep 13, 2023
f4714e9
Address comments
ahuang11 Sep 13, 2023
8ea52d7
Fix other asserts too
ahuang11 Sep 13, 2023
228d2ef
Add missing self
ahuang11 Sep 13, 2023
81c52aa
Remove assert ahead of np.testing
ahuang11 Sep 13, 2023
a9625c1
Remove testing max
ahuang11 Sep 13, 2023
4c5048d
Address comment
ahuang11 Sep 14, 2023
61c8fb7
Address comment
ahuang11 Sep 14, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
matrix:
os: ['ubuntu-latest', 'macos-latest', 'windows-latest']
python-version: ['3.8', '3.11']
bokeh-version: ['2', '3']
bokeh-version: ['3']
timeout-minutes: 120
defaults:
run:
Expand Down
113 changes: 113 additions & 0 deletions examples/reference/elements/bokeh/ImageStack.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<div class=\"contentcontainer med left\" style=\"margin-left: -50px;\">\n",
"<dl class=\"dl-horizontal\">\n",
" <dt>Title</dt> <dd> ImageStack Element</dd>\n",
" <dt>Dependencies</dt> <dd>Bokeh</dd>\n",
" <dt>Backends</dt>\n",
" <dd><a href='./ImageStack.ipynb'>Bokeh</a></dd>\n",
" <dd><a href='../matplotlib/ImageStack.ipynb'>Matplotlib</a></dd>\n",
" <dd><a href='../plotly/ImageStack.ipynb'>Plotly</a></dd>\n",
"</dl>\n",
"</div>"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import holoviews as hv\n",
"hv.extension('bokeh')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"``ImageStack`` facilitates the representation of a regularly spaced 2D grid within a continuous domain of color space values (RGB(A)). The grid's structure aligns closely with that of an Image element. In its simplest form, the grid can be defined through an array with dimensions of ``NxMxL``, where ``L`` represents the number of channels. Alternatively, explicit and uniformly spaced x/y-coordinate arrays can also define the ``ImageStack``.\n",
"\n",
"The core methods for constructing an ``ImageStack`` are:\n",
"\n",
"1. Creating using coordinates and channel values:\n",
" ```\n",
" ImageStack((X, Y, L1, L2, ..., LL), vdims=[\"l1\", \"l2\", ... \"ll\"])\n",
" ```\n",
" Here, ``X`` is a 1D array with ``M`` elements, ``Y`` is a 1D array with ``N`` elements, and ``L1``, ``L2``, ..., ``LL`` represent 2D arrays with dimensions ``NxM``.\n",
"\n",
"2. Creation through a composite array and bounds specification:\n",
" ```\n",
" ImageStack(Z, bounds=(x0, y0, x1, y1))\n",
" ```\n",
" In this scenario, ``Z`` is a 3D array with dimensions ``NxMxL``, and the bounds parameter defines the (left, bottom, right, top) corners of the grid.\n",
"\n",
"For comprehensive information, refer to the [Gridded Datasets](../../../user_guide/09-Gridded_Datasets.ipynb) user guide."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"x = np.arange(0, 3)\n",
"y = np.arange(5, 8)\n",
"a = np.array([[np.nan, np.nan, 1], [np.nan] * 3, [np.nan] * 3])\n",
"b = np.array([[np.nan] * 3, [1, 1, np.nan], [np.nan] * 3])\n",
"c = np.array([[np.nan] * 3, [np.nan] * 3, [1, 1, 1]])\n",
"\n",
"img_stack = hv.ImageStack((x, y, a, b, c), kdims=[\"x\", \"y\"], vdims=[\"a\", \"b\", \"c\"])\n",
"img_stack"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A `cmap` can be added to differentiate the different levels."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"cmap = [\"red\", \"green\", \"blue\"]\n",
"img_stack.opts(cmap=cmap)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Slicing, sampling, etc. on an ``ImageStack`` all operate in this continuous space, whereas the corresponding operations on a ``Raster`` work on the raw array coordinates.\n",
"\n",
"Here we take slices up to x=0.5 and y=7, which is out of bounds for the red."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"img_stack[:0.5, :7]"
]
}
],
"metadata": {
"language_info": {
"name": "python",
"pygments_lexer": "ipython3"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
98 changes: 98 additions & 0 deletions examples/reference/elements/matplotlib/ImageStack.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<div class=\"contentcontainer med left\" style=\"margin-left: -50px;\">\n",
"<dl class=\"dl-horizontal\">\n",
" <dt>Title</dt> <dd> ImageStack Element</dd>\n",
" <dt>Dependencies</dt> <dd>Bokeh</dd>\n",
" <dt>Backends</dt>\n",
" <dd><a href='./ImageStack.ipynb'>Bokeh</a></dd>\n",
" <dd><a href='../matplotlib/ImageStack.ipynb'>Matplotlib</a></dd>\n",
" <dd><a href='../plotly/ImageStack.ipynb'>Plotly</a></dd>\n",
"</dl>\n",
"</div>"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import holoviews as hv\n",
"hv.extension('matplotlib')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"``ImageStack`` facilitates the representation of a regularly spaced 2D grid within a continuous domain of color space values (RGB(A)). The grid's structure aligns closely with that of an Image element. In its simplest form, the grid can be defined through an array with dimensions of ``NxMxL``, where ``L`` represents the number of channels. Alternatively, explicit and uniformly spaced x/y-coordinate arrays can also define the ``ImageStack``.\n",
"\n",
"The core methods for constructing an ``ImageStack`` are:\n",
"\n",
"1. Creating using coordinates and channel values:\n",
" ```\n",
" ImageStack((X, Y, L1, L2, ..., LL), vdims=[\"l1\", \"l2\", ... \"ll\"])\n",
" ```\n",
" Here, ``X`` is a 1D array with ``M`` elements, ``Y`` is a 1D array with ``N`` elements, and ``L1``, ``L2``, ..., ``LL`` represent 2D arrays with dimensions ``NxM``.\n",
"\n",
"2. Creation through a composite array and bounds specification:\n",
" ```\n",
" ImageStack(Z, bounds=(x0, y0, x1, y1))\n",
" ```\n",
" In this scenario, ``Z`` is a 3D array with dimensions ``NxMxL``, and the bounds parameter defines the (left, bottom, right, top) corners of the grid.\n",
"\n",
"For comprehensive information, refer to the [Gridded Datasets](../../../user_guide/09-Gridded_Datasets.ipynb) user guide.\n",
"\n",
"*Note* The `datashader` library must be installed to use ``ImageStack`` with the matplotlib backend."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"x = np.arange(0, 3)\n",
"y = np.arange(5, 8)\n",
"a = np.array([[np.nan, np.nan, 1], [np.nan] * 3, [np.nan] * 3])\n",
"b = np.array([[np.nan] * 3, [1, 1, np.nan], [np.nan] * 3])\n",
"c = np.array([[np.nan] * 3, [np.nan] * 3, [1, 1, 1]])\n",
"\n",
"img_stack = hv.ImageStack((x, y, a, b, c), kdims=[\"x\", \"y\"], vdims=[\"a\", \"b\", \"c\"])\n",
"img_stack"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Slicing, sampling, etc. on an ``ImageStack`` all operate in this continuous space, whereas the corresponding operations on a ``Raster`` work on the raw array coordinates.\n",
"\n",
"Here we take slices up to x=0.5 and y=7, which is out of bounds for the red."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"img_stack[:0.5, :7]"
]
}
],
"metadata": {
"language_info": {
"name": "python",
"pygments_lexer": "ipython3"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
98 changes: 98 additions & 0 deletions examples/reference/elements/plotly/ImageStack.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<div class=\"contentcontainer med left\" style=\"margin-left: -50px;\">\n",
"<dl class=\"dl-horizontal\">\n",
" <dt>Title</dt> <dd> ImageStack Element</dd>\n",
" <dt>Dependencies</dt> <dd>Bokeh</dd>\n",
" <dt>Backends</dt>\n",
" <dd><a href='./ImageStack.ipynb'>Bokeh</a></dd>\n",
" <dd><a href='../matplotlib/ImageStack.ipynb'>Matplotlib</a></dd>\n",
" <dd><a href='../plotly/ImageStack.ipynb'>Plotly</a></dd>\n",
"</dl>\n",
"</div>"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import holoviews as hv\n",
"hv.extension('plotly')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"``ImageStack`` facilitates the representation of a regularly spaced 2D grid within a continuous domain of color space values (RGB(A)). The grid's structure aligns closely with that of an Image element. In its simplest form, the grid can be defined through an array with dimensions of ``NxMxL``, where ``L`` represents the number of channels. Alternatively, explicit and uniformly spaced x/y-coordinate arrays can also define the ``ImageStack``.\n",
"\n",
"The core methods for constructing an ``ImageStack`` are:\n",
"\n",
"1. Creating using coordinates and channel values:\n",
" ```\n",
" ImageStack((X, Y, L1, L2, ..., LL), vdims=[\"l1\", \"l2\", ... \"ll\"])\n",
" ```\n",
" Here, ``X`` is a 1D array with ``M`` elements, ``Y`` is a 1D array with ``N`` elements, and ``L1``, ``L2``, ..., ``LL`` represent 2D arrays with dimensions ``NxM``.\n",
"\n",
"2. Creation through a composite array and bounds specification:\n",
" ```\n",
" ImageStack(Z, bounds=(x0, y0, x1, y1))\n",
" ```\n",
" In this scenario, ``Z`` is a 3D array with dimensions ``NxMxL``, and the bounds parameter defines the (left, bottom, right, top) corners of the grid.\n",
"\n",
"For comprehensive information, refer to the [Gridded Datasets](../../../user_guide/09-Gridded_Datasets.ipynb) user guide.\n",
"\n",
"*Note* The `datashader` library must be installed to use ``ImageStack`` with the plotly backend."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"x = np.arange(0, 3)\n",
"y = np.arange(5, 8)\n",
"a = np.array([[np.nan, np.nan, 1], [np.nan] * 3, [np.nan] * 3])\n",
"b = np.array([[np.nan] * 3, [1, 1, np.nan], [np.nan] * 3])\n",
"c = np.array([[np.nan] * 3, [np.nan] * 3, [1, 1, 1]])\n",
"\n",
"img_stack = hv.ImageStack((x, y, a, b, c), kdims=[\"x\", \"y\"], vdims=[\"a\", \"b\", \"c\"])\n",
"img_stack"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Slicing, sampling, etc. on an ``ImageStack`` all operate in this continuous space, whereas the corresponding operations on a ``Raster`` work on the raw array coordinates.\n",
"\n",
"Here we take slices up to x=0.5 and y=7, which is out of bounds for the red."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"img_stack[:0.5, :7]"
]
}
],
"metadata": {
"language_info": {
"name": "python",
"pygments_lexer": "ipython3"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
5 changes: 3 additions & 2 deletions examples/user_guide/15-Large_Data.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,8 @@
"metadata": {},
"outputs": [],
"source": [
"gaussians = {i: hv.Points(rand_gauss2d(i), kdims, \"i\") for i in range(num_ks)}\n",
"gaussians = {str(i): hv.Points(rand_gauss2d(i), kdims, \"i\") for i in range(num_ks)}\n",
"\n",
"c = dynspread(datashade(hv.NdOverlay(gaussians, kdims='k'), aggregator=ds.by('k', ds.count())))\n",
"m = dynspread(datashade(hv.NdOverlay(gaussians, kdims='k'), aggregator=ds.by('k', ds.mean(\"i\"))))\n",
"\n",
Expand All @@ -462,7 +463,7 @@
"metadata": {},
"outputs": [],
"source": [
"lines = {i: hv.Curve(time_series(N=10000, S0=200+np.random.rand())) for i in range(num_ks)}\n",
"lines = {str(i): hv.Curve(time_series(N=10000, S0=200+np.random.rand())) for i in range(num_ks)}\n",
"lineoverlay = hv.NdOverlay(lines, kdims='k')\n",
"datashade(lineoverlay, pixel_ratio=2, line_width=4, aggregator=ds.by('k', ds.count())).opts(width=800)"
]
Expand Down
10 changes: 7 additions & 3 deletions holoviews/core/data/xarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def retrieve_unit_and_label(dim):
if isinstance(label, str):
vdim.label = label
elif len(vdim_param.default) == 1:
vdim = vdim_param.default[0]
vdim = asdim(vdim_param.default[0])
if vdim.name in data.dims:
raise DataError("xarray DataArray does not define a name, "
"and the default of '%s' clashes with a "
Expand All @@ -121,8 +121,12 @@ def retrieve_unit_and_label(dim):
"supply an explicit vdim." % eltype.__name__,
cls)
if not packed:
vdims = [vdim]
data = data.to_dataset(name=vdim.name)
if vdim in data.dims:
data = data.to_dataset(vdim.name)
vdims = [asdim(vd) for vd in data.data_vars]
else:
vdims = [vdim]
data = data.to_dataset(name=vdim.name)
ahuang11 marked this conversation as resolved.
Show resolved Hide resolved

if not isinstance(data, (xr.Dataset, xr.DataArray)):
if kdims is None:
Expand Down
Loading