Skip to content

Conversation

@kushalkolar
Copy link
Member

@kushalkolar kushalkolar commented Jan 13, 2026

closes #869

Replace positions related buffers when the user sets all the data with a new array that has a different number of positions (vertices) than the existing buffer. Example, user sets all line or scatter data, line.data = <bigger or smaller array>.

Implemented in all BufferManager subclasses, and the image TextureArrays

  • VertexPositions
  • VertexColors
  • VertexRotations
  • VertexPointSizes
  • VertexMarkers
  • MeshIndices, gets it automatically from parent class VertexPositions
  • images and volumes - create an entirely new TextureArray if setting all the data with a new image that has different dims
  • removes isolated_buffer, OOC rendering is the better way to handle very large data
  • make uniforms the default for all graphics, per-vertex properties have to be set explicitly, I think it makes things more intuitive.
  • test things manually for now, can make proper test later
  • test garbage collection

Slicing and setting data, i.e. graphic.data[<slice>] = <array> is unchanged. New buffers are created only when the entire data is set with new data that needs a bigger or smaller buffer.

@kushalkolar
Copy link
Member Author

OK I got the basics down for lines. One caveat is that now there's no check to make sure that the buffer sizes match for data and colors for example.

Consider this:

lg = subplot.add_line(np.random.rand(100))
lg.data = np.random.rand(200)

Now the last 100 line points are just black since they're not defined. A user has to explicitly set the colors of the new vertices that extend beyond the previously defined buffer.

lg.colors = ["w"] * 200

Or they can use a uniform color for things like this.

@kushalkolar
Copy link
Member Author

kushalkolar commented Jan 13, 2026

ok for images I think easiest way is to create new world objects 🤔

EDIT: Yup this will be fine, I was initially worried that we'd have to re-add event handlers if we create a new world object, but I don't think that's necessary since ImageGraphic and ImageVolumeGraphic use a pygfx.Group as the world object, so we can just clear the group and add new image tiles.

EDIT again: Just tested with image click events, if an event handler is added to the graphic then when new tiles are created the graphic is still responsive to those events because it's the pygfx.Group that is handling the events and not the individual image tiles.

@kushalkolar kushalkolar marked this pull request as ready for review January 13, 2026 07:27
@kushalkolar kushalkolar requested a review from clewis7 as a code owner January 13, 2026 07:27
@kushalkolar
Copy link
Member Author

@clewis7 would like to get your review before I do the gc tests

@github-actions
Copy link

github-actions bot commented Jan 13, 2026

📚 Docs preview built and uploaded! https://www.fastplotlib.org/ver/replaceable-buffers

@kushalkolar
Copy link
Member Author

I think we should make uniforms the default for all graphics 🤔.

Also good time to start a "performance tips" section of the docs. Replacing the buffer has a huge performance hit so you don't want do it all the time.

@kushalkolar
Copy link
Member Author

kushalkolar commented Jan 13, 2026

I found a memory leak, if old_buffer._wgpu_object.destroy() is not called then it lingers on in GPU VRAM even if the Binding object no longer exists.

Posted on pygfx: pygfx/pygfx#1264

For now I implemented manually destroying the GPUBuffer when it's replaced.

@kushalkolar
Copy link
Member Author

kushalkolar commented Jan 14, 2026

@clewis7 what do you think about:

For lines, default is:
uniform_colors = True

For scatters, default is:
uniform_colors = False

I think independent scatter colors is a more common usecase than lines. We can auto-determine it in the future based on the colors and cmap arg but I'll do that in the future.

EDIT: But then the API is inconsistent between lines and scatters :/

@clewis7
Copy link
Member

clewis7 commented Jan 14, 2026

OK I got the basics down for lines. One caveat is that now there's no check to make sure that the buffer sizes match for data and colors for example.

Consider this:

lg = subplot.add_line(np.random.rand(100))
lg.data = np.random.rand(200)

Now the last 100 line points are just black since they're not defined. A user has to explicitly set the colors of the new vertices that extend beyond the previously defined buffer.

lg.colors = ["w"] * 200

Or they can use a uniform color for things like this.

I think this behavior is confusing. Perhaps it is better to just by default take the current color scheme and extend it to the new or fewer points.

@clewis7
Copy link
Member

clewis7 commented Jan 14, 2026

@clewis7 what do you think about:

For lines, default is: uniform_colors = True

For scatters, default is: uniform_colors = False

I think independent scatter colors is a more common usecase than lines. We can auto-determine it in the future based on the colors and cmap arg but I'll do that in the future.

EDIT: But then the API is inconsistent between lines and scatters :/

Hmmm, I do agree that scatters are more likley to have individual colors. How much a performance reduction is it if you make the lines also have uniform_buffer=True as the default??

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.

Create a new buffer if necessary when setting an existing Graphic

3 participants