Skip to content

separate array logic and graphic logic in ImageWidget - #868

Merged
kushalkolar merged 64 commits into
ndwidgetfrom
iw-array
Feb 16, 2026
Merged

kushalkolar merged 64 commits into
ndwidgetfrom
iw-array

Conversation

@kushalkolar

@kushalkolar kushalkolar commented Jun 29, 2025 •

Copy link
Copy Markdown
Member

Basically a re-write of ImageWidget.

NDImageProcessor

This is a class that manages one n-dimensional array-like object. An array-like object must have at least 2 dimensions, and can have an unlimited number of more dimensions (but practically I doubt there's use cases for beyond ~5 dimensions, but it will work anyways). It can also process window functions and a finalizer function (previously called "frame_apply").

NDImageProcessor has the following important settable properties:
data: the n-dimensional array it manages
n_display_dims: one of 2 | 3, the number of "spatial dimensions". This is used to determine if an ImageGraphic or an ImageVolumeGraphic should be used.
rgb: whether it is rgb or not
n_slider_dims: auto-computed on demand based on n_display_dims and rgb.

NDImageProcessor.get(indices: tuple[int, ...]) is where all the work is done. It retrieves a 2D or 3D image and applies independent window functions on each dimension where a window_func is defined. Functions and window sizes can be unique across all dims!

Once the window functions are applied, a finalizer_func() is applied on the remaining 2 or 3 spatial dims if necessary.

The NDImageProcessor also handles computing the histogram.

NDImageProcessor can be subclassed to create ones that are specific for different types of arrays, such as dask arrays, and also allow for histogram logic to be unique to each.

ImageWidget

ImageWidget no longer does any compute or processing! It just hands each data array to an NDImageProcessor, and therefore keeps a list of all the processors that correspond to each array: ImageWidget._image_processors.

ImageWidget just handles graphics and sliders. When the slider indices (managed by ImageWidget.indices settable property) change, it just calls NDImageProcessor.get(new_indices) on each processor and the result is displayed, that's it 😄 .

When data arrays, n_display_dims, or rgb changes, dimensions are pushed/popped on ImageWidget.indices. For example, if a dimension is no longer present on any of the current arrays in the ImageWidget then it pops a dimension from indices and a slider will disappear. And vice-versa.

HistogramLUTTool was also re-written. It now just manages the graphics side of things. A precomputed histogram must be given to it.

@kushalkolar

kushalkolar commented Jul 6, 2025 •

Copy link
Copy Markdown
Member Author

If we add the following properties we can make things way more arbitrary:

dim_names: dict that maps numerical dim index to a dimension name, ex: {0: "t", 1: "z"}. Only need to name scrollable dims.

index: dict that maps dim name to current index, ex: {"t": 123, "z": 5}

image_dims: tuple[int, int] | tuple[int, int, int] numerical dim indices that define the image displayed in the ImageGraphic or ImageVolumeGraphic.

Also, for window_funcs, if a window func is provided for only one dim then it should apply the window only along that dim. If window_funcs are defined for multiple dimensions, then apply the window for all provided dims. Can also have a way to define the order, ex. do "t" first and "z" etc.

Histogram calculation can also be done within this widget anytime the window funcs or frame_apply funcs are changed. We can then just allow force-setting the HistogramLUTGraph.

@kushalkolar

kushalkolar commented Aug 3, 2025 •

Copy link
Copy Markdown
Member Author

Make a few ready-made subclasses of ImageWidgetArray, for example IWA_Dask, IWA_Lazy etc.

In ImageWidget.__init__(), parse each data array in the list use the appropriate IWA type based on the data array type.

IW also has a new kwarg iwa_types which can explicitly define the IWA type which corresponds to the data array.

Make the window functions more flexible. Allow options kwargs that include the full data array, i.e. IWA.data, and the current index. Useful for things like computing a window function and then using that on the original data or current frame. Example, use a rolling filter on the current window, use this to subtract from the original frame.

@kushalkolar

Copy link
Copy Markdown
Member Author

new kwarg on ImageWidget, "adaptive_histogram", List[bool] | bool which creates an event handler for current_index so that any time the slider is moved or the index is changed it sets the histogram based on the current frame/volume.

@kushalkolar

Copy link
Copy Markdown
Member Author

If the data doesn't change when moving through dims, example: if there's a simple 2D image amongst multiple txy videos, then would be good to handle this efficiently so that Texture doesn't isn't uploaded when it doesn't change.

@kushalkolar kushalkolar mentioned this pull request Oct 18, 2025
52 of 78 tasks
@kushalkolar

kushalkolar commented Nov 1, 2025 •

Copy link
Copy Markdown
Member Author

ok so another issue is that you can't use a window function when you have a mix of movies and images (no t dim) 😞 . So this separation also needs to fix this issue.

Also need to make it possible for an ImageWidget subplot to be blank, set that data index as None and just ignore when scrolling.

@kushalkolar

Copy link
Copy Markdown
Member Author

argument to specify a transpose tuple of size 2 or 3 that is applied on the final image/volume after slicing, window functions, etc. could be useful.

@kushalkolar

Copy link
Copy Markdown
Member Author

ok I think I got a good way to apply window funcs, clean, understandable.

# array with many slider_dims
a = np.random.rand(25, 20, 8, 4, 100, 100)
print("shape of a:\t\t", a.shape)

# final slice is: (i - w, i, i + w)
# specify window size for each dim
windows = (3, None, 2, None)
# order in which window funcs are applied
order = (0, 2)
# window function for each dim
funcs = (np.mean, None, np.std, None)

# current slider indices
indices = (15, 5, 4, 2)

indexer = list()

for i, w in zip(indices, windows):
    if w is not None:
        s = slice(i - w, i + w, 1)  # start, stop, step
    else:
        s = slice(i, i + 1, 1)
    indexer.append(s)

print("indexer:\t\t", indexer)

a_s = a[tuple(indexer)]

# also provide the user the option to use this window-sliced array in one function where they handle everything
print("indexer applied to a:\t", a_s.shape)

for dim in order:
    f = funcs[dim]

    a = f(a, axis=dim, keepdims=True)
    print(f"shape of a after window func: {f} on dim: {dim} is:\t {a.shape}")

@kushalkolar

kushalkolar commented Nov 4, 2025 •

Copy link
Copy Markdown
Member Author

Thoughts on how sliders should map onto dims:

if we have this array, let's say it's [t, z, m, n]:
[1_000, 30, 100, 100]

then, do we assume the following smaller array is [t, m, n] or [z, m, n]?
[n, 100, 100]

Another way to think about this:

We want to allow arbitrary numbers of dims, so if we have the following array with ndim 6:
[a, b, c, d, m, n]

[m, n] are the image dims (it could also be RGB or volumetric, that stuff is easy to deal with, ignore it for now)

Do we assume a smaller array with ndim 4 is:
[a, b, m, n]

or:

[c, d, m, n]

Sliders will be made for a, b, c, d so this is important to decide.

One way to thing of it is: right-most are image dims, so slider dims accumulate as soon as image dims finish?
This would mean we interpret the shorter array above as [c, d, m, n]

Another way to think of it is, slider dims accumulate from left to right until they reach the image dims.
This would mean we interpret the above array as [a, b, m, n]

EDIT: We have chosen to do [c, d, m, n]

@FlynnOConnell

Copy link
Copy Markdown
Collaborator

I think accumulating the slider dims from left to right makes sense.

However, depending on the use-case, I would want to be able to choose between [a b m n] and [c d m n]. For microscopy, [t z m n] is the most popular but I've also seen libraries use [z t m n] (e.g. suite3d). These two dim orders behave completely differently and take a lot of fine-tuning in dask/numpy depending on which you use.

What about defaulting to "left to right" mapping with an optional semantic argument, e.g.:

ImageWidget(
    data=array,
    image_dims=(-2, -1),  # or just always the last two dims
    slider_dims=(0, 1, 2, 3),  # explicit ordering
    dim_names={0: "t", 1: "z", 2: "c"}  # for imgui slider labels
)

@kushalkolar

Copy link
Copy Markdown
Member Author

Another important thing: other than slider dims, nothing else has to be the same between iw arrays. For example, we can allow each individual array in the ImageWidget to have their own window function or frame apply function. Not sure what's the best API for this though.

Maybe the constructor can take a window funca arg, which if it's a list it defines the window func per data array. This would of course be symmetric with the properties.

@kushalkolar

Copy link
Copy Markdown
Member Author

display_dims should be a mutable property. When changed from 2 or 3, delete the existing graphic and replace it.

@kushalkolar

kushalkolar commented Nov 5, 2025 •

Copy link
Copy Markdown
Member Author

ok I got the basics down!

I now realize the histogram is not gonna be trivial 😄

We can't sub-sample the original array and then pass it through the window funcs because that won't correspond to windows in the original data.

I think we need to do something like this:

  • if a window function is used for a dim, use a small number of indices from this dim depending on the window size, but at least 5 or 10. Apply the window function with these indices.
  • if a dim has no window function, use some number of indices from this dim, but can be somewhat generous.
  • if using a finalizer_func that's applied before displaying the frame or volume, do not subsample these spatial dims, for example a Gaussian kernel would provide very different results on a full spatial sample vs. a subsample.

I think we can use some of the logic in utils.subsample_array and do something like;

  1. Create a new func get_subsample_indices that returns the indices necessary to subsample the array.
  2. Determine a number of sample indices, call get() with the indices.
  3. Concatenate all these arrays and compute the histogram.

@apasarkar @FlynnOConnell

@kushalkolar

Copy link
Copy Markdown
Member Author

Thoughts on how sliders should map onto dims:

if we have this array, let's say it's [t, z, m, n]: [1_000, 30, 100, 100]

then, do we assume the following smaller array is [t, m, n] or [z, m, n]? [n, 100, 100]

Another way to think about this:

We want to allow arbitrary numbers of dims, so if we have the following array with ndim 6: [a, b, c, d, m, n]

[m, n] are the image dims (it could also be RGB or volumetric, that stuff is easy to deal with, ignore it for now)

Do we assume a smaller array with ndim 4 is: [a, b, m, n]

or:

[c, d, m, n]

Sliders will be made for a, b, c, d so this is important to decide.

One way to thing of it is: right-most are image dims, so slider dims accumulate as soon as image dims finish? This would mean we interpret the shorter array above as [c, d, m, n]

Another way to think of it is, slider dims accumulate from left to right until they reach the image dims. This would mean we interpret the above array as [a, b, m, n]

EDIT: We have chosen to do [c, d, m, n]

ok so both are actually easy to do and this is something that ImageWidget can handle before calling get() on each of the individual NDImageViews:

# consider an example index from all 4 sliders
indices = (100, 15, 5, 3)

# if we have 4 example array which have the following number of slider dims
n_slider_dims = [4, 3, 2, 1]

right -> left ordering

# get the indices we use for each of the 4 arrays with different numbers of dims
for n in n_slider_dims:
    print(f"{n} slider_dims, right -> left indices are: {indices[-n:]}")

out:

4 slider_dims, right -> left indices are: (100, 15, 5, 3)
3 slider_dims, right -> left indices are: (15, 5, 3)
2 slider_dims, right -> left indices are: (5, 3)
1 slider_dims, right -> left indices are: (3,)

left -> right ordering

for n in n_slider_dims:
    print(f"{n} slider_dims, left -> right indices are: {indices[:n]}")

out:

4 slider_dims, left -> right indices are: (100, 15, 5, 3)
3 slider_dims, left -> right indices are: (100, 15, 5)
2 slider_dims, left -> right indices are: (100, 15)
1 slider_dims, left -> right indices are: (100,)

@FlynnOConnell

@kushalkolar

Copy link
Copy Markdown
Member Author

my all time favorite commit in fastplotlib 😄 : 7770ee0

@FlynnOConnell

Copy link
Copy Markdown
Collaborator

image

beauty lol

@kushalkolar

kushalkolar commented Nov 6, 2025 •

Copy link
Copy Markdown
Member Author

ok the basics work! 🥳

Needs tests, more manual testing, some cleanup and tweaks and will be ready to go! I anticipate there will be a few growing pains, lots of parsing since this has to deal with a diverse range of complex datasets and compute possibilities so it may take a while to iron out all the bugs.

nd2-2025-11-06_02.40.05.mp4
nd2-2025-11-06_02.49.11.mp4
nd3-2025-11-06_02.50.17.mp4

@apasarkar @FlynnOConnell @clewis7 gonna need a review from all of you :D

@kushalkolar

Copy link
Copy Markdown
Member Author

Allow the spatial func to be a compute shader or a python function.

@FlynnOConnell

FlynnOConnell commented Nov 21, 2025 •

Copy link
Copy Markdown
Collaborator

@kushalkolar I'm confused at where in the code we expect custom lazy arrays to be called on a set of indices.

This line is causing me problems:

if isolated_buffer:
# useful if data is read-only, example: memmaps
self._value = np.zeros(data.shape, dtype=data.dtype)
self.value[:] = data[:]

.. where data[:] is causing my arrays getitem to load fully into RAM.

These are 4D TZXY, so when texture = pygfx.Texture(self.value[data_slice], dim=2) is called, my array's 4D structure errors:

  File "C:\Users\RBO\repos\mbo_utilities\.venv\Lib\site-packages\pygfx\resources\_texture.py", line 145, in __init__
    the_size = size_from_array(view, dim)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\RBO\repos\mbo_utilities\.venv\Lib\site-packages\pygfx\resources\_texture.py", line 591, in size_from_array
    raise ValueError(
ValueError: Can't map shape (71, 14, 448, 448) on 2D tex. Maybe also specify size?

In the ImageGraphic.data docstring , it mentions data must implement memoryview(), but the call to memoryview doesn't happen until the Texture() definition here:

# create a pygfx.Texture from this chunk
for _, buffer_index, data_slice in self:
texture = pygfx.Texture(self.value[data_slice], dim=2)
self.buffer[buffer_index] = texture

The dim=2 here is throwing me off, so we expect this to always be 2D at this point?

EDIT

ValueError: Can't map shape (71, 14, 448, 448) on 2D tex. Maybe also specify size?

This happened because my array.ndim was returning the wrong value.

Everything is working flawlessly so far!

@FlynnOConnell

Copy link
Copy Markdown
Collaborator

@kushalkolar YESYESYESYES THANK YOU

iw-array-test.mp4

More to test on Sunday!

@FlynnOConnell

Copy link
Copy Markdown
Collaborator
if issubclass(processors, NDImageProcessor):
    processors = [processors] * len(data)

Gives TypeError: issubclass() arg 1 must be a class when I pass a list of processors.

Could do:

if isinstance(processors, type) and issubclass(processors, NDImageProcessor):
    processors = [processors] * len(data)

Works with a single processor:

isinstance(processors[0], type)
Out[1]: True

@kushalkolar

Copy link
Copy Markdown
Member Author

More ideas:

  • two modes for histograms: 1) update on every frame, 2) global histogram that represents full data. A kwargs or something.

