Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork8.1k
Description
Problem
Matplotlib’s currentRectangleSelector only supports axis-aligned rectangles. Many domains (image annotation, computer vision, OCR, remote sensing, microscopy, UI layout tools) needoriented/rotated bounding boxes with interactiveresize/rotate/translate. Today, users hack around this withPolygonSelector (4 points) or custom event handlers, which leads to inconsistent UX, no angle snapping, and a lot of duplicated code.
Proposed solution
Introduce a new widget:OrientedRectangleSelector, an interactive selector that behaves likeRectangleSelector but supportsarbitrary rotation. It provides:
- Corner and edge handles for resizing (with optional aspect-ratio lock).
- A rotation handle with optionalangle snapping.
- Dragging the center to translate.
- Live callbacks during interaction and a final
onselecton release. - Visual feedback (cursors, handles) and optional blitting for performance.
This mirrors the mental model ofRectangleSelector while adding rotation.
High-level API
frommatplotlib.widgetsimportOrientedRectangleSelectorors=OrientedRectangleSelector(ax,onselect=None,# called on mouse release with final paramsonmove_callback=None,# called during interaction with live params*,useblit=False,button=None,minspanx=0,minspany=0,spancoords="data",maxdist=10,# handle hit test (px)snap_angle=True,angle_snap_increment=1.0,# degreesmaintain_aspect_ratio=False,min_size=0.02,# in data unitsinitial_center=(0.5,0.5),initial_width=0.3,initial_height=0.2,initial_angle=0.0,# degreeshandle_props=None,# dict for corner/edge/rotate/center stylesline_props=None,# rectangle edge propsstate_modifier_keys=None,# {'rotate': 'shift', 'aspect_ratio': 'control', 'snap': 'alt'})
Returned/Callback params
{"center":np.ndarray([cx,cy]),"width":float,"height":float,"angle":float,# degrees"corners":np.ndarray(shape=(4,2)),# BL, BR, TR, TL in data coords"area":float}Programmatic control
ors.set_rectangle(center=(x,y),width=w,height=h,angle=a)params=ors.get_rectangle_params()ors.update_properties({"snap_angle":False,"min_size":0.05})
Example usage
fig,ax=plt.subplots()ax.imshow(img,cmap="gray")defonmove(params):# live feedback (e.g., show crop/metrics)passdefondone(params):print(params["center"],params["width"],params["height"],params["angle"])ors=OrientedRectangleSelector(ax,onselect=ondone,onmove_callback=onmove,snap_angle=True,angle_snap_increment=1.0)plt.show()
UX details
- Handles: 4 corners, 4 edge midpoints, 1 rotation handle, 1 center “+”.
- Cursors: move/resize/rotate cursors based on hover target.
- Snapping: configurable granularity (default 1°; can be 15° etc.).
- Constraints: configurable minimum size; easy to add “keep inside axes” later.

Implementation notes
A reference implementation is attached (ready to adapt to Matplotlib conventions):
- Uses a
Rectanglepatch drawn at the origin and transformed viaAffine2D(rotate + translate) for numerical stability. - Hit-testing in data space; handle detection uses pixel tolerance.
- Optional blitting for smooth interaction.
- Clean separation of interaction modes: translate, rotate, resize-corner, resize-edge.
- Public methods mirror
RectangleSelectorwhere possible; extras are additive.
Backward compatibility
No breakage. New widget, opt-in. Naming followsRectangleSelector. Consider adding an aliasRotatedRectangleSelector for searchability.
Performance
Blitting support keeps interaction smooth; complexity is similar to existing selectors. Handle count is fixed (small); transform math is minimal.
Testing
- Unit tests for:
- Local↔world transform correctness.
- Angle snapping correctness.
- Aspect-ratio lock.
- Min-size constraint.
- Image tests for handle placement and rotation rendering.
- Event simulation tests (press/motion/release) to validate callbacks.
Documentation
- User guide with interactive examples.
- API reference with detailed parameter descriptions.
- Changelog for version updates.
[I am ready to do that!]
Future extensions (non-blocking)
- Constrain rectangle within axes/view limits.
- Keyboard nudging & precise numeric entry.
- Multi-rectangle manager as a helper (selection, add/remove).
- Snapping to guide lines / other artists.
Note: I have more ideas for this widget and ready to take full ownership and I can implement them.