Skip to content

Commit

Permalink
Merge pull request #11 from MarcCote/ui_enh_slider
Browse files Browse the repository at this point in the history
ENH: Can now use value or ratio to set automatically the position of …
  • Loading branch information
ranveeraggarwal committed Apr 1, 2017
2 parents 371b6d9 + bc1989c commit eac3e05
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 43 deletions.
6 changes: 4 additions & 2 deletions dipy/viz/tests/test_ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,15 +257,17 @@ def test_ui_line_slider_2d(recording=False):
recording_filename = pjoin(DATA_DIR, filename + ".log.gz")
expected_events_counts_filename = pjoin(DATA_DIR, filename + ".pkl")

line_slider_2d_test = ui.LineSlider2D()
line_slider_2d_test = ui.LineSlider2D(initial_value=-2,
min_value=-5, max_value=5)
line_slider_2d_test.set_center((300, 300))

# Assign the counter callback to every possible event.
event_counter = EventCounter()
event_counter.monitor(line_slider_2d_test)

current_size = (600, 600)
show_manager = window.ShowManager(size=current_size, title="DIPY Line Slider")
show_manager = window.ShowManager(size=current_size,
title="DIPY Line Slider")

show_manager.ren.add(line_slider_2d_test)

Expand Down
117 changes: 76 additions & 41 deletions dipy/viz/ui.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from __future__ import division
from _warnings import warn

import numpy as np
Expand Down Expand Up @@ -1296,6 +1297,7 @@ def key_press(i_ren, obj, textbox_object):

class LineSlider2D(UI):
""" A 2D Line Slider.
A sliding ring on a line with a percentage indicator.
Currently supports:
Expand All @@ -1322,10 +1324,10 @@ class LineSlider2D(UI):
The text that shows percentage.
"""
def __init__(self, line_width=5, inner_radius=0,
outer_radius=10, center=(450, 300),
length=200, text_size=16):

def __init__(self, line_width=5, inner_radius=0, outer_radius=10,
center=(450, 300), length=200, initial_value=50,
min_value=0, max_value=100, text_size=16,
text_template="{value:.1f} ({ratio:.0%})"):
"""
Parameters
----------
Expand All @@ -1339,16 +1341,35 @@ def __init__(self, line_width=5, inner_radius=0,
Center of the slider.
length : int
Length of the slider.
initial_value : float
Initial value of the slider.
min_value : float
Minimum value of the slider.
max_value : float
Maximum value of the slider.
text_size : int
Size of the text to display alongside the slider (pt).
text_template : str, callable
If str, text template can contain one or multiple of the
replacement fields: `{value:}`, `{ratio:}`.
If callable, this instance of `:class:LineSlider2D` will be
passed as argument to the text template function.
"""
super(LineSlider2D, self).__init__()

self.length = length
self.min_value = min_value
self.max_value = max_value

self.text_template = text_template

self.line_width = line_width
self.center = center
self.current_state = center[0]
self.left_x_position = center[0] - length / 2
self.right_x_position = center[0] + length / 2
self._ratio = (self.current_state - self.left_x_position) / length

self.slider_line = None
self.slider_disk = None
Expand All @@ -1357,6 +1378,10 @@ def __init__(self, line_width=5, inner_radius=0,
self.build_actors(inner_radius=inner_radius,
outer_radius=outer_radius, text_size=text_size)

# Setting the disk position will also update everything.
self.value = initial_value
# self.update()

self.handle_events(None)

def build_actors(self, inner_radius, outer_radius, text_size):
Expand Down Expand Up @@ -1394,15 +1419,11 @@ def build_actors(self, inner_radius, outer_radius, text_size):
# Actor
self.slider_disk = vtk.vtkActor2D()
self.slider_disk.SetMapper(mapper)
self.slider_disk.SetPosition(self.center[0], self.center[1])
# /Slider Disk

# Slider Text
self.text = TextActor2D()

self.text.position = (self.left_x_position-50, self.center[1]-10)
percentage = self.calculate_percentage(current_val=int(self.current_state))
self.text.message = percentage
self.text.position = (self.left_x_position - 50, self.center[1] - 10)
self.text.font_size = text_size
# /Slider Text

Expand All @@ -1422,44 +1443,63 @@ def set_position(self, position):
"""
x_position = position[0]

if x_position < self.center[0] - self.length/2:
x_position = self.center[0] - self.length/2

if x_position > self.center[0] + self.length/2:
x_position = self.center[0] + self.length/2
self.slider_disk.SetPosition(x_position, self.center[1])

self.current_state = x_position
self.update()

def calculate_percentage(self, current_val):
""" Calculates the percentage to be displayed.
@property
def value(self):
return self._value

Parameters
----------
current_val : int
Absolute value of the disk's x position.
@value.setter
def value(self, value):
value_range = self.max_value - self.min_value
self.ratio = (value - self.min_value) / value_range

"""
percentage = int(((current_val-self.left_x_position)*100
)/(self.right_x_position-self.left_x_position))
if percentage < 0:
percentage = 0
if percentage > 100:
percentage = 100
@property
def ratio(self):
return self._ratio

return str(percentage) + "%"
@ratio.setter
def ratio(self, ratio):
position_x = self.left_x_position + ratio*self.length
self.set_position((position_x, None))

def set_percentage(self, current_val):
""" Sets text percentage.
def format_text(self):
""" Returns formatted text to display along the slider. """
if callable(self.text_template):
return self.text_template(self)

Parameters
----------
current_val : int
This is the x-position of the slider in the 2D coordinate space
and not the percentage on the base scale.
return self.text_template.format(ratio=self.ratio, value=self.value)

"""
self.current_state = current_val
percentage = self.calculate_percentage(current_val=current_val)
self.text.message = percentage
def update(self):
""" Updates the slider. """

# Compute the ratio determined by the position of the slider disk.
length = float(self.right_x_position - self.left_x_position)
assert length == self.length
self._ratio = (self.current_state - self.left_x_position) / length

# Compute the selected value considering min_value and max_value.
value_range = self.max_value - self.min_value
self._value = self.min_value + self.ratio*value_range

# Update text disk actor.
self.slider_disk.SetPosition(self.current_state, self.center[1])

# Update text.
text = self.format_text()
self.text.message = text
offset_x = 8 * len(text) / 2.
offset_y = 30
self.text.position = (self.current_state - offset_x,
self.center[1] - offset_y)

def set_center(self, position):
""" Sets the center of the slider to position.
Expand All @@ -1476,12 +1516,9 @@ def set_center(self, position):
x_change = position[0] - self.center[0]
self.current_state += x_change
self.center = position
self.set_position((self.current_state, self.center[1]))

self.left_x_position = position[0] - self.length / 2
self.right_x_position = position[0] + self.length / 2
self.text.position = (position[0] - self.length / 2 - 40, position[1] - 10)
self.set_percentage(int(self.current_state))
self.set_position((self.current_state, self.center[1]))

@staticmethod
def line_click_callback(i_ren, obj, slider):
Expand All @@ -1497,7 +1534,6 @@ def line_click_callback(i_ren, obj, slider):
"""
position = i_ren.event.position
slider.set_position(position)
slider.set_percentage(position[0])
i_ren.force_render()
i_ren.event.abort() # Stop propagating the event.

Expand Down Expand Up @@ -1529,7 +1565,6 @@ def disk_move_callback(i_ren, obj, slider):
"""
position = i_ren.event.position
slider.set_position(position)
slider.set_percentage(position[0])
i_ren.force_render()
i_ren.event.abort() # Stop propagating the event.

Expand Down

0 comments on commit eac3e05

Please sign in to comment.