Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Player value_throttled #3756

Merged
merged 1 commit into from
Aug 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions examples/reference/widgets/DiscretePlayer.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,16 @@
"\n",
"* **``direction``** (int): Current play direction of the Player (-1: playing in reverse,\n",
"0: paused, 1: playing).\n",
"* **``interval``** (int): Interval in milliseconds between updates\n",
"* **``loop_policy``** (str): Looping policy; must be one of 'once', 'loop', or 'reflect'\n",
"* **``options``** (list or dict): A list or dictionary of options to select from\n",
"* **``value``** (object): The current value; must be one of the option values\n",
"* **``value_throttled``** (object): The current value throttled until mouseup (when selected using slider)\n",
"\n",
"##### Display\n",
"\n",
"* **``disabled``** (boolean): Whether the widget is editable\n",
"* **``interval``** (int): Interval in milliseconds between updates\n",
"* **``name``** (str): The title of the widget\n",
"* **``loop_policy``** (str): Looping policy; must be one of 'once', 'loop', or 'reflect'\n",
"* **``show_loop_controls``** (boolean): Whether radio buttons allowing to switch between loop policies options are shown\n",
"\n",
"___"
Expand Down
7 changes: 4 additions & 3 deletions examples/reference/widgets/Player.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,18 @@
"\n",
"* **``direction``** (int): Current play direction of the Player (-1: playing in reverse,\n",
"0: paused, 1: playing).\n",
"* **``interval``** (int): Interval in milliseconds between updates\n",
"* **``loop_policy``** (str): Looping policy; must be one of 'once', 'loop', or 'reflect'\n",
"* **``start``** (int): The range's lower bound\n",
"* **``end``** (int): The range's upper bound\n",
"* **``step``** (int): The interval between values\n",
"* **``value``** (object): The current value; must be one of the option values\n",
"* **``value``** (int): The current integer value\n",
"* **``value_throttled``** (int): The current integer value throttled until mouseup (when selected using slider)\n",
"\n",
"##### Display\n",
"\n",
"* **``disabled``** (boolean): Whether the widget is editable\n",
"* **``interval``** (int): Interval in milliseconds between updates\n",
"* **``name``** (str): The title of the widget\n",
"* **``loop_policy``** (str): Looping policy; must be one of 'once', 'loop', or 'reflect'\n",
"* **``show_loop_controls``** (boolean): Whether radio buttons allowing to switch between loop policies options are shown\n",
"\n",
"___"
Expand Down
16 changes: 12 additions & 4 deletions panel/models/player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,12 @@ export class PlayerView extends WidgetView {
this.sliderEl.value = String(this.model.value)
this.sliderEl.min = String(this.model.start)
this.sliderEl.max = String(this.model.end)
this.sliderEl.onchange = (ev) => this.set_frame(parseInt((ev.target as HTMLInputElement).value))
this.sliderEl.addEventListener('input', (ev) => {
this.set_frame(parseInt((ev.target as HTMLInputElement).value), false)
})
this.sliderEl.addEventListener('change', (ev) => {
this.set_frame(parseInt((ev.target as HTMLInputElement).value))
})

// Buttons
const button_div = div() as any
Expand Down Expand Up @@ -211,9 +216,10 @@ export class PlayerView extends WidgetView {
this.el.appendChild(this.groupEl)
}

set_frame(frame: number): void {
if (this.model.value != frame)
this.model.value = frame;
set_frame(frame: number, throttled: boolean=true): void {
this.model.value = frame
if (throttled)
this.model.value_throttled = frame
if (this.sliderEl.value != String(frame))
this.sliderEl.value = String(frame);
}
Expand Down Expand Up @@ -358,6 +364,7 @@ export namespace Player {
step: p.Property<number>
loop_policy: p.Property<typeof LoopPolicy["__type__"]>
value: p.Property<any>
value_throttled: p.Property<any>
show_loop_controls: p.Property<boolean>
}
}
Expand Down Expand Up @@ -386,6 +393,7 @@ export class Player extends Widget {
step: [ Int, 1 ],
loop_policy: [ LoopPolicy, "once" ],
value: [ Int, 0 ],
value_throttled: [ Int, 0 ],
show_loop_controls: [ Boolean, true ],
}))