@FlynnOConnell

Copy link
Copy Markdown
Collaborator

right-click histogram to change the colormap?

@kushalkolar

Copy link
Copy Markdown
Member Author

@apasarkar

apasarkar commented Dec 14, 2025 •

Copy link
Copy Markdown
Collaborator

@kushalkolar some thoughts re: the multi-session use case.

I think I understand what you're suggesting above re: arrays with dynamical shapes. Conceptually this would allow us to define a (num_sessions, <other_dimensions>) array. As you scroll through the "num_sessions" axis, you display data from a different session, and this movie can have a different spatial FOV (and number of frames).

I wonder whether it would be more intuitive to allow the "data" parameter in ImageWidget to be multi-dimensional. For e.g.:


group_1 = [session_1_vid1, session_1_vid2, ..._session_1_vidn1]

group_2 = [session_2_vid2, session_2_vid2, ..., session_2_vidn2]

group_M = [...]

data_arr = [group_1, group_2, ..., group_M]

iw = fpl.ImageWidget(data = [data_arr])

iw.show()               

Here, imagewidget would recognize the nested list structure and add an extra scrollable dimension to allow the user to move between groups of arrays.

This probably also relates to the multi-dimensional-everything vis.

@apasarkar

Copy link
Copy Markdown
Collaborator

