37
37
PanTool ,
38
38
Range1d ,
39
39
ResetTool ,
40
+ Select ,
40
41
Tabs ,
41
42
TapTool ,
42
43
Title ,
43
- Toggle ,
44
44
VeeHead ,
45
45
WheelZoomTool ,
46
46
)
@@ -3396,58 +3396,64 @@ def __init__(self, scheduler, **kwargs):
3396
3396
self .init_root ()
3397
3397
3398
3398
def init_root (self ):
3399
- def handle_toggle (_toggle ):
3400
- self .toggle .label = (
3401
- "Bytes (Toggle for Values)"
3402
- if self .toggle .active
3403
- else "Timing (Toggle for Bytes)"
3404
- )
3399
+ def handle_selector_chng (attr , old , new ):
3400
+ self .freq_selected = new
3405
3401
self .substantial_change = True
3406
3402
3407
3403
self .function_selector = MultiChoice (value = [], options = [])
3408
3404
self .function_selector .placeholder = "Select specific functions"
3409
- self .toggle = Toggle (label = "Timing (Toggle for Bytes)" )
3410
- self .toggle .on_click (handle_toggle )
3405
+ self .freq_selector = Select (title = "Freq selection" , options = [])
3406
+ self .freq_selector .on_change ("value" , handle_selector_chng )
3407
+ self .freq_selected = "seconds"
3411
3408
self .task_exec_by_activity_chart = figure ()
3412
3409
self .task_exec_by_prefix_chart = figure ()
3413
3410
self .senddata_by_activity_chart = figure ()
3414
3411
self .root = column (
3415
3412
self .function_selector ,
3416
- self .toggle ,
3413
+ self .freq_selector ,
3417
3414
row ([self .task_exec_by_prefix_chart , self .task_exec_by_activity_chart ]),
3418
3415
row ([self .senddata_by_activity_chart ]),
3419
3416
sizing_mode = "scale_width" ,
3420
3417
)
3421
3418
3419
+ def format (self , freq : str , val : Any ) -> str :
3420
+ formatters = {"bytes" : format_bytes , "seconds" : format_time }
3421
+ return formatters .get (freq , str )(val )
3422
+
3422
3423
@without_property_validation
3423
3424
@log_errors
3424
3425
def update (self ):
3425
3426
items = sorted (
3426
3427
(k , v )
3427
3428
for k , v in self .scheduler .cumulative_worker_metrics .items ()
3428
- if isinstance (k , tuple ) and k [ - 1 ] in ( "bytes" , "seconds" )
3429
+ if isinstance (k , tuple )
3429
3430
)
3430
3431
for (type , * parts ), val in items :
3431
3432
if type == "get-data" :
3432
3433
operation , freq = parts
3434
+
3435
+ if freq not in self .freq_selector .options :
3436
+ # note append doesn't work here
3437
+ self .freq_selector .options += [freq ]
3438
+
3433
3439
if operation not in self .senddata ["operation" ]:
3434
3440
self .substantial_change = True
3435
3441
self .senddata ["operation" ].append (operation )
3436
3442
3437
3443
idx = self .senddata ["operation" ].index (operation )
3438
- while idx >= len (self .senddata [f"{ operation } _value" ]):
3439
- self .senddata [f"{ operation } _bytes" ].append (0 )
3440
- self .senddata [f"{ operation } _value" ].append (0 )
3441
- self .senddata [f"{ operation } _text" ].append (0 )
3442
- if freq == "bytes" :
3443
- self .senddata [f"{ operation } _text" ][idx ] = format_bytes (val )
3444
- self .senddata [f"{ operation } _bytes" ][idx ] = val
3445
- elif freq == "seconds" :
3446
- self .senddata [f"{ operation } _text" ][idx ] = format_time (val )
3447
- self .senddata [f"{ operation } _value" ][idx ] = val
3444
+ while idx >= len (self .senddata [f"{ operation } _{ freq } " ]):
3445
+ self .senddata [f"{ operation } _{ freq } " ].append (0 )
3446
+ self .senddata [f"{ operation } _{ freq } _text" ].append ("" )
3447
+ self .senddata [f"{ operation } _{ freq } _text" ][idx ] = self .format (freq , val )
3448
+ self .senddata [f"{ operation } _{ freq } " ][idx ] = val
3448
3449
3449
3450
elif type == "execute" :
3450
3451
function_name , operation , freq = parts
3452
+
3453
+ if freq not in self .freq_selector .options :
3454
+ # note append doesn't work here
3455
+ self .freq_selector .options += [freq ]
3456
+
3451
3457
if operation not in self .task_operations :
3452
3458
self .substantial_change = True
3453
3459
self .task_operations .append (operation )
@@ -3461,19 +3467,16 @@ def update(self):
3461
3467
3462
3468
# Some function/operation combos missing, so need to keep columns aligned
3463
3469
for op in self .task_operations :
3464
- while len (self .task_exec_data [f"{ op } _value " ]) != len (
3470
+ while len (self .task_exec_data [f"{ op } _ { freq } " ]) != len (
3465
3471
self .task_exec_data ["functions" ]
3466
3472
):
3467
- self .task_exec_data [f"{ op } _value" ].append (0 )
3468
- self .task_exec_data [f"{ op } _bytes" ].append (0 )
3469
- self .task_exec_data [f"{ op } _text" ].append ("" )
3473
+ self .task_exec_data [f"{ op } _{ freq } " ].append (0 )
3474
+ self .task_exec_data [f"{ op } _{ freq } _text" ].append ("" )
3470
3475
3471
- if freq == "seconds" :
3472
- self .task_exec_data [f"{ operation } _text" ][idx ] = format_time (val )
3473
- self .task_exec_data [f"{ operation } _value" ][idx ] = val
3474
- elif freq == "bytes" :
3475
- self .task_exec_data [f"{ operation } _text" ][idx ] = format_bytes (val )
3476
- self .task_exec_data [f"{ operation } _bytes" ][idx ] = val
3476
+ self .task_exec_data [f"{ operation } _{ freq } " ][idx ] = val
3477
+ self .task_exec_data [f"{ operation } _{ freq } _text" ][idx ] = self .format (
3478
+ freq , val
3479
+ )
3477
3480
3478
3481
data = self .task_exec_data .copy ()
3479
3482
# If user has manually selected function(s) then we are only showing them.
@@ -3495,9 +3498,13 @@ def update(self):
3495
3498
f"Filter by function ({ len (self .function_selector .options )} ):"
3496
3499
)
3497
3500
3498
- task_exec_piechart = self ._build_task_execution_by_activity_chart ()
3499
- task_exec_barchart = self ._build_task_execution_by_prefix_chart ()
3500
- senddata_piechart = self ._build_senddata_chart ()
3501
+ task_exec_piechart = self ._build_task_execution_by_activity_chart (
3502
+ self .task_exec_data_limited .copy ()
3503
+ )
3504
+ task_exec_barchart = self ._build_task_execution_by_prefix_chart (
3505
+ self .task_exec_data_limited .copy ()
3506
+ )
3507
+ senddata_piechart = self ._build_senddata_chart (self .senddata .copy ())
3501
3508
3502
3509
# replacing the child causes small blips if done every iteration vs updating renderers
3503
3510
# but it's needed when new functions and/or operations show up to rerender plot
@@ -3511,28 +3518,20 @@ def update(self):
3511
3518
self .task_exec_by_activity_chart .renderers = task_exec_barchart .renderers
3512
3519
self .senddata_by_activity_chart .renderers = senddata_piechart .renderers
3513
3520
3514
- def _build_task_execution_by_activity_chart (self ):
3515
- show_bytes = self .toggle .active
3521
+ def _build_task_execution_by_activity_chart (
3522
+ self , task_exec_data : defaultdict [str , list ]
3523
+ ) -> figure :
3516
3524
piechart_data = dict ()
3517
3525
piechart_data ["value" ] = [
3518
- sum (
3519
- self .task_exec_data_limited [
3520
- f"{ op } _{ 'bytes' if show_bytes else 'value' } "
3521
- ]
3522
- )
3526
+ sum (task_exec_data [f"{ op } _{ self .freq_selected } " ])
3523
3527
for op in self .task_operations
3524
3528
]
3525
3529
piechart_data ["text" ] = [
3526
- format_bytes (n ) if show_bytes else format_time (n )
3527
- for n in piechart_data ["value" ]
3530
+ self .format (self .freq_selected , v ) for v in piechart_data ["value" ]
3528
3531
]
3529
3532
piechart_data ["angle" ] = [
3530
3533
(
3531
- sum (
3532
- self .task_exec_data_limited [
3533
- f"{ operation } _{ 'bytes' if show_bytes else 'value' } "
3534
- ]
3535
- )
3534
+ sum (task_exec_data [f"{ operation } _{ self .freq_selected } " ])
3536
3535
/ sum (piechart_data ["value" ])
3537
3536
if sum (piechart_data ["value" ])
3538
3537
else 0 # may not have any bytes movement reported, avoid divide by zero
@@ -3571,9 +3570,11 @@ def _build_task_execution_by_activity_chart(self):
3571
3570
)
3572
3571
return piechart
3573
3572
3574
- def _build_task_execution_by_prefix_chart (self ):
3573
+ def _build_task_execution_by_prefix_chart (
3574
+ self , task_exec_data : defaultdict [str , list ]
3575
+ ) -> figure :
3575
3576
barchart = figure (
3576
- x_range = self . task_exec_data_limited ["functions" ],
3577
+ x_range = task_exec_data ["functions" ],
3577
3578
height = 500 ,
3578
3579
title = "Task execution, by prefix" ,
3579
3580
tools = "pan,wheel_zoom,box_zoom,reset" ,
@@ -3582,67 +3583,59 @@ def _build_task_execution_by_prefix_chart(self):
3582
3583
barchart .yaxis .visible = False
3583
3584
barchart .xaxis .major_label_orientation = 0.2
3584
3585
barchart .grid .grid_line_color = None
3585
- renderers = barchart .vbar_stack (
3586
- [
3587
- name
3588
- for name in self .task_exec_data_limited .keys ()
3589
- if name .endswith ("bytes" if self .toggle .active else "value" )
3590
- and len (self .task_exec_data_limited [name ])
3591
- ],
3592
- x = "functions" ,
3593
- width = 0.9 ,
3594
- source = self .task_exec_by_prefix_src ,
3595
- color = small_palettes ["YlGnBu" ].get (len (self .task_operations ), []),
3596
- legend_label = self .task_operations ,
3597
- )
3598
- for vbar in renderers :
3599
- tooltips = [
3600
- (
3601
- vbar .name ,
3602
- f"@{{{ vbar .name .replace ('_bytes' , '' ).replace ('_value' , '' )} _text}}" ,
3603
- ),
3604
- ("function" , "@functions" ),
3605
- ]
3606
- barchart .add_tools (HoverTool (tooltips = tooltips , renderers = [vbar ]))
3586
+ stackers = [
3587
+ name for name in task_exec_data if name .endswith (self .freq_selected )
3588
+ ]
3589
+ if stackers :
3590
+ renderers = barchart .vbar_stack (
3591
+ stackers ,
3592
+ x = "functions" ,
3593
+ width = 0.9 ,
3594
+ source = self .task_exec_by_prefix_src ,
3595
+ color = small_palettes ["YlGnBu" ].get (len (self .task_operations ), []),
3596
+ legend_label = self .task_operations ,
3597
+ )
3598
+ for vbar in renderers :
3599
+ tooltips = [
3600
+ (
3601
+ vbar .name ,
3602
+ f"@{{{ vbar .name } _text}}" ,
3603
+ ),
3604
+ ("function" , "@functions" ),
3605
+ ]
3606
+ barchart .add_tools (HoverTool (tooltips = tooltips , renderers = [vbar ]))
3607
3607
3608
- if any (
3609
- len (self .task_exec_by_prefix_src .data [k ])
3610
- != len (self .task_exec_data_limited [k ])
3611
- for k in self .task_exec_by_prefix_src .data
3612
- ):
3613
- self .substantial_change = True
3614
- self .task_exec_by_prefix_src .data = dict (self .task_exec_data_limited )
3615
- barchart .renderers = renderers
3616
- return barchart
3608
+ if any (
3609
+ len (self .task_exec_by_prefix_src .data [k ]) != len (task_exec_data [k ])
3610
+ for k in self .task_exec_by_prefix_src .data
3611
+ ):
3612
+ self .substantial_change = True
3617
3613
3618
- def _build_senddata_chart (self ):
3619
- show_bytes = self .toggle .active
3614
+ self .task_exec_by_prefix_src .data = dict (task_exec_data )
3615
+ barchart .renderers = renderers
3616
+ return barchart
3620
3617
3621
- senddata = dict ()
3622
- senddata ["operation" ] = self .senddata ["operation" ]
3623
- senddata ["value" ] = [
3624
- (sum (self .senddata [f"{ op } _{ 'bytes' if show_bytes else 'value' } " ]))
3625
- for op in self .senddata ["operation" ]
3626
- ]
3627
- senddata ["text" ] = [
3628
- format_bytes (n ) if show_bytes else format_time (n ) for n in senddata ["value" ]
3618
+ def _build_senddata_chart (self , senddata : defaultdict [str , list ]) -> figure :
3619
+ piedata = dict ()
3620
+ piedata ["operation" ] = senddata ["operation" ]
3621
+ piedata ["value" ] = [
3622
+ (sum (senddata [f"{ op } _{ self .freq_selected } " ]))
3623
+ for op in senddata ["operation" ]
3629
3624
]
3630
- senddata ["angle" ] = [
3625
+ piedata ["text" ] = [self .format (self .freq_selected , v ) for v in piedata ["value" ]]
3626
+ piedata ["angle" ] = [
3631
3627
(
3632
- (
3633
- sum (self .senddata [f"{ op } _{ 'bytes' if show_bytes else 'value' } " ])
3634
- / sum (senddata ["value" ])
3635
- )
3636
- if sum (senddata ["value" ])
3628
+ (sum (senddata [f"{ op } _{ self .freq_selected } " ]) / sum (piedata ["value" ]))
3629
+ if sum (piedata ["value" ])
3637
3630
else 0.0
3638
3631
)
3639
3632
* 2
3640
3633
* math .pi
3641
- for op in senddata ["operation" ]
3634
+ for op in piedata ["operation" ]
3642
3635
]
3643
- senddata ["color" ] = small_palettes ["YlGnBu" ].get (len (senddata ["operation" ]), [])
3636
+ piedata ["color" ] = small_palettes ["YlGnBu" ].get (len (piedata ["operation" ]), [])
3644
3637
3645
- self .sendsrc .data = senddata
3638
+ self .sendsrc .data = piedata
3646
3639
senddata_piechart = figure (
3647
3640
height = 500 ,
3648
3641
title = "Send data, by activity" ,
0 commit comments