GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Rectangle/bbox layouts in a Figure by kushalkolar · Pull Request #740 · fastplotlib/fastplotlib

Conversation

@kushalkolar

@kushalkolar kushalkolar commented Feb 27, 2025 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

Flexible rectangle/bbox layouts with resizable and draggable subplots!

Summary of this PR:

  1. Adds layouts._engine, which is a module for layout engines.
    • WindowLayout is a layout with subplots that can be moved and resized. A subplot is defined with a rect or extent.
    • GridLayout is a subclass of WindowLayout using fixed extents.
  2. Adds a Frame class. This contains the plane Mesh, resize_handle Point object, and the subplot title TextGraphic. It also manages the Subplot viewport rect and the dock viewport rects.
  3. Adds a RectManager which manages the Frame rect, makes it easy to manage rect, fractional rects, extent, etc. in one class. This allows Frame to use a rect or extent in absolute screen space or as fraction of the canvas.
  4. The Layout engine manages the subplot frames.

Users can specify rects or extents, in absolute pixels or as fractions of the canvas.

Future PRs will allow adding/removing a subplot and insets.

closes #315 closes #616

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@kushalkolar

kushalkolar commented Feb 27, 2025

Copy link
Copy Markdown
Member Author

One possible way to do automatic rectangle packing: https://github.com/laserson/squarify

@almarklein have you done something like this before? Allow bboxes for subplot viewport rects to be defined, and then when a viewport rect is resized all the other rects should adjust accordinlgy.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@almarklein

almarklein commented Feb 28, 2025

Copy link
Copy Markdown
Collaborator

One observation is that sometimes you want to position something in absolute pixels, and sometimes as a fraction of the parent's space. In visvis I therefore positioned widget-objects like this (taken from the visvis docs):

Each element (x,y,w,h) can be either: 1) The integer amount of pixels relative to the parent's position; 2) The fractional amount (float value between 0.0 and 1.0) of the parent's width or height. Each value can be negative. For x and y this simply means a negative offset from the parent's left and top. For the width and height the difference from the parent's full width/height is taken.

But this is a bit weird/confusing. Plus very often you want a relative position with some offset.

So in visvis2 (wip) I borrowed an approach from CSS, each item in the rect is a string e.g. "120px", "50%" or "50% - 20px". See https://github.com/pygfx/visvis2/blob/3e3e9d785c34d3170433c78595390f2304185df3/visvis2/_view.py#L33-L39 I've implemented something similar in pygfx/pygfx#954 (not sure if that will stay).

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@almarklein

almarklein commented Feb 28, 2025 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Collaborator

If you want more elaborate layout you should probably implement container objects that position their children in a specific way, similar to CSS flexbox and the like. But that'd be a lot more work (it's harder than it looks).

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@kushalkolar

kushalkolar commented Feb 28, 2025

Copy link
Copy Markdown
Member Author

Each element (x,y,w,h) can be either: 1) The integer amount of pixels relative to the parent's position; 2) The fractional amount (float value between 0.0 and 1.0) of the parent's width or height.

Ah I actually just did this! https://github.com/fastplotlib/fastplotlib/pull/740/files#diff-44de8531560bd88b7488ae543fbd3ff464555037e40be4d4d26b5fec8a17ace5R91-R96

I was wondering if you knew anything about auto-packing/docking algorithms. It's easy to find GUI toolkits that have it but I can't find any explanation of the backend algorithms anywhere.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@almarklein

almarklein commented Feb 28, 2025

Copy link
Copy Markdown
Collaborator

I was wondering if you knew anything about auto-packing/docking algorithms.

Ah. I did stuff like that in Flexx, but there I could leverage HTML/CSS. I remember that in the early days Jupyterlab used some custom layout engine, but I cannot find it anymore. I suspect they moved to using CSS Flexbox.

I would recommend looking at what Matplotlib does, e.g. here: https://github.com/matplotlib/matplotlib/blob/6fc8169112a42e3f6f55793a6b56159cd8ff69d7/lib/matplotlib/figure.py#L2677

A note of warning: widget layout can be a pretty deep rabbit-hole 😉

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@kushalkolar

kushalkolar commented Mar 1, 2025

Copy link
Copy Markdown
Member Author

Thanks! I think we'll just have a free-form drag & resize subplots on the canvas and block overlaps, and have another mode that uses a simple tiling algorithm maybe from squarify.

This answer on stackoverflow is very good: https://stackoverflow.com/a/306332 and this demo 😄 https://silentmatt.com/rectangle-intersection/

almarklein reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@kushalkolar

kushalkolar commented Mar 1, 2025 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member Author

Ok I've got the basics down! 🥳

Next step, integrate this mess into Figure 😂

flex_layout-2025-03-01_04.45.06.mp4