Re: the parameters for the constructor, I wonder whether we can get rid of n_display_dims by adding a "volume" boolean. This boolean is by default False (in the same way that rgb is).

By inspecting the values for volume and rgb, the imagewidget constructor can track what the number of display dimensions should be automatically. (2, 3, or 4 in the case where rgb and volume are both true).

This might be easier for the user (since they are specifying parameters directly related to what they expect to see in the data).

* fix typos

* add rendercanvas to intersphinx_mapping
@kushalkolar
kushalkolar changed the base branch from main to ndwidget February 14, 2026 09:01
@kushalkolar

Copy link
Copy Markdown
Member Author

ok this is ready to merge into the ndwidget branch, but I will do that tomorrow to make sure it goes well 🥳

@kushalkolar
kushalkolar marked this pull request as ready for review February 14, 2026 09:08
@kushalkolar
kushalkolar requested a review from clewis7 as a code owner February 14, 2026 09:08
@kushalkolar
kushalkolar merged commit 47ec02a into ndwidget Feb 16, 2026
@kushalkolar
kushalkolar deleted the iw-array branch April 14, 2026 16:12
kushalkolar added a commit that referenced this pull request Sep 21, 2026
* start ndprocessors

* basic timeseries

* add __init__

* heatmap for timeseries works!

