@@ -23,6 +23,8 @@ def __init__(self, **kwargs):
2323 self ._options = None
2424 self ._variable_name = None
2525
26+ self ._random_slug = {}
27+
2628 self .callback = kwargs .get ('callback' , None )
2729 self .container = kwargs .get ('container' , None )
2830 self .options = kwargs .get ('options' , None )
@@ -54,6 +56,7 @@ def _jupyter_include_scripts(self):
5456 def _jupyter_javascript (self ,
5557 global_options = None ,
5658 container = None ,
59+ random_slug = None ,
5760 retries = 3 ,
5861 interval = 1000 ):
5962 """Return the JavaScript code which Jupyter Labs will need to render the chart.
@@ -68,6 +71,10 @@ def _jupyter_javascript(self,
6871 property if set, and ``'highcharts_target_div'`` if not set.
6972 :type container: :class:`str <python:str>` or :obj:`None <python:None>`
7073
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+
7178 :param retries: The number of times to retry rendering the chart. Used to avoid race conditions with the
7279 Highcharts script. Defaults to 3.
7380 :type retries: :class:`int <python:int>`
@@ -79,35 +86,46 @@ def _jupyter_javascript(self,
7986 :rtype: :class:`str <python:str>`
8087 """
8188 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 } '
8394
8495 if global_options is not None :
8596 global_options = validate_types (global_options ,
8697 types = SharedOptions )
8798
8899 js_str = ''
89100 js_str += utility_functions .get_retryHighcharts ()
90-
101+
91102 if global_options :
92103 js_str += '\n ' + utility_functions .prep_js_for_jupyter (global_options .to_js_literal ()) + '\n '
93104
94105 js_str += utility_functions .prep_js_for_jupyter (self .to_js_literal (),
95106 container = self .container ,
107+ random_slug = random_slug ,
96108 retries = retries ,
97109 interval = interval )
98110
99111 self .container = original_container
100112
101113 return js_str
102114
103- def _jupyter_container_html (self , container = None ):
115+ def _jupyter_container_html (self ,
116+ container = None ,
117+ random_slug = None ):
104118 """Returns the Jupyter Labs HTML container for rendering the chart in Jupyter Labs context.
105119
106120 :param container: The ID to apply to the HTML container when rendered in Jupyter Labs. Defaults to
107121 :obj:`None <python:None>`, which applies the :meth:`.container <highcharts_core.chart.Chart.container>`
108122 property if set, and ``'highcharts_target_div'`` if not set.
109123 :type container: :class:`str <python:str>` or :obj:`None <python:None>`
110124
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+
111129 :rtype: :class:`str <python:str>`
112130 """
113131 if self .options .chart :
@@ -116,6 +134,8 @@ def _jupyter_container_html(self, container = None):
116134 height = 400
117135
118136 container = container or self .container or 'highcharts_target_div'
137+ if random_slug :
138+ container = f'{ container } _{ random_slug } '
119139
120140 container_str = f"""<div id=\" { container } \" style=\" width:100%; height:{ height } ;\" ></div>\n """
121141
@@ -426,6 +446,9 @@ def _copy_dict_key(cls,
426446 preserve_data = kwargs .get ('preserve_data' , True )
427447
428448 original_value = original [key ]
449+ if other is None :
450+ other = {}
451+
429452 other_value = other .get (key , None )
430453
431454 if key == 'data' and preserve_data :
@@ -525,9 +548,9 @@ def copy(self,
525548 :returns: A mutated version of ``other`` with new property values
526549
527550 """
528- super ().copy (other = other ,
529- overwrite = overwrite ,
530- ** kwargs )
551+ return super ().copy (other = other ,
552+ overwrite = overwrite ,
553+ ** kwargs )
531554
532555 def add_series (self , * series ):
533556 """Adds ``series`` to the
@@ -666,6 +689,18 @@ def display(self,
666689 :param container: The ID to apply to the HTML container when rendered in Jupyter Labs. Defaults to
667690 :obj:`None <python:None>`, which applies the :meth:`.container <highcharts_core.chart.Chart.container>`
668691 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+
669704 :type container: :class:`str <python:str>` or :obj:`None <python:None>`
670705
671706 :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,
693728 include_display = display_mod .Javascript (data = include_js_str )
694729
695730 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 )
697741 html_display = display_mod .HTML (data = html_str )
698742
699743 chart_js_str = self ._jupyter_javascript (global_options = global_options ,
700744 container = container ,
745+ random_slug = random_slug ,
701746 retries = retries ,
702747 interval = interval )
703748 javascript_display = display_mod .Javascript (data = chart_js_str )
0 commit comments