# How to get the clicked markup node in the 3D view?

**URL:** <https://discourse.slicer.org/t/how-to-get-the-clicked-markup-node-in-the-3d-view/46937>\
**Category:** Support\
**Tags:** python, markups\
**Created:** [May 6, 2026, 2:34pm UTC](https://discourse.slicer.org/t/how-to-get-the-clicked-markup-node-in-the-3d-view/46937 "2026-05-06T14:34:56Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![NogginBops](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/nogginbops/32/82314_2.png) [@NogginBops](https://discourse.slicer.org/u/NogginBops)\
**Post date:** [May 6, 2026, 2:34pm UTC](https://discourse.slicer.org/t/how-to-get-the-clicked-markup-node-in-the-3d-view/46937/1 "2026-05-06T14:34:56Z")

</div>

Hi,

I’m interested in knowing what node is selected/hovered by the mouse when the left mouse button is pressed.  
I’ve tried using the scene interactor and trying to use the vtk picker, but I’m not really able to get it to work.  
I’ve also tried adding observers to my markup objects in the hope that they would receive the left mouse button event, but instead the display node receives NoEvent when I press the left mouse button which is not very useful.

So I’m wondering, how do I get the node that was clicked on in the 3D view. I know it must be possible as Slicer is able to highlight the markup object when the mouse is hovered over them, but I can’t really find the code that does that.

Thanks in advance!

---

<div class="post-metadata">

**Author:** ![pieper](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/pieper/32/8_2.png) [@pieper](https://discourse.slicer.org/u/pieper)\
**Post date:** [May 6, 2026, 5:01pm UTC](https://discourse.slicer.org/t/how-to-get-the-clicked-markup-node-in-the-3d-view/46937/2 "2026-05-06T17:01:09Z")

</div>

Here’s what I got from [the slicer-skill](https://discourse.slicer.org/t/new-slicer-skill-ai-tool/46243).

> 🤖 This post contains AI-generated content.

Here’s a reply you can post to the forum:

* * *

The piece you’re missing is that Slicer’s 3D view doesn’t really hand raw mouse events to MRML nodes — it routes them through _displayable managers_, which is also why your observers on the display nodes never see anything useful. The good news is that the model displayable manager already exposes the picker you want, and there’s an official snippet for it in the Script Repository under “Get 3D coordinates from 2D display coordinates” (gui.md).

Wire it up to the 3D view’s interactor and you get the clicked node directly:

```auto
import slicer, qt, vtk

threeDView = slicer.app.layoutManager().threeDWidget(0).threeDView()
viewNode = threeDView.mrmlViewNode()
modelDM = slicer.app.applicationLogic().GetViewDisplayableManagerByClassName(
    viewNode, "vtkMRMLModelDisplayableManager")

def onLeftClick(caller, event):
    x, y = caller.GetEventPosition()
    # VTK's y is bottom-up; the displayable manager's Pick expects that, so no flip needed.
    if modelDM.Pick(x, y) and modelDM.GetPickedNodeID():
        nodeID = modelDM.GetPickedNodeID() # this is the *display* node ID
        displayNode = slicer.mrmlScene.GetNodeByID(nodeID)
        dataNode = displayNode.GetDisplayableNode() if displayNode else None
        ras = modelDM.GetPickedRAS()
        cellID = modelDM.GetPickedCellID()
        print(f"Clicked {dataNode.GetName() if dataNode else '(none)'} "
              f"at RAS={tuple(ras)} cell={cellID}")

interactor = threeDView.interactor()
tag = interactor.AddObserver(vtk.vtkCommand.LeftButtonPressEvent, onLeftClick, 0.0)
# To remove later: interactor.RemoveObserver(tag)

```

A couple of gotchas that probably bit you:

- `GetPickedNodeID()` returns the **display node ID** , not the data node ID. Call `GetDisplayableNode()` on it to get the model/markup/segmentation node.
- A priority of `0.0` (or negative) means you observe _after_ the standard interactor style, so you don’t break camera rotation. If you want to suppress default behavior on a hit, raise the priority and call `caller.AbortFlagOn()`.
- `vtkMRMLModelDisplayableManager.Pick()` only finds things rendered as polydata (models, segmentation surfaces, markup glyphs). Volume rendering and slice planes need different displayable managers.

For **hover** (highlight as the cursor moves), swap `LeftButtonPressEvent` for `vtk.vtkCommand.MouseMoveEvent`. Be sure to throttle — `Pick()` on every move event in a heavy scene will hurt FPS; a `qt.QTimer` with `setSingleShot(True)` reset on each move is the usual trick.

If you also need this for markups specifically (control-point hover highlight), that’s done inside `vtkMRMLMarkupsDisplayableManager` via the `CanProcessInteractionEvent` / `ProcessInteractionEvent` API on `vtkMRMLAbstractDisplayableManager` — it’s the modern path for writing a custom interaction, but for “what node did the user click?” the snippet above is the simplest answer.

---

<div class="post-metadata">

**Author:** ![NogginBops](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/nogginbops/32/82314_2.png) [@NogginBops](https://discourse.slicer.org/u/NogginBops)\
**Post date:** [May 7, 2026, 2:07pm UTC](https://discourse.slicer.org/t/how-to-get-the-clicked-markup-node-in-the-3d-view/46937/3 "2026-05-07T14:07:19Z")

</div>

Thanks for the reply.

However it does seem that this doesn’t actually help me as the `vtkMRMLModelDisplayableManager` displayable manager doesn’t expose markups. I’m able to detect clicks on other model geometry, but not markups (with the caveat that the coordinate system for picking and mouse coordinates are flipped so you need to flip the y axis of the mouse position before calling `modelDM.Pick()`).

So I decided to look at `vtkMRMLMarkupsDisplayableManager` but it seems like that doesn’t expose any functions related to picking. Looking at the code for `vtkMRMLMarkupsDisplayableManager` I can see that it does have internal code for picking (`vtkMRMLMarkupsDisplayableManager::FindClosestWidget`) but nothing that is publicly exposed.

Is there any workaround for this or should I open an issue on github about this?

---

<div class="post-metadata">

**Author:** ![pieper](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/pieper/32/8_2.png) [@pieper](https://discourse.slicer.org/u/pieper)\
**Post date:** [May 7, 2026, 2:15pm UTC](https://discourse.slicer.org/t/how-to-get-the-clicked-markup-node-in-the-3d-view/46937/4 "2026-05-07T14:15:07Z")

</div>

I haven’t done that in a while, but this code may help:

[https://github.com/Slicer/LandmarkRegistration/blob/master/RegistrationLib/Landmarks.py](https://github.com/Slicer/LandmarkRegistration/blob/master/RegistrationLib/Landmarks.py)

---

<div class="post-metadata">

**Author:** ![NogginBops](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/nogginbops/32/82314_2.png) [@NogginBops](https://discourse.slicer.org/u/NogginBops)\
**Post date:** [May 7, 2026, 2:31pm UTC](https://discourse.slicer.org/t/how-to-get-the-clicked-markup-node-in-the-3d-view/46937/5 "2026-05-07T14:31:35Z")

</div>

I don’t seem to be able to find any relevant code in the link you sent. The closest is some code that use the `PointModifiedEvent` and `PointEndInteractionEvent` events which I can’t use.

I want to be able to left click on a region of interest and have my plugin get the region of interest that was clicked. I initially looked for relevant events on `vtkMRMLROINode` and `vtkMRMLROIDisplayNode` but they don’t expose any events, so that is why I look in the direction of pickers and the like.