@almarklein Additional pointer control might be useful to implement in rendercanvas. For example here, the ability to lock the system cursor when the user can done an invalid movement, such as trying to overlap two rects. Instead of the rect stopping and the cursor continuing to move much further away, I think it would be nice to also have the cursor stop moving at the same time. I think cursor-locking behavior is what most people are used to for these types of things 🤔 . There's something about this which just feel slightly off and I think that it's this.

I found how it can be done in the browser: https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API#locked_state

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@kushalkolar

kushalkolar commented Mar 2, 2025

Copy link
Copy Markdown
Member Author

Idea:

Instead of putting all the layout management logic inside the Figure class we keep it as separate classes. Figure.layout_manager is an instance of a layout manager class. Right now we can have 3 different layout managers, Grid, freeform Flex (the implementation in the video above), and Squarify for the treemap once I figure out how to implement that.

Merge the implementation of the subplot Frame stuff into the Subplot class, I think this makes sense since it will then give all subplots the underlay plane, title, and resize handler. The rect and extent properties can be made read-only since we don't want users to manually change a subplot rect by directly addresses the subplot. Users can "request" changing a subplot rect via Figure.layout_manager if the type of LayoutManager supports it. For example, do not allow users to change the rect if the layout manager is a Grid since the rects are done automatically, but if it is a Flex layout we allow the user to request changing the rect. The request to change the rect is "denied" if the user passes in an invalid rect or a rect that would overlap with another subplot or cause other issues.

Basically to summarize:

We make:

Figure.layout_manager which is an instance of GridLayout, FlexLayout, or SquarifyLayout.

The LayoutManager manages pointer events which allow subplots to move or resize (if a flex layout). In a GridLayout it just auto-sets the subplot rects.

For FlexLayout we have FlexLayout.set_rect(subplot, rect: <x, y, w, h>) which is a user-facing function that allows them to manually define a rect. This function will raise if the user passes an invalid rect.
Similarly we have functions FlexLayout.set_extent(subplot, extent: <x0, x1, y0, y1>) for extent.

To the current Subplot class we add the stuff from Frame in the PR as it looks right now, to give it the plane Mesh, resize handler, subplot title text. Properties like rect, extent are read-only for the user. The LayoutManager however can set the subplot rect.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@clewis7

clewis7 commented Mar 2, 2025

Copy link
Copy Markdown
Member

I think layout manager sounds like a nice way to abstract, and then users can specify the layout they want via string when they instantiate a plot

fig = fpl.Figure(layout="grid")

I think by default, we would want to maintain the grid layout we have now.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@clewis7

clewis7 commented Mar 2, 2025

Copy link
Copy Markdown
Member

Also, would squarify be for making rectangular subplots of different sizes and tiling them all together?

If that's the case, could we not also use squarify for making our grids too? Fixed rectangles that get tiles together in a particular shape. Or maybe I am not understanding what the the squarify layout would be for

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@kushalkolar

kushalkolar commented Mar 2, 2025

Copy link
Copy Markdown
Member Author

Yes squarify is for tiling rects of diff sizes. I think it's overkill for a simple grid plot layout though so we should keep them separate.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@kushalkolar

kushalkolar commented Mar 2, 2025

Copy link
Copy Markdown
Member Author

In the flex and squarify layouts we can also have a swap method to swap subplot rects

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

This was referenced Mar 3, 2025
Alternative Plotting Backend hyperspy/hyperspy#3499
Open
Auto truncate and create ellipses if subplot rect is not wide enough for subplot title #746
Open
@almarklein

almarklein commented Mar 5, 2025

Copy link
Copy Markdown
Collaborator

Instead of the rect stopping and the cursor continuing to move much further away, I think it would be nice to also have the cursor stop moving at the same time.

I think we have an issue to be able to hide the cursor, which is also convenient for games. But that means you have to draw some sort of cursor yourself. Is that what you mean? AFAIK You cannot keep the OS's cursor and stop it from moving.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@kushalkolar

kushalkolar commented Mar 6, 2025

Copy link
Copy Markdown
Member Author

keep the OS's cursor and stop it from moving.

This is what I meant, I'll do another search and see if there is such a thing. Otherwise once we have our own cursors.

I just realized a grid layout can just be managed by a flex layout with fractional extents, this will make the implementations easier.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@kushalkolar

kushalkolar commented Mar 7, 2025 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member Author

so what's left is:

  1. layout.set_rect() or settable Subplot.rect that respects the overlap allow/not allowed mode
  2. mode to allow/not allow overlaps
    • if there are overlaps need to determine which subplot goes on top...
  3. cleanup implemention
rects-2025-03-08_02.43.12.mp4

@almarklein related to pygfx/pygfx#492, would it be possible to have an underlay render pass which also doesn't have a depth butter? For rendering the box frame of the subplot, subplot title and resize handles?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@kushalkolar
kushalkolar force-pushed the figure-rect-mode branch from a446428 to c11acab Compare March 8, 2025 06:08
@kushalkolar kushalkolar mentioned this pull request Mar 8, 2025
regenerate ground truths #747
Closed
@kushalkolar

kushalkolar commented Mar 8, 2025