* NDPositions, basics work, reorganize, increase default scatter size

* black

* NDPositions working with multi-dim stack of lines, need to test window funcs

* scatter collection

* progress, need to change to other branch so committing

* better

* interpolation for heatmap

* better place for check

* window functions working on n_datapoints dim

* p dim window funcs working for single and multiple dims I think

* black

* index_mappings is working I think, lightly tested on p dim

* remove nd_timeseries since nd_positions is sufficient

* auto-replace buffers (#974)

* remove isolated_buffer

* remove isolated_buffer from mixin

* basics works for positions data

* replaceable buffers for all positions related features

* image data buffer can change

* resizeable buffers for volume

* black

* buffer resize condition checked only if new value is an array

* gc for buffer managers

* uniform colors WIP

* switching color modes works!

* typo

* balck

* update tests for color_mode

* update examples

* backend tests passing

* default for all uniforms is True

* update examples

* forgot

* update test

* example tests passing

* dereferencing test and fixes

* simplify texture array tests a bit

* image replace buffer tests pass yay

* forgot a file

* comments, check image graphic

* add image reshaping example

* add buffer replace imgui thing for manual testing

* black

* dont call wgpu_obj.destroy(), seems to work and clear VRAM with normal dereferencing

* slower changes

* update

* update example

* fixes and tweaks for test

* remove unecessary stuff

* update

* docstrings

* fix example

* update example

* update example

* update docs

* some basic OOC working

* max num of dipslay datapoints

* scatter stack, not tested

* progress

* scatter collection updates

* tootip handlers for ndpositions

* refactoring, general NDPP_Pandas processor for any dataframe data

* separate array logic and graphic logic in `ImageWidget` (#868)

* start separating iw plotting and array logic

* some more basics down

* comment

* collapse into just having a window function, no frame_function

* progress

* placeholder for computing histogram

* formatting

* remove spaghetti

* more progress

* basics working :D

* black

* most of the basics work in iw

* fix

* progress

* progress but still broken

* flippin display dims works

* camera scale must be positive for MIP rendering

* a very difficult to encounter iterator bug!

* patch iterator caveats

* mostly worksgit status

* add ArrayProtocol

* rename

* fixes

* set camera orthogonal to xy plane when going from 3d -> 2d

* naming, cleaning

* cleanup, correct way to push and pop dims

* quality of life improvements

* new histogram lut tool

* new hlut tool

* imagewidget rgb toggle works

* more progress

* support rgb(a) image volumes

* ImageGraphic cleanup

* cleanup, docs

* fix

* updates

* new per-data array properties work

* black formatting

* fixes and other things

* typing tweaks

* better iterator, fix bugs

* fixes

* show tooltips in right clck menu

* ignore nans and inf for histogram

* histogram of zeros

* docstrings

* fix imgui pixels

* iw indices event handlers only get a tuple of the indices

* bugfix

* fix cmap setter

* spatial_func better name

* bugfix

* hist specify quantile

* fix typos (#991)

* fix typos

* add rendercanvas to intersphinx_mapping

* nd-iw backup

* correct ImageGraphic w.r.t. ndw

* last fixes in ndi

* update

* basic minimal ndw orchestration working

* implement auto-x for timeseries

* bugfix update worldobject -> graphic map for image tiles

* bugfix linear selector set limits

* linear selector for timeseries

* return full data if display_window is Noen

* arrow key to step indices

* imgui separator

* fix and ui stuff

* both auto x range modes working

* progress

* moving stuff

* much much better organization of things

* GlobalIndexVector working with ndpostions and ndimage

* examples

* progress

* do not reset vmin vmax when replacing Image buffer

* WIP migrate to xarray

* window funcs in NDProcessor class using xarray, WIP, not tested

* typo

* basic single index slicing working with xarray

* window funcs working for NDPositions and NDPP_Pands

* display_window window funcs working for NDPositions

* imgui stuff

* finish migrate NDImage to xarray, basics work

* NDImage working mostly, behavior viz is back

* better flipping logic

* update examples

* more progress

* update example

* histogram working for images

* NDProcessor property aliases

* more aliasing

* fix

* update example

* fix

* ui

* cleanup old iw-array, imports, add deprecation warning on old iw

* add ndwidget section to deps with xarray

* nice repr for NDProcessor

* imgui right click menu for ndgraphics

* better

* controller options separate window

* update imgui

* fix

* fix compute histogram

* other features WIP

* basics of other features works with ScatterStack for colors, markers, sizes, need to keep testing

* require min pygfx v0.16.0 due to gc hash fix necessary for NDWidget

* fix PlotArea.y_range

* fix to create isolated buffer for colors when buffer replaced

* np.empty

* cmap_transform_each WIP

* progress

* fix

* replace graphic when data changed, tweak index_mappings

* Update installation docs (#1013)

* add simplejpeg to notebook deps

* Update guide.rst

* Update guide.rst

* Update README.md

* cmap lib handles image colormaps now

* multi-windows ndwidget, maintain features like cmap when switching graphics

* progress

* lighting objects only when a mesh is added

* fix

* update axes only when camera or view changes

* clean heatmap func

* stupid print

* docstrings, comments

* remove unused attr, comments

* remove print

* add NDGraphic.pause, expose histogram widget

* ndg pause in imgui

* add helper function to convert heatmap timeseries to postional data shape

* index wans't calling handlers

* remove

* allow image types other than float32 (#1027)

* Includes code for doing batched transforms in both directions (#1025)

* Includes code for doing batched transforms in both directions

* Streamlined parsing logic and updated docstrings for model to world code

* Fixes inconsistent error messages

* More streamlined type checking

* Gets rid of checks and uses np asarray

* Some more aesthetic updates to the syntax

* Update fastplotlib/graphics/_base.py

---------

Co-authored-by: Kushal Kolar <kushalkolar@gmail.com>

* async NDProcessor (#1026)

* async NDProcessor established, NOT TESTED

* ASYNC NDPROC IS WORKING :D :D CELEBRATE

* comments

* type annot

* fix

* fix

* polish async integration, cuda also integrated

* no longer using xarray, allow simpler ArrayProtocol

* comments

* comments

* docs

* forgot to set back to False

* remove xarray from pyproject.toml

* throttling

* Adds nd vector graphic (#1034)

* Includes nd vector code that works

* Faster position assignment, no more for loop

* Batched computations for vector set function

* Formatting updates

* Includes improved annotations and changes ordering of the data slice from the vectors graphic

* Some further improvements to the pylinalg code

* Fixes remaining formatting and naming issues

* Apply suggestions from code review

Co-authored-by: Kushal Kolar <kushalkolar@gmail.com>

---------

Co-authored-by: Kushal Kolar <kushalkolar@gmail.com>

* Adds kwargs so user can customize vector field estimates (#1036)

* Adds kwargs so user can customize vector field estimates

* Does the kwarg organization the way ndpositions does

* fixes graphic constructor

* implement yuv and other colorspaces and "bufferless" `TextureArray` (#1033)

* implement yuv and 'bufferless' TextureArraY

* unbuffered and yuv420 works

* warning on tooltip

* NDImage always uses unbuffered, support colorspaces in NDIMage

* update docstrings

* by default disable AA and set pixel_scale=1.0 for performance

* unpacked yuv support

* independent graphics and texture features for rgb and yuv

* docstrings

* docstrings

* import order

* yuv graphic working nicely

* add enum to top level namespace

* update script to produce add graphics mixin

* add yuv example

* update ndimage with yuv stuff

* fixes

* yuv video working well with NDWidget

* cleanup

* `SelectionVector`, `HighlightSelector`, `VisibilitySelector`, `SelectorCollection` (#1038)

* start selection vector stuff, protocol

* highlight selector WIP

* fixes

* progress

* lut repeat

* highlight and visibility selectors working, selection vector working

* PlotArea checks for SelectorProtocol instead, move some stuff around

* selector collection, not yet tested

* cleanup

* bugfix for linear selector limits

* add example

* better append, remove

* cleanup

* basically rewrote entire ImageHighlightSelector

* black

* happy with iamge selectors

* toy multi session example

* correct mapping stuff

* better scalar/vector handling

* comments

* compute capabilities (#1040)

* allow setting texture usage directly

* ImageHighlightSelector, VisibilitySelector and ImageVisibilitySelector can handle 'None' as placeholders in the selection

* fix example

* comments

* better axes padding for tick labels, settable axis label (#1049)

* better axes padding for tick labels, settable axis label

* cleanup

* move axes to tools

* update

* move stuff around

* update docs

* update

* update

* use fully fledged async, `NDPositions` improvements (#1050)

* use fully fledged async

* better throttling

* torch.Tensor.tranpose() doesn't like tuples

* we need time-based throttling, but it can be gentler

* improvements

* improvements

* fixes

* x_range fix

* fix NDPandasProcessor

* fix

* HighlightSelector fix to append None

* cleanup better

* know ndg current dipslayed indices

* improve example

* docstrings, cleanup

* remove __array_ufunc__ from required attrs

* do not require __array__() to be implemented for ndwidget

* auto ref ranges

* fix imgui

* tear out NDTimeseries from NDPositions

* imgui refactor (#1066)

* start imgui window refactor

* update w.r.t. imgui changes

* imgui hlut colorbar stuff

* better focus logic

* imgui popup stuff

* update docs

* update examples, remove HistogramLUTTool

* update examples

* imgui menubar example

* update docs, tweaks

* docs

* doc fixes

* docs

* fix

* right click anywhere in colorbar/hlut window

* inf line, dashing, thin bool (#1064)

* Create partial_camera_linking.py (#1020)

* inf line, dashing, thin bool

* tests

* new screenshots

* Selection vector improve (#1061)

* Full selection vector implementation

* Includes some documentation at top of SelectionVector

* Minor typing fix in linear selector selection setter

* First working version with selection vector

* Reworks the logic for adding selectors, improves some documentation, adds partial instead of lambda functions, improves typing in highlight selector

* Fixes casting bug in the integer version of the code

* Update fastplotlib/graphics/selectors/_selection_vector.py

* Update fastplotlib/graphics/selectors/_selection_vector.py

* Removes unused init time parameter and also updates the typing on the default inverse mapping function to always return an integer

* Adds a nonneg check in selection vector selection setter

* Adds nonneg test for inverse handler

---------

Co-authored-by: Kushal Kolar <kushalkolar@gmail.com>

* Includes basic np dlpack function that is tested to work across jax a… (#1067)

* Includes basic np dlpack function that is tested to work across jax and torch

* delays dimension permutation for all code that uses ndprocessor

* Eliminates old comment

* Updates the numpy dep to be the min version that allows dlpack conversion across devices

* Includes code to update spatial dims indices whenever spatial dims is changed

* Moves the spatial dims indices computation to the read only property in the base class, updates docs, uses public property in the ndprocessor subclasses

* Filters for None values in the inv handler (#1073)

* bugfix after last PR

* alpha is material.opacity (#1074)

* clamp vmin, vmax in colorbar histogram LUT tool (#1076)

* Flat graphic features 2nd edition (#1072)

* refactor cmap and cmap_transform for positional graphics

* color mode stuff

* WIP

* more WIP

* better add_graphic autogen

* more progress

* mostly done refactoring positions graphics cmap stuff

* forgot to update mixin

* cmap_transform tweaks

* wip, JaggedArray

* mostly works, writing tests

* remove a print

* image collection examples

* fix

* feature inheritance in PositionsGraphic and cmap_range

* cmap handling

* cmap tweaks

* remove parse_cmap_values, rely on cmap lib

* fix example, remove unused line of code

* Image just uses cmap lib now too

* delete_ndgraphic()

* ndtimeseries cmap example

* steps for stacks

* ndtimeseries sets stack steps

* docstrings

* docstrings

* comments

* renames

* docstring

* fixes

* update tests/test_colors_buffer_manager.py

* update test_markers_buffer_manager.py

* update plot_helpers test

* update test_point_rotations_buffer_manager.py

* update test_positions_graphics.py

* update another test

* more tests

* update yet more tests

* remove unused

* infline tests

* collections tests

* updating examples, wip

* more examples updates

* more examples updates

* more example updates

* more example updates

* example and docstring

* docstring

* remove complex line collection slicing example, stick with real usecases

* better line stack example

* update example

* update example

* update link

* update more examples

* examples and fixes

* fix

* more fixes

* fix

* updates

* Fix

* update docs

* docs

* add image collection to docs conf.py

* update docs

* Ndw rename consistency (#1078)

* rename for consistency

* more consistency

* more

* final renames

* fix

* cursor fix

* missed renames

* pandas fix

* restore ImageWidget, auto-collapse NDWidget sliders UI if no slider dims and no appended UIs

* imagewidget stuff

* ImageVolumeGraphic args fix

* NDWSubplot dims check only for array-like

* collapsed property on ImaguiWindoW

* update iw examples

* colorbar fix

* lingering rename

* fix

* type

* clim_quantile for NDImage, other fixes

* public 'max_display_datapoints' property

* dw setter

* imgui right click for NDGraphics

* axes label tweaks

* remove unused zarr placeholder

* fix docstring

* config system (#1080)

* basic scaffold done

* inheritance

* done

* config works!

* config on graphics

* axes config

* full config implementation basically works

* fix

* mixins call Graphic construtors with kwargs nothing is positional

* print

* config presets

* comments, docstrings

* docstrings

* remove ConfigValue

* comments

* much better add graphics mixin using descriptors, examples, fix a test

* anotehr example

* GlobalConfig.to_dict()

* docs

* reset to default config after each screenshot test

* add_<graphics>() stub generator, fix maintain_aspect logic w.r.t. config stuff

* change so maintain_aspect can be tested better

* docstring

* reset config after running each docs gallery examle

* better example

* docs

* remove randon shit

* ndw stuff is all top level importable, move types to utils

* fix black

* fix import

* matplotlib migration docs

* wording

* uncommnet iw for docs conf.py

* update example

* update

* update

* temp skip nds_extras in docs

* temp comment out vis selector example

* fix usage args

* just make usage a kwarg to ImageGraphic

* update api docs stuff

* update example

* fix docstrings etc.

* type annots

* ndw import stuff

* docs for nds extras

* docs reqs

* nds extras

* ReferenceIndices.pop_dims

* graphics stubs

* fix for None data, remove delete_ndgraphic() for now

* collections stubs

* ndw docs, WIP

* ndw guide

* types fix

* better axes ticks text outline, WIP on ndwidget playback in docs, stubs

* ndw animate in docs works

* fix display_dims bug

* remove tranpose from ArrayProtocol

* bugfix, spatial func stuff

* ndw tests

* black

* more balck

* add example

* fixes

* fix

* update

* other CI fiel

* skip ndw and imgui test if not present

* garbage collection of graphics in imgui popup

* temp imgui ping

* fix

* update CI

* Update screenshots.yml

* update screenshots

* fix docstrings

* update test thresholds, remove line dashing from screenshot tests

* update api docs

* another example

* skip testing an example

* higher RMSE threshold on mac because I am so done with this shit

* Update ci.yml

* Update ci-pygfx-release.yml

---------

Co-authored-by: Amol Pasarkar <amolpasarkar@gmail.com>
Co-authored-by: Flynn <75346097+FlynnOConnell@users.noreply.github.com>
Co-authored-by: Caitlin Lewis <caitlin9165@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

Sponsor
SponsoredKunjungi sekarang
Promo