@@ -87,6 +87,7 @@ def __init__(self, *args, **kwargs):
87
87
self ._html_report_extra = [] # (Used by pytest_plugin.py)
88
88
self ._default_driver = None
89
89
self ._drivers_list = []
90
+ self ._chart_data = {}
90
91
self ._tour_steps = {}
91
92
92
93
def open (self , url ):
@@ -3437,6 +3438,265 @@ def begin_presentation(
3437
3438
3438
3439
############
3439
3440
3441
+ def create_pie_chart (self , chart_name = None , title = None ):
3442
+ """ Creates a JavaScript pie chart using "HighCharts". """
3443
+ if not chart_name :
3444
+ chart_name = "default"
3445
+ style = "pie"
3446
+ unit = "Count"
3447
+ self .__create_highchart (
3448
+ chart_name = chart_name , title = title , style = style , unit = unit )
3449
+
3450
+ def __create_highchart (
3451
+ self , chart_name = None , title = None , style = None , unit = None ):
3452
+ """ Creates a JavaScript chart using the "HighCharts" library. """
3453
+ if not chart_name :
3454
+ chart_name = "default"
3455
+ if not title :
3456
+ title = ""
3457
+ if not style :
3458
+ style = "pie"
3459
+ if not unit :
3460
+ unit = "Count"
3461
+ chart_libs = (
3462
+ """
3463
+ <script src="%s"></script>
3464
+ <script src="%s"></script>
3465
+ <script src="%s"></script>
3466
+ <script src="%s"></script>
3467
+ <script src="%s"></script>
3468
+ """ % (
3469
+ constants .JQuery .MIN_JS ,
3470
+ constants .HighCharts .HC_JS ,
3471
+ constants .HighCharts .EXPORTING_JS ,
3472
+ constants .HighCharts .EXPORT_DATA_JS ,
3473
+ constants .HighCharts .ACCESSIBILITY_JS ))
3474
+ chart_css = (
3475
+ """
3476
+ <style>
3477
+ .highcharts-figure, .highcharts-data-table table {
3478
+ min-width: 320px;
3479
+ max-width: 660px;
3480
+ margin: 1em auto;
3481
+ }
3482
+ .highcharts-data-table table {
3483
+ font-family: Verdana, sans-serif;
3484
+ border-collapse: collapse;
3485
+ border: 1px solid #EBEBEB;
3486
+ margin: 10px auto;
3487
+ text-align: center;
3488
+ width: 100%;
3489
+ max-width: 500px;
3490
+ }
3491
+ .highcharts-data-table caption {
3492
+ padding: 1em 0;
3493
+ font-size: 1.2em;
3494
+ color: #555;
3495
+ }
3496
+ .highcharts-data-table th {
3497
+ font-weight: 600;
3498
+ padding: 0.5em;
3499
+ }
3500
+ .highcharts-data-table td, .highcharts-data-table th,
3501
+ .highcharts-data-table caption {
3502
+ padding: 0.5em;
3503
+ }
3504
+ .highcharts-data-table thead tr,
3505
+ .highcharts-data-table tr:nth-child(even) {
3506
+ background: #f8f8f8;
3507
+ }
3508
+ .highcharts-data-table tr:hover {
3509
+ background: #f1f7ff;
3510
+ }
3511
+ </style>
3512
+ """ )
3513
+ chart_description = ""
3514
+ chart_figure = (
3515
+ """
3516
+ <figure class="highcharts-figure">
3517
+ <div id="container"></div>
3518
+ <p class="highcharts-description">%s</p>
3519
+ </figure>
3520
+ """ % chart_description )
3521
+ chart_init_1 = (
3522
+ """
3523
+ <script>
3524
+ // Build the chart
3525
+ Highcharts.chart('container', {
3526
+ credits: {
3527
+ enabled: false
3528
+ },
3529
+ title: {
3530
+ text: '%s'
3531
+ },
3532
+ chart: {
3533
+ renderTo: 'statusChart',
3534
+ plotBackgroundColor: null,
3535
+ plotBorderWidth: null,
3536
+ plotShadow: false,
3537
+ type: '%s'
3538
+ },
3539
+ """ % (title , style ))
3540
+ # "{series.name}:" => "Count:" (based on unit)
3541
+ point_format = (r'<b>{point.y}</b><br />'
3542
+ r'<b>{point.percentage:.1f}%</b>' )
3543
+ chart_init_2 = (
3544
+ """
3545
+ tooltip: {
3546
+ pointFormat: '%s'
3547
+ },
3548
+ """ % point_format )
3549
+ chart_init_3 = (
3550
+ r"""
3551
+ accessibility: {
3552
+ point: {
3553
+ valueSuffix: '%'
3554
+ }
3555
+ },
3556
+ plotOptions: {
3557
+ pie: {
3558
+ allowPointSelect: true,
3559
+ cursor: 'pointer',
3560
+ dataLabels: {
3561
+ enabled: false,
3562
+ format: '{point.name}: {point.y:.1f}%'
3563
+ },
3564
+ showInLegend: true
3565
+ }
3566
+ },
3567
+ """ )
3568
+ chart_init = chart_init_1 + chart_init_2 + chart_init_3
3569
+ series = (
3570
+ """
3571
+ series: [{
3572
+ name: '%s',
3573
+ colorByPoint: true,
3574
+ data: [
3575
+ """ % unit )
3576
+ new_chart = chart_libs + chart_css + chart_figure + chart_init + series
3577
+ self ._chart_data [chart_name ] = []
3578
+ self ._chart_data [chart_name ].append (new_chart )
3579
+
3580
+ def add_data_point (self , label , value , color = None , chart_name = None ):
3581
+ """ Add a data point to a SeleniumBase-generated chart.
3582
+ @Params
3583
+ label - The label name for the data point.
3584
+ value - The numeric value of the data point.
3585
+ color - The HTML color of the data point.
3586
+ Can be an RGB color. Eg: "#55ACDC".
3587
+ Can also be a named color. Eg: "Teal".
3588
+ chart_name - If creating multiple charts,
3589
+ use this to select which one.
3590
+ """
3591
+ if not chart_name :
3592
+ chart_name = "default"
3593
+ if chart_name not in self ._chart_data :
3594
+ # Create a chart if it doesn't already exist
3595
+ self .create_pie_chart (chart_name = chart_name )
3596
+ if not color :
3597
+ color = ""
3598
+ data_point = (
3599
+ """
3600
+ {
3601
+ name: '%s',
3602
+ y: %s,
3603
+ color: '%s'
3604
+ },
3605
+ """ % (label , value , color ))
3606
+ self ._chart_data [chart_name ].append (data_point )
3607
+
3608
+ def save_chart (self , chart_name = None , filename = None ):
3609
+ """ Saves a SeleniumBase-generated chart to a file for later use.
3610
+ @Params
3611
+ chart_name - If creating multiple charts at the same time,
3612
+ use this to select the one you wish to use.
3613
+ filename - The name of the HTML file that you wish to
3614
+ save the chart to. (filename must end in ".html")
3615
+ """
3616
+ if not chart_name :
3617
+ chart_name = "default"
3618
+ if not filename :
3619
+ filename = "my_chart.html"
3620
+ if chart_name not in self ._chart_data :
3621
+ raise Exception ("Chart {%s} does not exist!" % chart_name )
3622
+ if not filename .endswith ('.html' ):
3623
+ raise Exception ('Chart file must end in ".html"!' )
3624
+ the_html = ""
3625
+ for chart_data_point in self ._chart_data [chart_name ]:
3626
+ the_html += chart_data_point
3627
+ the_html += (
3628
+ """
3629
+ ]
3630
+ }]
3631
+ });
3632
+ </script>
3633
+ """ )
3634
+ saved_charts_folder = constants .Charts .SAVED_FOLDER
3635
+ if saved_charts_folder .endswith ("/" ):
3636
+ saved_charts_folder = saved_charts_folder [:- 1 ]
3637
+ if not os .path .exists (saved_charts_folder ):
3638
+ try :
3639
+ os .makedirs (saved_charts_folder )
3640
+ except Exception :
3641
+ pass
3642
+ file_path = saved_charts_folder + "/" + filename
3643
+ out_file = codecs .open (file_path , "w+" , encoding = "utf-8" )
3644
+ out_file .writelines (the_html )
3645
+ out_file .close ()
3646
+ print ('\n >>> [%s] was saved!' % file_path )
3647
+ return file_path
3648
+
3649
+ def display_chart (self , chart_name = None , filename = None ):
3650
+ """ Displays a SeleniumBase-generated chart in the browser window.
3651
+ @Params
3652
+ chart_name - If creating multiple charts at the same time,
3653
+ use this to select the one you wish to use.
3654
+ filename - The name of the HTML file that you wish to
3655
+ save the chart to. (filename must end in ".html")
3656
+ """
3657
+ if not chart_name :
3658
+ chart_name = "default"
3659
+ if not filename :
3660
+ filename = "my_chart.html"
3661
+ if chart_name not in self ._chart_data :
3662
+ raise Exception ("Chart {%s} does not exist!" % chart_name )
3663
+ if not filename .endswith ('.html' ):
3664
+ raise Exception ('Chart file must end in ".html"!' )
3665
+ file_path = self .save_chart (chart_name = chart_name , filename = filename )
3666
+ self .open_html_file (file_path )
3667
+ chart_folder = constants .Charts .SAVED_FOLDER
3668
+ try :
3669
+ print ("\n *** Close the browser window to continue ***" )
3670
+ while (len (self .driver .window_handles ) > 0 and (
3671
+ chart_folder in self .get_current_url ())):
3672
+ time .sleep (0.05 )
3673
+ except Exception :
3674
+ pass
3675
+
3676
+ def extract_chart (self , chart_name = None ):
3677
+ """ Extracts the HTML from a SeleniumBase-generated chart.
3678
+ @Params
3679
+ chart_name - If creating multiple charts at the same time,
3680
+ use this to select the one you wish to use.
3681
+ """
3682
+ if not chart_name :
3683
+ chart_name = "default"
3684
+ if chart_name not in self ._chart_data :
3685
+ raise Exception ("Chart {%s} does not exist!" % chart_name )
3686
+ the_html = ""
3687
+ for chart_data_point in self ._chart_data [chart_name ]:
3688
+ the_html += chart_data_point
3689
+ the_html += (
3690
+ """
3691
+ ]
3692
+ }]
3693
+ });
3694
+ </script>
3695
+ """ )
3696
+ return the_html
3697
+
3698
+ ############
3699
+
3440
3700
def create_tour (self , name = None , theme = None ):
3441
3701
""" Creates a tour for a website. By default, the Shepherd JavaScript
3442
3702
Library is used with the Shepherd "Light" / "Arrows" theme.
0 commit comments