Copy link
Copy Markdown
Member Author

We can allow one inset plot area within a subplot, arbitrary overlaps would be a mess with the screenspace camera and if a user wants many overlapping plots they should probably make them separate anyways

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@kushalkolar

kushalkolar commented Mar 9, 2025

Copy link
Copy Markdown
Member Author

Let's do insets and add/remove subplots and row/columms in another PR.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@kushalkolar
kushalkolar marked this pull request as ready for review March 9, 2025 08:19
@kushalkolar
kushalkolar requested a review from clewis7 as a code owner March 9, 2025 08:19
@kushalkolar kushalkolar mentioned this pull request Mar 10, 2025
docs via ssh #751
Merged
clewis7
clewis7 requested changes Mar 10, 2025
View reviewed changes
Comment thread examples/flex_layouts/extent_frac_layout.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread examples/flex_layouts/extent_layout.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread examples/flex_layouts/rect_frac_layout.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread examples/flex_layouts/rect_layout.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread fastplotlib/graphics/_base.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread fastplotlib/layouts/_engine.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread fastplotlib/layouts/_engine.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread fastplotlib/layouts/_engine.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread fastplotlib/layouts/_figure.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread fastplotlib/layouts/_frame.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

@kushalkolar

kushalkolar commented Mar 11, 2025

Copy link
Copy Markdown
Member Author

@almarklein would be great to get your thoughts on this PR! 😄

almarklein reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

almarklein
almarklein reviewed Mar 13, 2025
View reviewed changes
Comment thread fastplotlib/layouts/_engine.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

almarklein
almarklein reviewed Mar 13, 2025
View reviewed changes
Comment thread fastplotlib/layouts/_engine.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

almarklein
almarklein reviewed Mar 13, 2025
View reviewed changes
Comment thread fastplotlib/layouts/_engine.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

almarklein
almarklein reviewed Mar 13, 2025
View reviewed changes
Comment thread fastplotlib/layouts/_engine.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

kushalkolar and others added 19 commits March 14, 2025 18:16
@kushalkolar
comments, docstrings
a26e24a
@kushalkolar
update w.r.t. text changes
7aaeb0f
@clewis7 @kushalkolar
small typos
8e0e27a
# Conflicts:
#	fastplotlib/layouts/_engine.py
@clewis7 @kushalkolar
small typos
1264ec6
@kushalkolar @almarklein
Update fastplotlib/layouts/_engine.py
61ac3ff
Co-authored-by: Almar Klein <[email protected]>
@kushalkolar
rename FlexLayout -> WindowLayout
8b9a466
@kushalkolar
better check for imgui
996bbe7
@kushalkolar
imports
0bc9600
@kushalkolar
comments
0efd2b2
@kushalkolar
example tests files moved
302deb5
@kushalkolar
smaller canvas initial size for abs pixels until rendercanvs fix for …
db14148
…glfw
@kushalkolar
better error messages
0976aa4
@kushalkolar
update screenshots
6b318ee
@kushalkolar
update screenshots
5123f86
@kushalkolar
black
acff8cd
@kushalkolar
newer black really was an extra comma for some reason
89ee960
@kushalkolar
update example
1b69eaa
@kushalkolar
underline
bc4b634
@kushalkolar
docstring, better exception messages
f6263a3
@kushalkolar
kushalkolar force-pushed the figure-rect-mode branch from c7b4daf to f6263a3 Compare March 14, 2025 22:17
@github-actions

github-actions Bot commented Mar 14, 2025 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

📚 Docs preview built and uploaded! https://www.fastplotlib.org/ver/figure-rect-mode

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@kushalkolar

kushalkolar commented Mar 14, 2025

Copy link
Copy Markdown
Member Author

@clewis7 should be gtg! 🥳

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@kushalkolar

kushalkolar commented Mar 14, 2025

Copy link
Copy Markdown
Member Author

All tests using pygfx@main passing, docs built!

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

clewis7
clewis7 approved these changes Mar 15, 2025
View reviewed changes

@clewis7 clewis7 left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🥳 🥳 🥳

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@clewis7
clewis7 merged commit 20c9421 into main Mar 15, 2025
@clewis7
clewis7 deleted the figure-rect-mode branch March 15, 2025 20:08
This was referenced Mar 23, 2025
set_title bug #732
Closed
Figure names should take flat list and reshape it #541
Closed
@kushalkolar kushalkolar mentioned this pull request Mar 27, 2025
pointer_leave events pick_info always comes from the Frame mesh plane #777
Open
@kushalkolar kushalkolar mentioned this pull request May 15, 2025
Fix rect manager #820
Merged
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@almarklein almarklein almarklein left review comments
@clewis7 clewis7 clewis7 approved these changes

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

imgui subplot toolbar should go below subplot "bottom" dock Customizable Figure layouts

Uh oh!

There was an error while loading. Please reload this page.

3 participants

@kushalkolar @almarklein @clewis7
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.