Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
FSL
fsleyes
fsleyes
Commits
a7c5d5f5
Commit
a7c5d5f5
authored
Apr 29, 2022
by
Paul McCarthy
🚵
Browse files
ENH: New ability to show cursor coordinates in ortho view
parent
efbfd4c6
Changes
3
Hide whitespace changes
Inline
Side-by-side
fsleyes/gl/ortholabels.py
View file @
a7c5d5f5
...
...
@@ -5,29 +5,41 @@
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
"""This module provides the :class:`OrthoLabels` class, which manages
anatomical
orient
ation labels for an :class:`.OrthoPanel`.
anatomical
and loc
ation labels for an :class:`.OrthoPanel`.
This logic is independent from the :class:`.OrthoPanel` so it can be used in
off-screen rendering (see :mod:`.render`).
"""
import
fsl.data.image
as
fslimage
import
fsl.data.constants
as
constants
class
OrthoLabels
:
"""The ``OrthoLabels`` class manages anatomical orientation labels which
are displayed on a set of three :class:`.SliceCanvas` instances, one for
each plane in the display coordinate system, typically within an
:class:`.OrthoPanel`.
"""The ``OrthoLabels`` class manages anatomical orientation and location
labels which are displayed on a set of three :class:`.SliceCanvas`
instances, one for each plane in the display coordinate system, typically
within an :class:`.OrthoPanel`.
The ``OrthoLabels`` class uses :class:`.annotations.Text` annotations,
showing the user the anatomical orientation of the display on each
canvas. These labels are only shown if the currently selected overlay (as
dicated by the :attr:`.DisplayContext.selectedOverlay` property) is a
:class:`.Image` instance, **or** the
:meth:`.DisplayOpts.referenceImage` property for the currently selected
overlay returns an :class:`.Image` instance.
showing the user:
- the anatomical orientation of the display on each canvas.
- the current location on a selected csanvas.
Anatomical labels can be toggled on and off via the
:attr:`.OrthoOpts.showLabels` property, and location via the
:attr:`.OrthoOpts.showLocation` priperty.
Anatomical labels are only shown if the currently selected overlay (as
dictated by the :attr:`.DisplayContext.selectedOverlay` property) is a
:class:`.Image` instance, **or** the :meth:`.DisplayOpts.referenceImage`
property for the currently selected overlay returns an :class:`.Image`
instance.
If the currently selected overlay is an :class:`.Image`, both voxel and
world coordinates are shown. Otherwise only world coordinates are shown.
"""
...
...
@@ -53,14 +65,14 @@ class OrthoLabels:
# labels is a list of dicts, one
# for each canvas, containing Text
# annotations to show anatomical
# orientation
# orientation
and location
annots
=
[{}
for
c
in
canvases
]
self
.
__canvases
=
canvases
self
.
__annots
=
annots
# Create the Text annotations
for
side
in
(
'left'
,
'right'
,
'top'
,
'bottom'
):
for
side
in
(
'left'
,
'right'
,
'top'
,
'bottom'
,
'location'
):
for
canvas
,
cannots
in
zip
(
canvases
,
annots
):
annot
=
canvas
.
getAnnotations
()
cannots
[
side
]
=
annot
.
text
(
''
,
0
,
0
,
hold
=
True
)
...
...
@@ -68,31 +80,36 @@ class OrthoLabels:
# Initialise the display properties
# of each Text annotation
for
cannots
in
annots
:
cannots
[
'left'
]
.
halign
=
'left'
cannots
[
'right'
]
.
halign
=
'right'
cannots
[
'top'
]
.
halign
=
'centre'
cannots
[
'bottom'
].
halign
=
'centre'
cannots
[
'left'
]
.
valign
=
'centre'
cannots
[
'right'
]
.
valign
=
'centre'
cannots
[
'top'
]
.
valign
=
'top'
cannots
[
'bottom'
].
valign
=
'bottom'
cannots
[
'left'
]
.
x
=
0.0
cannots
[
'left'
]
.
y
=
0.5
cannots
[
'right'
]
.
x
=
1.0
cannots
[
'right'
]
.
y
=
0.5
cannots
[
'bottom'
].
x
=
0.5
cannots
[
'bottom'
].
y
=
0.0
cannots
[
'top'
]
.
x
=
0.5
cannots
[
'top'
]
.
y
=
1.0
cannots
[
'left'
]
.
halign
=
'left'
cannots
[
'right'
]
.
halign
=
'right'
cannots
[
'top'
]
.
halign
=
'centre'
cannots
[
'bottom'
]
.
halign
=
'centre'
cannots
[
'location'
].
halign
=
'left'
cannots
[
'left'
]
.
valign
=
'centre'
cannots
[
'right'
]
.
valign
=
'centre'
cannots
[
'top'
]
.
valign
=
'top'
cannots
[
'bottom'
]
.
valign
=
'bottom'
cannots
[
'location'
].
valign
=
'top'
cannots
[
'left'
]
.
x
=
0.0
cannots
[
'left'
]
.
y
=
0.5
cannots
[
'right'
]
.
x
=
1.0
cannots
[
'right'
]
.
y
=
0.5
cannots
[
'bottom'
].
x
=
0.5
cannots
[
'bottom'
]
.
y
=
0.0
cannots
[
'top'
]
.
x
=
0.5
cannots
[
'top'
]
.
y
=
1.0
cannots
[
'location'
].
x
=
0.0
cannots
[
'location'
].
y
=
1.0
# Keep cannots 5 pixels away
# from the canvas edges
cannots
[
'left'
]
.
off
=
(
5
,
0
)
cannots
[
'right'
]
.
off
=
(
-
5
,
0
)
cannots
[
'top'
]
.
off
=
(
0
,
-
5
)
cannots
[
'bottom'
].
off
=
(
0
,
5
)
cannots
[
'left'
]
.
off
=
(
5
,
0
)
cannots
[
'right'
]
.
off
=
(
-
5
,
0
)
cannots
[
'top'
]
.
off
=
(
0
,
-
5
)
cannots
[
'bottom'
]
.
off
=
(
0
,
5
)
cannots
[
'location'
].
off
=
(
5
,
-
5
)
# Add listeners to properties
# that need to trigger a label
...
...
@@ -104,22 +121,26 @@ class OrthoLabels:
# a panel refresh occurs (where
# the latter is managed by the
# OrthoPanel).
refresh
Args
=
{
label
Args
=
{
'name'
:
name
,
'callback'
:
self
.
__refreshLabels
,
'immediate'
:
True
}
locationArgs
=
dict
(
labelArgs
)
locationArgs
[
'callback'
]
=
self
.
__refreshLocation
for
c
in
canvases
:
c
.
opts
.
addListener
(
'invertX'
,
**
refreshArgs
)
c
.
opts
.
addListener
(
'invertY'
,
**
refreshArgs
)
orthoOpts
.
addListener
(
'showLabels'
,
**
refreshArgs
)
orthoOpts
.
addListener
(
'labelSize'
,
**
refreshArgs
)
orthoOpts
.
addListener
(
'fgColour'
,
**
refreshArgs
)
displayCtx
.
addListener
(
'selectedOverlay'
,
**
refreshArgs
)
displayCtx
.
addListener
(
'displaySpace'
,
**
refreshArgs
)
displayCtx
.
addListener
(
'radioOrientation'
,
**
refreshArgs
)
c
.
opts
.
addListener
(
'invertX'
,
**
labelArgs
)
c
.
opts
.
addListener
(
'invertY'
,
**
labelArgs
)
orthoOpts
.
addListener
(
'showLabels'
,
**
labelArgs
)
orthoOpts
.
addListener
(
'labelSize'
,
**
labelArgs
)
orthoOpts
.
addListener
(
'fgColour'
,
**
labelArgs
)
displayCtx
.
addListener
(
'selectedOverlay'
,
**
labelArgs
)
displayCtx
.
addListener
(
'displaySpace'
,
**
labelArgs
)
displayCtx
.
addListener
(
'radioOrientation'
,
**
labelArgs
)
orthoOpts
.
addListener
(
'showLocation'
,
**
locationArgs
)
displayCtx
.
addListener
(
'location'
,
**
locationArgs
)
overlayList
.
addListener
(
'overlays'
,
name
,
self
.
__overlayListChanged
)
...
...
@@ -142,11 +163,13 @@ class OrthoLabels:
self
.
__annots
=
None
orthoOpts
.
removeListener
(
'showLabels'
,
name
)
orthoOpts
.
removeListener
(
'showLocation'
,
name
)
orthoOpts
.
removeListener
(
'labelSize'
,
name
)
orthoOpts
.
removeListener
(
'fgColour'
,
name
)
displayCtx
.
removeListener
(
'selectedOverlay'
,
name
)
displayCtx
.
removeListener
(
'displaySpace'
,
name
)
displayCtx
.
removeListener
(
'radioOrientation'
,
name
)
displayCtx
.
removeListener
(
'location'
,
name
)
overlayList
.
removeListener
(
'overlays'
,
name
)
for
c
in
canvases
:
...
...
@@ -166,9 +189,12 @@ class OrthoLabels:
text
.
destroy
()
def
refreshLabels
(
self
):
"""Forces the label annotations to be refreshed."""
def
refreshLabels
(
self
,
*
a
):
"""Forces the orientation and location annotations to be refreshed.
All arguments are ignored.
"""
self
.
__refreshLabels
()
self
.
__refreshLocation
()
def
__overlayListChanged
(
self
,
*
a
):
...
...
@@ -196,6 +222,41 @@ class OrthoLabels:
# it here.
if
len
(
self
.
__overlayList
)
in
(
0
,
1
):
self
.
__refreshLabels
()
self
.
__refreshLocation
()
def
__refreshLocation
(
self
,
*
a
):
"""
"""
displayCtx
=
self
.
__displayCtx
sopts
=
self
.
__orthoOpts
annots
=
self
.
__annots
overlay
=
displayCtx
.
getSelectedOverlay
()
if
overlay
is
None
:
return
for
cannots
,
canvas
in
zip
(
annots
,
'XYZ'
):
showLoc
=
sopts
.
showLocation
==
canvas
cannots
[
'location'
].
enabled
=
showLoc
if
sopts
.
showLocation
==
'no'
:
return
opts
=
displayCtx
.
getOpts
(
overlay
)
if
sopts
.
showLocation
==
'X'
:
locLbl
=
annots
[
0
][
'location'
]
elif
sopts
.
showLocation
==
'Y'
:
locLbl
=
annots
[
1
][
'location'
]
elif
sopts
.
showLocation
==
'Z'
:
locLbl
=
annots
[
2
][
'location'
]
wx
,
wy
,
wz
=
displayCtx
.
worldLocation
loc
=
f
'
{
wx
:
0.2
f
}
{
wy
:
0.2
f
}
{
wz
:
0.2
f
}
'
if
isinstance
(
overlay
,
fslimage
.
Nifti
):
vx
,
vy
,
vz
=
opts
.
getVoxel
()
loc
=
f
'
{
loc
}
\n
{
vx
}
{
vy
}
{
vz
}
'
locLbl
.
fontSize
=
sopts
.
labelSize
locLbl
.
colour
=
sopts
.
fgColour
locLbl
.
text
=
loc
def
__refreshLabels
(
self
,
*
a
):
...
...
@@ -205,16 +266,18 @@ class OrthoLabels:
displayCtx
=
self
.
__displayCtx
sopts
=
self
.
__orthoOpts
canvases
=
self
.
__canvases
annots
=
self
.
__annots
overlay
=
displayCtx
.
getSelectedOverlay
()
showLabels
=
sopts
.
showLabels
and
(
overlay
is
not
None
)
canvases
=
self
.
__canvases
annots
=
self
.
__annots
for
cannots
,
canvas
in
zip
(
annots
,
'XYZ'
):
cannots
[
'left'
]
.
enabled
=
showLabels
cannots
[
'right'
]
.
enabled
=
showLabels
cannots
[
'top'
]
.
enabled
=
showLabels
cannots
[
'bottom'
]
.
enabled
=
showLabels
for
cannots
in
annots
:
for
text
in
cannots
.
values
():
text
.
enabled
=
sopts
.
showLabels
and
(
overlay
is
not
None
)
if
not
sopts
.
showLabels
or
overlay
is
None
:
if
not
showLabels
:
return
opts
=
displayCtx
.
getOpts
(
overlay
)
...
...
@@ -224,9 +287,8 @@ class OrthoLabels:
labels
,
orients
=
opts
.
getLabels
()
xlo
,
ylo
,
zlo
,
xhi
,
yhi
,
zhi
=
labels
vertOrient
=
len
(
xlo
)
>
1
fontSize
=
sopts
.
labelSize
fgColour
=
tuple
(
sopts
.
fgColour
)
fontSize
=
sopts
.
labelSize
fgColour
=
tuple
(
sopts
.
fgColour
)
# If any axis orientation is unknown, make
# the foreground colour red, to highlight
...
...
fsleyes/gl/text.py
View file @
a7c5d5f5
...
...
@@ -223,6 +223,7 @@ class Text:
fontSize
=
self
.
fontSize
,
fgColour
=
self
.
colour
,
bgColour
=
self
.
bgColour
,
halign
=
self
.
halign
,
alpha
=
self
.
alpha
)
bmp
=
np
.
flipud
(
bmp
).
transpose
([
2
,
1
,
0
])
self
.
__bitmap
=
bmp
...
...
fsleyes/views/orthopanel.py
View file @
a7c5d5f5
...
...
@@ -316,9 +316,10 @@ class OrthoPanel(canvaspanel.CanvasPanel):
def
refresh
(
*
a
):
self
.
Refresh
()
sceneOpts
.
addListener
(
'labelSize'
,
name
,
refresh
,
weak
=
False
)
sceneOpts
.
addListener
(
'fgColour'
,
name
,
refresh
,
weak
=
False
)
sceneOpts
.
addListener
(
'showLabels'
,
name
,
refresh
,
weak
=
False
)
sceneOpts
.
addListener
(
'labelSize'
,
name
,
refresh
,
weak
=
False
)
sceneOpts
.
addListener
(
'fgColour'
,
name
,
refresh
,
weak
=
False
)
sceneOpts
.
addListener
(
'showLabels'
,
name
,
refresh
,
weak
=
False
)
sceneOpts
.
addListener
(
'showLocation'
,
name
,
refresh
,
weak
=
False
)
# The lastFocusedCanvas method allows
# a ref to the most recently focused
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment