@@ -23,6 +23,8 @@ def __init__(self, **kwargs):
23
23
self ._options = None
24
24
self ._variable_name = None
25
25
26
+ self ._random_slug = {}
27
+
26
28
self .callback = kwargs .get ('callback' , None )
27
29
self .container = kwargs .get ('container' , None )
28
30
self .options = kwargs .get ('options' , None )
@@ -54,6 +56,7 @@ def _jupyter_include_scripts(self):
54
56
def _jupyter_javascript (self ,
55
57
global_options = None ,
56
58
container = None ,
59
+ random_slug = None ,
57
60
retries = 3 ,
58
61
interval = 1000 ):
59
62
"""Return the JavaScript code which Jupyter Labs will need to render the chart.
@@ -68,6 +71,10 @@ def _jupyter_javascript(self,
68
71
property if set, and ``'highcharts_target_div'`` if not set.
69
72
:type container: :class:`str <python:str>` or :obj:`None <python:None>`
70
73
74
+ :param random_slug: The random sequence of characters to append to the container name to ensure uniqueness.
75
+ Defaults to :obj:`None <python:None>`
76
+ :type random_slug: :class:`str <python:str>` or :obj:`None <python:None>`
77
+
71
78
:param retries: The number of times to retry rendering the chart. Used to avoid race conditions with the
72
79
Highcharts script. Defaults to 3.
73
80
:type retries: :class:`int <python:int>`
@@ -79,35 +86,46 @@ def _jupyter_javascript(self,
79
86
:rtype: :class:`str <python:str>`
80
87
"""
81
88
original_container = self .container
82
- self .container = container or self .container or 'highcharts_target_div'
89
+ new_container = container or self .container or 'highcharts_target_div'
90
+ if not random_slug :
91
+ self .container = new_container
92
+ else :
93
+ self .container = f'{ new_container } _{ random_slug } '
83
94
84
95
if global_options is not None :
85
96
global_options = validate_types (global_options ,
86
97
types = SharedOptions )
87
98
88
99
js_str = ''
89
100
js_str += utility_functions .get_retryHighcharts ()
90
-
101
+
91
102
if global_options :
92
103
js_str += '\n ' + utility_functions .prep_js_for_jupyter (global_options .to_js_literal ()) + '\n '
93
104
94
105
js_str += utility_functions .prep_js_for_jupyter (self .to_js_literal (),
95
106
container = self .container ,
107
+ random_slug = random_slug ,
96
108
retries = retries ,
97
109
interval = interval )
98
110
99
111
self .container = original_container
100
112
101
113
return js_str
102
114
103
- def _jupyter_container_html (self , container = None ):
115
+ def _jupyter_container_html (self ,
116
+ container = None ,
117
+ random_slug = None ):
104
118
"""Returns the Jupyter Labs HTML container for rendering the chart in Jupyter Labs context.
105
119
106
120
:param container: The ID to apply to the HTML container when rendered in Jupyter Labs. Defaults to
107
121
:obj:`None <python:None>`, which applies the :meth:`.container <highcharts_core.chart.Chart.container>`
108
122
property if set, and ``'highcharts_target_div'`` if not set.
109
123
:type container: :class:`str <python:str>` or :obj:`None <python:None>`
110
124
125
+ :param random_slug: The random sequence of characters to append to the container/function name to ensure
126
+ uniqueness. Defaults to :obj:`None <python:None>`
127
+ :type random_slug: :class:`str <python:str>` or :obj:`None <python:None>`
128
+
111
129
:rtype: :class:`str <python:str>`
112
130
"""
113
131
if self .options .chart :
@@ -116,6 +134,8 @@ def _jupyter_container_html(self, container = None):
116
134
height = 400
117
135
118
136
container = container or self .container or 'highcharts_target_div'
137
+ if random_slug :
138
+ container = f'{ container } _{ random_slug } '
119
139
120
140
container_str = f"""<div id=\" { container } \" style=\" width:100%; height:{ height } ;\" ></div>\n """
121
141
@@ -426,6 +446,9 @@ def _copy_dict_key(cls,
426
446
preserve_data = kwargs .get ('preserve_data' , True )
427
447
428
448
original_value = original [key ]
449
+ if other is None :
450
+ other = {}
451
+
429
452
other_value = other .get (key , None )
430
453
431
454
if key == 'data' and preserve_data :
@@ -525,9 +548,9 @@ def copy(self,
525
548
:returns: A mutated version of ``other`` with new property values
526
549
527
550
"""
528
- super ().copy (other = other ,
529
- overwrite = overwrite ,
530
- ** kwargs )
551
+ return super ().copy (other = other ,
552
+ overwrite = overwrite ,
553
+ ** kwargs )
531
554
532
555
def add_series (self , * series ):
533
556
"""Adds ``series`` to the
@@ -666,6 +689,18 @@ def display(self,
666
689
:param container: The ID to apply to the HTML container when rendered in Jupyter Labs. Defaults to
667
690
:obj:`None <python:None>`, which applies the :meth:`.container <highcharts_core.chart.Chart.container>`
668
691
property if set, and ``'highcharts_target_div'`` if not set.
692
+
693
+ .. note::
694
+
695
+ Highcharts for Python will append a 6-character random string to the value of ``container``
696
+ to ensure uniqueness of the chart's container when rendering in a Jupyter Notebook/Labs context. The
697
+ :class:`Chart <highcharts_core.chart.Chart>` instance will retain the mapping between container and the
698
+ random string so long as the instance exists, thus allowing you to easily update the rendered chart by
699
+ calling the :meth:`.display() <highcharts_core.chart.Chart.display>` method again.
700
+
701
+ If you wish to create a new chart from the instance that does not update the existing chart, then you can do
702
+ so by specifying a new ``container`` value.
703
+
669
704
:type container: :class:`str <python:str>` or :obj:`None <python:None>`
670
705
671
706
:param retries: The number of times to retry rendering the chart. Used to avoid race conditions with the
@@ -693,11 +728,21 @@ def display(self,
693
728
include_display = display_mod .Javascript (data = include_js_str )
694
729
695
730
container = container or self .container or 'highcharts_target_div'
696
- html_str = self ._jupyter_container_html (container )
731
+ if not self ._random_slug :
732
+ self ._random_slug = {}
733
+
734
+ random_slug = self ._random_slug .get (container , None )
735
+
736
+ if not random_slug :
737
+ random_slug = utility_functions .get_random_string ()
738
+ self ._random_slug [container ] = random_slug
739
+
740
+ html_str = self ._jupyter_container_html (container , random_slug )
697
741
html_display = display_mod .HTML (data = html_str )
698
742
699
743
chart_js_str = self ._jupyter_javascript (global_options = global_options ,
700
744
container = container ,
745
+ random_slug = random_slug ,
701
746
retries = retries ,
702
747
interval = interval )
703
748
javascript_display = display_mod .Javascript (data = chart_js_str )
0 commit comments