Expand Down
2 changes: 2 additions & 0 deletions panel/models/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ class Player(Widget):

value = Int(0, help="Current value of the player app")

value_throttled = Int(0, help="Current throttled value of the player app")

step = Int(1, help="Number of steps to advance the player by.")

interval = Int(500, help="Interval between updates")
Expand Down
46 changes: 33 additions & 13 deletions panel/widgets/player.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import param

from ..config import config
from ..models.widgets import Player as _BkPlayer
from ..util import indexOf, isIn
from .base import Widget
Expand All @@ -20,23 +21,23 @@

class PlayerBase(Widget):

direction = param.Integer(0, doc="""
Current play direction of the Player (-1: playing in reverse,
0: paused, 1: playing)""")

interval = param.Integer(default=500, doc="""
Interval between updates, in milliseconds. Default is 500, i.e.
two updates per second.""")

loop_policy = param.ObjectSelector(default='once',
objects=['once', 'loop', 'reflect'], doc="""
loop_policy = param.ObjectSelector(
default='once', objects=['once', 'loop', 'reflect'], doc="""
Policy used when player hits last frame""")

step = param.Integer(default=1, doc="""
Number of frames to step forward and back by on each event.""")

show_loop_controls = param.Boolean(default=True, doc="""
Whether the loop controls radio buttons are shown""")

direction = param.Integer(0, doc="""
Current play direction of the Player (-1: playing in reverse,
0: paused, 1: playing)""")
step = param.Integer(default=1, doc="""
Number of frames to step forward and back by on each event.""")

height = param.Integer(default=80)

Expand All @@ -48,6 +49,11 @@ class PlayerBase(Widget):

__abstract = True

def __init__(self, **params):
if 'value' in params and 'value_throttled' in self.param:
params['value_throttled'] = params['value']
super().__init__(**params)

def play(self):
self.direction = 1

Expand Down Expand Up @@ -79,6 +85,9 @@ class Player(PlayerBase):

value = param.Integer(default=0, doc="Current player value")

value_throttled = param.Integer(default=0, constant=True, doc="""
Current throttled player value.""")

_supports_embed: ClassVar[bool] = True

def __init__(self, **params):
Expand All @@ -91,6 +100,14 @@ def __init__(self, **params):
params['value'] = params['start']
super().__init__(**params)

def _process_property_change(self, msg):
if config.throttled:
if "value" in msg:
del msg["value"]
if "value_throttled" in msg:
msg["value"] = msg["value_throttled"]
return super()._process_property_change(msg)

def _get_embed_state(self, root, values=None, max_opts=3):
if values is None:
values = list(range(self.start, self.end, self.step))
Expand Down Expand Up @@ -121,9 +138,11 @@ class DiscretePlayer(PlayerBase, SelectBase):

value = param.Parameter(doc="Current player value")

value_throttled = param.Parameter(constant=True, doc="Current player value")

_rename: ClassVar[Mapping[str, str | None]] = {'name': None, 'options': None}

_source_transforms: ClassVar[Mapping[str, str | None]] = {'value': None}
_source_transforms: ClassVar[Mapping[str, str | None]] = {'value': None, 'value_throttled': None}

def _process_param_change(self, msg):
values = self.values
Expand All @@ -141,8 +160,9 @@ def _process_param_change(self, msg):
return super()._process_param_change(msg)

def _process_property_change(self, msg):
if 'value' in msg:
value = msg.pop('value')
if value < len(self.options):
msg['value'] = self.values[value]
for prop in ('value', 'value_throttled'):
if prop in msg:
value = msg.pop(prop)
if value < len(self.options):
msg[prop] = self.values[value]
return msg