@@ -92,6 +92,8 @@ def render_copilot_stats_plots(
92
92
plot_total_price (fig , bi , start_date , end_date , trunc_fn , pd_freq )
93
93
plot_retention (fig , bi , start_date , end_date , trunc_fn , pd_freq , dt_index )
94
94
95
+ annotate_bot_versions (fig , bi , trunc_fn , pd_freq , dt_index , tz )
96
+
95
97
gui .plotly_chart (fig , config = defaultPlotlyConfig )
96
98
97
99
@@ -432,6 +434,64 @@ def plot_retention(
432
434
add_legend (fig , "Retention" , color_idx = 9 , row = 5 )
433
435
434
436
437
+ def annotate_bot_versions (
438
+ fig : go .Figure ,
439
+ bi : BotIntegration ,
440
+ trunc_fn : TruncBase ,
441
+ pd_freq : str ,
442
+ dt_index : pd .Index ,
443
+ tz : pytz .timezone ,
444
+ color = "#d3d3d3" , # light gray
445
+ ):
446
+ if dt_index .empty :
447
+ return
448
+
449
+ versions = bi .published_run .versions .filter (
450
+ created_at__range = (dt_index .iloc [0 ], dt_index .iloc [- 1 ]),
451
+ ).annotate (dt = trunc_fn ("created_at" ))
452
+ if not versions .exists ():
453
+ return
454
+
455
+ dates = dt_index .to_list ()
456
+ labels = ["" ] * len (dates )
457
+ idx = 0
458
+
459
+ for version in reversed (versions ):
460
+ for idx in range (idx , len (dates )):
461
+ if dates [idx ] > version .dt :
462
+ break
463
+
464
+ text = "✏️ "
465
+ if version .change_notes :
466
+ text += version .change_notes
467
+ elif version .title and bi .published_run .title != version .title :
468
+ text += f"Renamed to: { version .title } "
469
+ if version .changed_by :
470
+ text += f" by { version .changed_by .full_name ()} "
471
+ text += f" ({ version .dt .strftime ('%b %d %Y' )} )"
472
+ labels [idx ] = text
473
+
474
+ # add vertical line to all subplots
475
+ for row in range (1 , fig .layout .grid .rows + 1 ):
476
+ fig .add_vline (
477
+ x = dates [idx ],
478
+ line = dict (color = color , width = 1 , dash = "dash" ),
479
+ yref = f"y{ row } " ,
480
+ )
481
+
482
+ # add a hidden scatter trace to show the hover labels
483
+ fig .add_trace (
484
+ go .Scatter (
485
+ x = dates ,
486
+ y = [0 ] * len (dates ),
487
+ customdata = labels ,
488
+ hovertemplate = "%{customdata}<extra></extra>" ,
489
+ showlegend = False ,
490
+ line = dict (width = 0 , color = color ),
491
+ )
492
+ )
493
+
494
+
435
495
def get_line_marker (* , color_idx : int , gradient : bool = False ):
436
496
ret = dict (
437
497
line = dict (color = COLOR_PALETTE [color_idx ]),
0 commit comments