From 7badd8227c38baeb8b92584057dbce4fd79b1f04 Mon Sep 17 00:00:00 2001 From: BenjaminGabet Date: Thu, 1 Dec 2022 16:57:27 +0100 Subject: [PATCH 01/10] [NF] OptiConstraint inherit from DataKeeper --- .../Optimization/test_Binh_and_Korn.py | 4 +- .../Optimization/test_Binh_and_Korn_Bayes.py | 4 +- pyleecan/Classes/Class_Dict.json | 23 +- pyleecan/Classes/OptiConstraint.py | 214 ++++++++---------- pyleecan/Functions/Optimization/check_cstr.py | 2 +- .../Optimization/OptiConstraint.csv | 4 +- .../check_optimization_input.py | 4 +- .../OptiBayesAlgSmoot/eval_const.py | 2 +- .../check_optimization_input.py | 4 +- 9 files changed, 106 insertions(+), 155 deletions(-) diff --git a/Tests/Validation/Optimization/test_Binh_and_Korn.py b/Tests/Validation/Optimization/test_Binh_and_Korn.py index d83bcb2a2..1f4c2ebc2 100644 --- a/Tests/Validation/Optimization/test_Binh_and_Korn.py +++ b/Tests/Validation/Optimization/test_Binh_and_Korn.py @@ -101,13 +101,13 @@ def test_Binh_and_Korn(): cstrs = [ OptiConstraint( name="first", - get_variable="lambda output: (output.simu.machine.rotor.slot.H0 - 5) ** 2 + output.simu.machine.stator.slot.H0 ** 2", + keeper="lambda output: (output.simu.machine.rotor.slot.H0 - 5) ** 2 + output.simu.machine.stator.slot.H0 ** 2", type_const="<=", value=25, ), OptiConstraint( name="second", - get_variable="lambda output: (output.simu.machine.rotor.slot.H0 - 5) ** 2 + (output.simu.machine.stator.slot.H0 + 3) ** 2", + keeper="lambda output: (output.simu.machine.rotor.slot.H0 - 5) ** 2 + (output.simu.machine.stator.slot.H0 + 3) ** 2", type_const=">=", value=7.7, ), diff --git a/Tests/Validation/Optimization/test_Binh_and_Korn_Bayes.py b/Tests/Validation/Optimization/test_Binh_and_Korn_Bayes.py index c55c53348..254b47e3b 100644 --- a/Tests/Validation/Optimization/test_Binh_and_Korn_Bayes.py +++ b/Tests/Validation/Optimization/test_Binh_and_Korn_Bayes.py @@ -100,13 +100,13 @@ def test_Binh_and_Korn(): cstrs = [ OptiConstraint( name="first", - get_variable="lambda output: (output.simu.machine.rotor.slot.H0 - 5) ** 2 + output.simu.machine.stator.slot.H0 ** 2", + keeper="lambda output: (output.simu.machine.rotor.slot.H0 - 5) ** 2 + output.simu.machine.stator.slot.H0 ** 2", type_const="<=", value=25, ), OptiConstraint( name="second", - get_variable="lambda output: (output.simu.machine.rotor.slot.H0 - 5) ** 2 + (output.simu.machine.stator.slot.H0 + 3) ** 2", + keeper="lambda output: (output.simu.machine.rotor.slot.H0 - 5) ** 2 + (output.simu.machine.stator.slot.H0 + 3) ** 2", type_const=">=", value=7.7, ), diff --git a/pyleecan/Classes/Class_Dict.json b/pyleecan/Classes/Class_Dict.json index 835a7b6e3..4601d2c0f 100644 --- a/pyleecan/Classes/Class_Dict.json +++ b/pyleecan/Classes/Class_Dict.json @@ -1037,6 +1037,7 @@ } ], "daughters": [ + "OptiConstraint", "OptiObjective" ], "desc": "Class for defining data to keep on a multi-simulation", @@ -8910,21 +8911,11 @@ "desc": "Constraint of the optimization problem", "is_internal": false, "methods": [], - "mother": "", + "mother": "DataKeeper", "name": "OptiConstraint", "package": "Optimization", "path": "pyleecan/Generator/ClassesRef/Optimization/OptiConstraint.csv", "properties": [ - { - "as_dict": "", - "desc": "name of the design variable", - "max": "", - "min": "", - "name": "name", - "type": "str", - "unit": "", - "value": "" - }, { "as_dict": "", "desc": "Type of comparison ( \"==\", \"<=\", \">=\", \"<\",\">\")", @@ -8944,16 +8935,6 @@ "type": "float", "unit": "", "value": 0 - }, - { - "as_dict": "", - "desc": "Function to get the variable to compare", - "max": "", - "min": "", - "name": "get_variable", - "type": "function", - "unit": "", - "value": null } ] }, diff --git a/pyleecan/Classes/OptiConstraint.py b/pyleecan/Classes/OptiConstraint.py index 6f2412f5c..39b295269 100644 --- a/pyleecan/Classes/OptiConstraint.py +++ b/pyleecan/Classes/OptiConstraint.py @@ -13,8 +13,9 @@ from ..Functions.load import load_init_dict from ..Functions.Load.import_class import import_class from copy import deepcopy -from ._frozen import FrozenClass +from .DataKeeper import DataKeeper +from numpy import array, ndarray from ntpath import basename from os.path import isfile from ._check import CheckTypeError @@ -24,7 +25,7 @@ from ._check import InitUnKnowClassError -class OptiConstraint(FrozenClass): +class OptiConstraint(DataKeeper): """Constraint of the optimization problem""" VERSION = 1 @@ -36,10 +37,16 @@ class OptiConstraint(FrozenClass): def __init__( self, - name="", type_const="<=", value=0, - get_variable=None, + name="", + symbol="", + unit="", + keeper=None, + error_keeper=None, + result=-1, + result_ref=None, + physic=None, init_dict=None, init_str=None, ): @@ -58,45 +65,51 @@ def __init__( if init_dict is not None: # Initialisation by dict assert type(init_dict) is dict # Overwrite default value with init_dict content - if "name" in list(init_dict.keys()): - name = init_dict["name"] if "type_const" in list(init_dict.keys()): type_const = init_dict["type_const"] if "value" in list(init_dict.keys()): value = init_dict["value"] - if "get_variable" in list(init_dict.keys()): - get_variable = init_dict["get_variable"] + if "name" in list(init_dict.keys()): + name = init_dict["name"] + if "symbol" in list(init_dict.keys()): + symbol = init_dict["symbol"] + if "unit" in list(init_dict.keys()): + unit = init_dict["unit"] + if "keeper" in list(init_dict.keys()): + keeper = init_dict["keeper"] + if "error_keeper" in list(init_dict.keys()): + error_keeper = init_dict["error_keeper"] + if "result" in list(init_dict.keys()): + result = init_dict["result"] + if "result_ref" in list(init_dict.keys()): + result_ref = init_dict["result_ref"] + if "physic" in list(init_dict.keys()): + physic = init_dict["physic"] # Set the properties (value check and convertion are done in setter) - self.parent = None - self.name = name self.type_const = type_const self.value = value - self.get_variable = get_variable - - # The class is frozen, for now it's impossible to add new properties - self._freeze() + # Call DataKeeper init + super(OptiConstraint, self).__init__( + name=name, + symbol=symbol, + unit=unit, + keeper=keeper, + error_keeper=error_keeper, + result=result, + result_ref=result_ref, + physic=physic, + ) + # The class is frozen (in DataKeeper init), for now it's impossible to + # add new properties def __str__(self): """Convert this object in a readeable string (for print)""" OptiConstraint_str = "" - if self.parent is None: - OptiConstraint_str += "parent = None " + linesep - else: - OptiConstraint_str += ( - "parent = " + str(type(self.parent)) + " object" + linesep - ) - OptiConstraint_str += 'name = "' + str(self.name) + '"' + linesep + # Get the properties inherited from DataKeeper + OptiConstraint_str += super(OptiConstraint, self).__str__() OptiConstraint_str += 'type_const = "' + str(self.type_const) + '"' + linesep OptiConstraint_str += "value = " + str(self.value) + linesep - if self._get_variable_str is not None: - OptiConstraint_str += "get_variable = " + self._get_variable_str + linesep - elif self._get_variable_func is not None: - OptiConstraint_str += ( - "get_variable = " + str(self._get_variable_func) + linesep - ) - else: - OptiConstraint_str += "get_variable = None" + linesep + linesep return OptiConstraint_str def __eq__(self, other): @@ -104,14 +117,14 @@ def __eq__(self, other): if type(other) != type(self): return False - if other.name != self.name: + + # Check the properties inherited from DataKeeper + if not super(OptiConstraint, self).__eq__(other): return False if other.type_const != self.type_const: return False if other.value != self.value: return False - if other._get_variable_str != self._get_variable_str: - return False return True def compare(self, other, name="self", ignore_list=None, is_add_value=False): @@ -122,14 +135,13 @@ def compare(self, other, name="self", ignore_list=None, is_add_value=False): if type(other) != type(self): return ["type(" + name + ")"] diff_list = list() - if other._name != self._name: - if is_add_value: - val_str = ( - " (self=" + str(self._name) + ", other=" + str(other._name) + ")" - ) - diff_list.append(name + ".name" + val_str) - else: - diff_list.append(name + ".name") + + # Check the properties inherited from DataKeeper + diff_list.extend( + super(OptiConstraint, self).compare( + other, name=name, ignore_list=ignore_list, is_add_value=is_add_value + ) + ) if other._type_const != self._type_const: if is_add_value: val_str = ( @@ -157,8 +169,6 @@ def compare(self, other, name="self", ignore_list=None, is_add_value=False): diff_list.append(name + ".value" + val_str) else: diff_list.append(name + ".value") - if other._get_variable_str != self._get_variable_str: - diff_list.append(name + ".get_variable") # Filter ignore differences diff_list = list(filter(lambda x: x not in ignore_list, diff_list)) return diff_list @@ -167,10 +177,11 @@ def __sizeof__(self): """Return the size in memory of the object (including all subobject)""" S = 0 # Full size of the object - S += getsizeof(self.name) + + # Get size of the properties inherited from DataKeeper + S += super(OptiConstraint, self).__sizeof__() S += getsizeof(self.type_const) S += getsizeof(self.value) - S += getsizeof(self._get_variable_str) return S def as_dict(self, type_handle_ndarray=0, keep_function=False, **kwargs): @@ -184,23 +195,16 @@ def as_dict(self, type_handle_ndarray=0, keep_function=False, **kwargs): and may prevent json serializability. """ - OptiConstraint_dict = dict() - OptiConstraint_dict["name"] = self.name + # Get the properties inherited from DataKeeper + OptiConstraint_dict = super(OptiConstraint, self).as_dict( + type_handle_ndarray=type_handle_ndarray, + keep_function=keep_function, + **kwargs + ) OptiConstraint_dict["type_const"] = self.type_const OptiConstraint_dict["value"] = self.value - if self._get_variable_str is not None: - OptiConstraint_dict["get_variable"] = self._get_variable_str - elif keep_function: - OptiConstraint_dict["get_variable"] = self.get_variable - else: - OptiConstraint_dict["get_variable"] = None - if self.get_variable is not None: - self.get_logger().warning( - "OptiConstraint.as_dict(): " - + f"Function {self.get_variable.__name__} is not serializable " - + "and will be converted to None." - ) # The class name is added to the dict for deserialisation purpose + # Overwrite the mother class name OptiConstraint_dict["__class__"] = "OptiConstraint" return OptiConstraint_dict @@ -208,47 +212,50 @@ def copy(self): """Creates a deepcopy of the object""" # Handle deepcopy of all the properties - name_val = self.name type_const_val = self.type_const value_val = self.value - if self._get_variable_str is not None: - get_variable_val = self._get_variable_str + name_val = self.name + symbol_val = self.symbol + unit_val = self.unit + if self._keeper_str is not None: + keeper_val = self._keeper_str + else: + keeper_val = self._keeper_func + if self._error_keeper_str is not None: + error_keeper_val = self._error_keeper_str + else: + error_keeper_val = self._error_keeper_func + if self.result is None: + result_val = None else: - get_variable_val = self._get_variable_func + result_val = self.result.copy() + if hasattr(self.result_ref, "copy"): + result_ref_val = self.result_ref.copy() + else: + result_ref_val = self.result_ref + physic_val = self.physic # Creates new object of the same type with the copied properties obj_copy = type(self)( - name=name_val, type_const=type_const_val, value=value_val, - get_variable=get_variable_val, + name=name_val, + symbol=symbol_val, + unit=unit_val, + keeper=keeper_val, + error_keeper=error_keeper_val, + result=result_val, + result_ref=result_ref_val, + physic=physic_val, ) return obj_copy def _set_None(self): """Set all the properties to None (except pyleecan object)""" - self.name = None self.type_const = None self.value = None - self.get_variable = None - - def _get_name(self): - """getter of name""" - return self._name - - def _set_name(self, value): - """setter of name""" - check_var("name", value, "str") - self._name = value - - name = property( - fget=_get_name, - fset=_set_name, - doc="""name of the design variable - - :Type: str - """, - ) + # Set to None the properties inherited from DataKeeper + super(OptiConstraint, self)._set_None() def _get_type_const(self): """getter of type_const""" @@ -262,7 +269,7 @@ def _set_type_const(self, value): type_const = property( fget=_get_type_const, fset=_set_type_const, - doc="""Type of comparison ( "==", "<=", ">=", "<",">") + doc=u"""Type of comparison ( "==", "<=", ">=", "<",">") :Type: str """, @@ -280,43 +287,8 @@ def _set_value(self, value): value = property( fget=_get_value, fset=_set_value, - doc="""Value to compare + doc=u"""Value to compare :Type: float """, ) - - def _get_get_variable(self): - """getter of get_variable""" - return self._get_variable_func - - def _set_get_variable(self, value): - """setter of get_variable""" - if value is None: - self._get_variable_str = None - self._get_variable_func = None - elif isinstance(value, str) and "lambda" in value: - self._get_variable_str = value - self._get_variable_func = eval(value) - elif isinstance(value, str) and isfile(value) and value[-3:] == ".py": - self._get_variable_str = value - f = open(value, "r") - exec(f.read(), globals()) - self._get_variable_func = eval(basename(value[:-3])) - elif callable(value): - self._get_variable_str = None - self._get_variable_func = value - else: - raise CheckTypeError( - "For property get_variable Expected function or str (path to python file or lambda), got: " - + str(type(value)) - ) - - get_variable = property( - fget=_get_get_variable, - fset=_set_get_variable, - doc="""Function to get the variable to compare - - :Type: function - """, - ) diff --git a/pyleecan/Functions/Optimization/check_cstr.py b/pyleecan/Functions/Optimization/check_cstr.py index 970ef492e..1c741d37b 100644 --- a/pyleecan/Functions/Optimization/check_cstr.py +++ b/pyleecan/Functions/Optimization/check_cstr.py @@ -25,7 +25,7 @@ def check_cstr(solver, indiv): # Browse constraints for constraint in solver.problem.constraint: # Compute value to compare - var_val = constraint.get_variable(indiv.output) + var_val = constraint.keeper(indiv.output) # Compare the value with the constraint type_const = constraint.type_const diff --git a/pyleecan/Generator/ClassesRef/Optimization/OptiConstraint.csv b/pyleecan/Generator/ClassesRef/Optimization/OptiConstraint.csv index 10955cadf..13eb22a77 100644 --- a/pyleecan/Generator/ClassesRef/Optimization/OptiConstraint.csv +++ b/pyleecan/Generator/ClassesRef/Optimization/OptiConstraint.csv @@ -1,5 +1,3 @@ Variable name,Unit,Description (EN),Size,Type,Default value,Minimum value,Maximum value,,Package,Inherit,Methods,Constante Name,Constante Value,Description classe,Classe fille -name,,name of the design variable,1,str,,,,,Optimization,,,VERSION,1,Constraint of the optimization problem, -type_const,,"Type of comparison ( ""=="", ""<="", "">="", ""<"","">"")",1,str,<=,,,,,,,,,, +type_const,,"Type of comparison ( ""=="", ""<="", "">="", ""<"","">"")",1,str,<=,,,,Optimization,DataKeeper,,VERSION,1,Constraint of the optimization problem, value,,Value to compare,2,float,0,,,,,,,,,, -get_variable,,Function to get the variable to compare,1,function,None,,,,,,,,,, diff --git a/pyleecan/Methods/Optimization/OptiBayesAlgSmoot/check_optimization_input.py b/pyleecan/Methods/Optimization/OptiBayesAlgSmoot/check_optimization_input.py index c683c846b..4a079c42f 100644 --- a/pyleecan/Methods/Optimization/OptiBayesAlgSmoot/check_optimization_input.py +++ b/pyleecan/Methods/Optimization/OptiBayesAlgSmoot/check_optimization_input.py @@ -99,9 +99,9 @@ def check_optimization_input(self): ) raise OptimizationAttributeError(mess) # Check getter - elif not callable(cstr.get_variable): + elif not callable(cstr.keeper): mess = ( - "The constraint '{}' function get_variable is not callable.".format( + "The constraint '{}' function keeper is not callable.".format( cstr.name ) ) diff --git a/pyleecan/Methods/Optimization/OptiBayesAlgSmoot/eval_const.py b/pyleecan/Methods/Optimization/OptiBayesAlgSmoot/eval_const.py index 7dbae0ca7..72b30ea32 100644 --- a/pyleecan/Methods/Optimization/OptiBayesAlgSmoot/eval_const.py +++ b/pyleecan/Methods/Optimization/OptiBayesAlgSmoot/eval_const.py @@ -13,7 +13,7 @@ def eval_const(self, constraint, input_x): var.setter(self.xoutput.simu, x[i]) i += 1 - const_value = constraint.get_variable(self.xoutput) + const_value = constraint.keeper(self.xoutput) if constraint.type_const == "<=": constraint_values.append(const_value - constraint.value) elif constraint.type_const == ">=": diff --git a/pyleecan/Methods/Optimization/OptiGenAlgNsga2Deap/check_optimization_input.py b/pyleecan/Methods/Optimization/OptiGenAlgNsga2Deap/check_optimization_input.py index 3a8ef6361..8c16e957f 100644 --- a/pyleecan/Methods/Optimization/OptiGenAlgNsga2Deap/check_optimization_input.py +++ b/pyleecan/Methods/Optimization/OptiGenAlgNsga2Deap/check_optimization_input.py @@ -108,9 +108,9 @@ def check_optimization_input(self): ) raise OptimizationAttributeError(mess) # Check getter - elif not callable(cstr.get_variable): + elif not callable(cstr.keeper): mess = ( - "The constraint '{}' function get_variable is not callable.".format( + "The constraint '{}' function keeper is not callable.".format( cstr.name ) ) From f008c1bb340bbb009222ec2f1f4b8dbc17d9377e Mon Sep 17 00:00:00 2001 From: BenjaminGabet Date: Fri, 2 Dec 2022 11:19:13 +0100 Subject: [PATCH 02/10] [NF] adding two new class : OptiDesignVarSet & OptiDesignVarInterval --- Tests/Plot/test_ICEM_2020.py | 8 +- .../Optimization/test_Binh_and_Korn.py | 8 +- .../Optimization/test_Binh_and_Korn_Bayes.py | 8 +- .../Optimization/test_opti_datakeeper_list.py | 8 +- .../Optimization/test_opti_preprocessing.py | 8 +- Tests/Validation/Optimization/test_zdt3.py | 5 +- .../Optimization/test_zdt3_Bayes.py | 5 +- pyleecan/Classes/Class_Dict.json | 53 +++-- pyleecan/Classes/OptiDesignVar.py | 44 +--- pyleecan/Classes/OptiDesignVarInterval.py | 200 ++++++++++++++++++ pyleecan/Classes/OptiDesignVarSet.py | 200 ++++++++++++++++++ pyleecan/Classes/import_all.py | 2 + pyleecan/Functions/load_switch.py | 2 + .../ClassesRef/Optimization/OptiDesignVar.csv | 3 +- .../Optimization/OptiDesignVarInterval.csv | 2 + .../Optimization/OptiDesignVarSet.csv | 2 + .../check_optimization_input.py | 14 +- .../check_optimization_input.py | 14 +- .../OptiGenAlgNsga2Deap/mutate.py | 6 +- 19 files changed, 488 insertions(+), 104 deletions(-) create mode 100644 pyleecan/Classes/OptiDesignVarInterval.py create mode 100644 pyleecan/Classes/OptiDesignVarSet.py create mode 100644 pyleecan/Generator/ClassesRef/Optimization/OptiDesignVarInterval.csv create mode 100644 pyleecan/Generator/ClassesRef/Optimization/OptiDesignVarSet.csv diff --git a/Tests/Plot/test_ICEM_2020.py b/Tests/Plot/test_ICEM_2020.py index b502f52e2..425341baf 100644 --- a/Tests/Plot/test_ICEM_2020.py +++ b/Tests/Plot/test_ICEM_2020.py @@ -20,7 +20,7 @@ from pyleecan.Classes.Simu1 import Simu1 from pyleecan.Classes.Output import Output from pyleecan.Classes.SlotUD2 import SlotUD2 -from pyleecan.Classes.OptiDesignVar import OptiDesignVar +from pyleecan.Classes.OptiDesignVarInterval import OptiDesignVarInterval from pyleecan.Classes.OptiObjective import OptiObjective from pyleecan.Classes.OptiProblem import OptiProblem from pyleecan.Classes.ImportMatrixVal import ImportMatrixVal @@ -745,11 +745,10 @@ def test_Optimization_problem(): # Design variables my_vars = [ - OptiDesignVar( + OptiDesignVarInterval( name="Stator slot opening", symbol="W0", unit="m", - type_var="interval", space=[ 0.2 * output.simu.machine.stator.slot.W2, output.simu.machine.stator.slot.W2, @@ -757,11 +756,10 @@ def test_Optimization_problem(): get_value="lambda space: random.uniform(*space)", setter="simu.machine.stator.slot.W0", ), - OptiDesignVar( + OptiDesignVarInterval( name="Rotor magnet width", symbol="Wmag", unit="m", - type_var="interval", space=[ 0.5 * output.simu.machine.rotor.slot.W0, 0.99 * output.simu.machine.rotor.slot.W0, diff --git a/Tests/Validation/Optimization/test_Binh_and_Korn.py b/Tests/Validation/Optimization/test_Binh_and_Korn.py index 1f4c2ebc2..0def816b3 100644 --- a/Tests/Validation/Optimization/test_Binh_and_Korn.py +++ b/Tests/Validation/Optimization/test_Binh_and_Korn.py @@ -15,7 +15,7 @@ from pyleecan.Classes.Simu1 import Simu1 from pyleecan.Classes.OPslip import OPslip from pyleecan.Classes.Output import Output -from pyleecan.Classes.OptiDesignVar import OptiDesignVar +from pyleecan.Classes.OptiDesignVarInterval import OptiDesignVarInterval from pyleecan.Classes.OptiObjective import OptiObjective from pyleecan.Classes.OptiConstraint import OptiConstraint from pyleecan.Classes.OptiProblem import OptiProblem @@ -79,18 +79,16 @@ def test_Binh_and_Korn(): # ### Design variable my_vars = [ - OptiDesignVar( + OptiDesignVarInterval( name="Rotor slot height", symbol="RH0", - type_var="interval", space=[0, 5], # May generate error in FEMM get_value="lambda space: random.uniform(*space)", setter="simu.machine.rotor.slot.H0", ), - OptiDesignVar( + OptiDesignVarInterval( name="Stator slot height", symbol="SH0", - type_var="interval", space=[0, 3], # May generate error in FEMM get_value="lambda space: random.uniform(*space)", setter="simu.machine.stator.slot.H0", diff --git a/Tests/Validation/Optimization/test_Binh_and_Korn_Bayes.py b/Tests/Validation/Optimization/test_Binh_and_Korn_Bayes.py index 254b47e3b..c55c3e555 100644 --- a/Tests/Validation/Optimization/test_Binh_and_Korn_Bayes.py +++ b/Tests/Validation/Optimization/test_Binh_and_Korn_Bayes.py @@ -15,7 +15,7 @@ from pyleecan.Classes.Simu1 import Simu1 from pyleecan.Classes.OPslip import OPslip from pyleecan.Classes.Output import Output -from pyleecan.Classes.OptiDesignVar import OptiDesignVar +from pyleecan.Classes.OptiDesignVarInterval import OptiDesignVarInterval from pyleecan.Classes.OptiObjective import OptiObjective from pyleecan.Classes.OptiConstraint import OptiConstraint from pyleecan.Classes.OptiProblem import OptiProblem @@ -78,18 +78,16 @@ def test_Binh_and_Korn(): # ### Design variable my_vars = [ - OptiDesignVar( + OptiDesignVarInterval( name="Rotor slot height", symbol="RH0", - type_var="interval", space=[0, 5], # May generate error in FEMM get_value="lambda space: random.uniform(*space)", setter="simu.machine.rotor.slot.H0", ), - OptiDesignVar( + OptiDesignVarInterval( name="Stator slot height", symbol="SH0", - type_var="interval", space=[0, 3], # May generate error in FEMM get_value="lambda space: random.uniform(*space)", setter="simu.machine.stator.slot.H0", diff --git a/Tests/Validation/Optimization/test_opti_datakeeper_list.py b/Tests/Validation/Optimization/test_opti_datakeeper_list.py index 72c496fb3..98235d848 100644 --- a/Tests/Validation/Optimization/test_opti_datakeeper_list.py +++ b/Tests/Validation/Optimization/test_opti_datakeeper_list.py @@ -11,7 +11,7 @@ import pytest from pyleecan.Classes.Simu1 import Simu1 from pyleecan.Classes.DataKeeper import DataKeeper -from pyleecan.Classes.OptiDesignVar import OptiDesignVar +from pyleecan.Classes.OptiDesignVarInterval import OptiDesignVarInterval from pyleecan.Classes.OptiObjective import OptiObjective from pyleecan.Classes.OptiProblem import OptiProblem from pyleecan.Classes.OptiGenAlgNsga2Deap import OptiGenAlgNsga2Deap @@ -35,18 +35,16 @@ def test_opti_datakeeper_list(): # Design variable my_vars = [ - OptiDesignVar( + OptiDesignVarInterval( name="Rotor slot height", symbol="RH0", - type_var="interval", space=[0, 5], # May generate error in FEMM get_value=lambda space: random.uniform(*space), setter="simu.machine.rotor.slot.H0", ), - OptiDesignVar( + OptiDesignVarInterval( name="Stator slot height", symbol="SH0", - type_var="interval", space=[0, 3], # May generate error in FEMM get_value=lambda space: random.uniform(*space), setter="simu.machine.stator.slot.H0", diff --git a/Tests/Validation/Optimization/test_opti_preprocessing.py b/Tests/Validation/Optimization/test_opti_preprocessing.py index 6e22ca83a..7c99f7271 100644 --- a/Tests/Validation/Optimization/test_opti_preprocessing.py +++ b/Tests/Validation/Optimization/test_opti_preprocessing.py @@ -10,7 +10,7 @@ from os.path import join import pytest from pyleecan.Classes.Simu1 import Simu1 -from pyleecan.Classes.OptiDesignVar import OptiDesignVar +from pyleecan.Classes.OptiDesignVarInterval import OptiDesignVarInterval from pyleecan.Classes.OptiObjective import OptiObjective from pyleecan.Classes.OptiProblem import OptiProblem from pyleecan.Classes.OptiGenAlgNsga2Deap import OptiGenAlgNsga2Deap @@ -35,18 +35,16 @@ def test_opti_preprocessing(): # Design variable my_vars = [ - OptiDesignVar( + OptiDesignVarInterval( name="Rotor slot height", symbol="RH0", - type_var="interval", space=[0, 5], # May generate error in FEMM get_value=lambda space: random.uniform(*space), setter="simu.machine.rotor.slot.H0", ), - OptiDesignVar( + OptiDesignVarInterval( name="Stator slot height", symbol="SH0", - type_var="interval", space=[0, 3], # May generate error in FEMM get_value=lambda space: random.uniform(*space), setter="simu.machine.stator.slot.H0", diff --git a/Tests/Validation/Optimization/test_zdt3.py b/Tests/Validation/Optimization/test_zdt3.py index 94ebf5afb..184cecef0 100644 --- a/Tests/Validation/Optimization/test_zdt3.py +++ b/Tests/Validation/Optimization/test_zdt3.py @@ -11,7 +11,7 @@ from pyleecan.Classes.MagFEMM import MagFEMM from pyleecan.Classes.Simu1 import Simu1 from pyleecan.Classes.Output import Output -from pyleecan.Classes.OptiDesignVar import OptiDesignVar +from pyleecan.Classes.OptiDesignVarInterval import OptiDesignVarInterval from pyleecan.Classes.OptiObjective import OptiObjective from pyleecan.Classes.OptiConstraint import OptiConstraint from pyleecan.Classes.OptiProblem import OptiProblem @@ -87,10 +87,9 @@ def new_setter(simu, value): for i in range(30): my_vars.append( - OptiDesignVar( + OptiDesignVarInterval( name="Ir({})".format(i), symbol="var_" + str(i), - type_var="interval", space=[0, 1], get_value=lambda space: np.random.uniform(*space), setter=gen_setter(i), diff --git a/Tests/Validation/Optimization/test_zdt3_Bayes.py b/Tests/Validation/Optimization/test_zdt3_Bayes.py index 61394aa1d..a3bd8e829 100644 --- a/Tests/Validation/Optimization/test_zdt3_Bayes.py +++ b/Tests/Validation/Optimization/test_zdt3_Bayes.py @@ -11,7 +11,7 @@ from pyleecan.Classes.MagFEMM import MagFEMM from pyleecan.Classes.Simu1 import Simu1 from pyleecan.Classes.Output import Output -from pyleecan.Classes.OptiDesignVar import OptiDesignVar +from pyleecan.Classes.OptiDesignVarInterval import OptiDesignVarInterval from pyleecan.Classes.OptiObjective import OptiObjective from pyleecan.Classes.OptiConstraint import OptiConstraint from pyleecan.Classes.OptiProblem import OptiProblem @@ -87,10 +87,9 @@ def new_setter(simu, value): for i in range(30): my_vars.append( - OptiDesignVar( + OptiDesignVarInterval( name="Ir({})".format(i), symbol="var_" + str(i), - type_var="interval", space=[0, 1], get_value=lambda space: np.random.uniform(*space), setter=gen_setter(i), diff --git a/pyleecan/Classes/Class_Dict.json b/pyleecan/Classes/Class_Dict.json index 4601d2c0f..cc2d1b41d 100644 --- a/pyleecan/Classes/Class_Dict.json +++ b/pyleecan/Classes/Class_Dict.json @@ -8945,8 +8945,11 @@ "value": "1" } ], - "daughters": [], - "desc": "Optimization", + "daughters": [ + "OptiDesignVarInterval", + "OptiDesignVarSet" + ], + "desc": "Abstract class for OptiDesignVar (Optimization)", "is_internal": false, "methods": [], "mother": "ParamExplorer", @@ -8954,16 +8957,6 @@ "package": "Optimization", "path": "pyleecan/Generator/ClassesRef/Optimization/OptiDesignVar.csv", "properties": [ - { - "as_dict": "", - "desc": "Type of the variable interval or set.", - "max": "", - "min": "", - "name": "type_var", - "type": "str", - "unit": "", - "value": "interval" - }, { "as_dict": "", "desc": "Space of the variable", @@ -8989,6 +8982,40 @@ } ] }, + "OptiDesignVarInterval": { + "constants": [ + { + "name": "VERSION", + "value": "1" + } + ], + "daughters": [], + "desc": "Optimization", + "is_internal": false, + "methods": [], + "mother": "OptiDesignVar", + "name": "OptiDesignVarInterval", + "package": "Optimization", + "path": "pyleecan/Generator/ClassesRef/Optimization/OptiDesignVarInterval.csv", + "properties": [] + }, + "OptiDesignVarSet": { + "constants": [ + { + "name": "VERSION", + "value": "1" + } + ], + "daughters": [], + "desc": "Optimization", + "is_internal": false, + "methods": [], + "mother": "OptiDesignVar", + "name": "OptiDesignVarSet", + "package": "Optimization", + "path": "pyleecan/Generator/ClassesRef/Optimization/OptiDesignVarSet.csv", + "properties": [] + }, "OptiGenAlg": { "constants": [ { @@ -10534,6 +10561,8 @@ ], "daughters": [ "OptiDesignVar", + "OptiDesignVarInterval", + "OptiDesignVarSet", "ParamExplorerInterval", "ParamExplorerSet" ], diff --git a/pyleecan/Classes/OptiDesignVar.py b/pyleecan/Classes/OptiDesignVar.py index 0df448230..781273a41 100644 --- a/pyleecan/Classes/OptiDesignVar.py +++ b/pyleecan/Classes/OptiDesignVar.py @@ -25,7 +25,7 @@ class OptiDesignVar(ParamExplorer): - """Optimization""" + """Abstract class for OptiDesignVar (Optimization)""" VERSION = 1 @@ -36,7 +36,6 @@ class OptiDesignVar(ParamExplorer): def __init__( self, - type_var="interval", space=[0, 1], get_value=None, name="", @@ -62,8 +61,6 @@ def __init__( if init_dict is not None: # Initialisation by dict assert type(init_dict) is dict # Overwrite default value with init_dict content - if "type_var" in list(init_dict.keys()): - type_var = init_dict["type_var"] if "space" in list(init_dict.keys()): space = init_dict["space"] if "get_value" in list(init_dict.keys()): @@ -79,7 +76,6 @@ def __init__( if "getter" in list(init_dict.keys()): getter = init_dict["getter"] # Set the properties (value check and convertion are done in setter) - self.type_var = type_var self.space = space self.get_value = get_value # Call ParamExplorer init @@ -95,7 +91,6 @@ def __str__(self): OptiDesignVar_str = "" # Get the properties inherited from ParamExplorer OptiDesignVar_str += super(OptiDesignVar, self).__str__() - OptiDesignVar_str += 'type_var = "' + str(self.type_var) + '"' + linesep OptiDesignVar_str += ( "space = " + linesep @@ -119,8 +114,6 @@ def __eq__(self, other): # Check the properties inherited from ParamExplorer if not super(OptiDesignVar, self).__eq__(other): return False - if other.type_var != self.type_var: - return False if other.space != self.space: return False if other._get_value_str != self._get_value_str: @@ -142,18 +135,6 @@ def compare(self, other, name="self", ignore_list=None, is_add_value=False): other, name=name, ignore_list=ignore_list, is_add_value=is_add_value ) ) - if other._type_var != self._type_var: - if is_add_value: - val_str = ( - " (self=" - + str(self._type_var) - + ", other=" - + str(other._type_var) - + ")" - ) - diff_list.append(name + ".type_var" + val_str) - else: - diff_list.append(name + ".type_var") if other._space != self._space: if is_add_value: val_str = ( @@ -175,7 +156,6 @@ def __sizeof__(self): # Get size of the properties inherited from ParamExplorer S += super(OptiDesignVar, self).__sizeof__() - S += getsizeof(self.type_var) if self.space is not None: for value in self.space: S += getsizeof(value) @@ -199,7 +179,6 @@ def as_dict(self, type_handle_ndarray=0, keep_function=False, **kwargs): keep_function=keep_function, **kwargs, ) - OptiDesignVar_dict["type_var"] = self.type_var OptiDesignVar_dict["space"] = ( self.space.copy() if self.space is not None else None ) @@ -224,7 +203,6 @@ def copy(self): """Creates a deepcopy of the object""" # Handle deepcopy of all the properties - type_var_val = self.type_var if self.space is None: space_val = None else: @@ -246,7 +224,6 @@ def copy(self): getter_val = self._getter_func # Creates new object of the same type with the copied properties obj_copy = type(self)( - type_var=type_var_val, space=space_val, get_value=get_value_val, name=name_val, @@ -260,30 +237,11 @@ def copy(self): def _set_None(self): """Set all the properties to None (except pyleecan object)""" - self.type_var = None self.space = None self.get_value = None # Set to None the properties inherited from ParamExplorer super(OptiDesignVar, self)._set_None() - def _get_type_var(self): - """getter of type_var""" - return self._type_var - - def _set_type_var(self, value): - """setter of type_var""" - check_var("type_var", value, "str") - self._type_var = value - - type_var = property( - fget=_get_type_var, - fset=_set_type_var, - doc="""Type of the variable interval or set. - - :Type: str - """, - ) - def _get_space(self): """getter of space""" return self._space diff --git a/pyleecan/Classes/OptiDesignVarInterval.py b/pyleecan/Classes/OptiDesignVarInterval.py new file mode 100644 index 000000000..5a56d7260 --- /dev/null +++ b/pyleecan/Classes/OptiDesignVarInterval.py @@ -0,0 +1,200 @@ +# -*- coding: utf-8 -*- +# File generated according to Generator/ClassesRef/Optimization/OptiDesignVarInterval.csv +# WARNING! All changes made in this file will be lost! +"""Method code available at https://github.com/Eomys/pyleecan/tree/master/pyleecan/Methods/Optimization/OptiDesignVarInterval +""" + +from os import linesep +from sys import getsizeof +from logging import getLogger +from ._check import check_var, raise_ +from ..Functions.get_logger import get_logger +from ..Functions.save import save +from ..Functions.load import load_init_dict +from ..Functions.Load.import_class import import_class +from copy import deepcopy +from .OptiDesignVar import OptiDesignVar + +from ntpath import basename +from os.path import isfile +from ._check import CheckTypeError +import numpy as np +import random +from numpy import isnan +from ._check import InitUnKnowClassError + + +class OptiDesignVarInterval(OptiDesignVar): + """Optimization""" + + VERSION = 1 + + # generic save method is available in all object + save = save + # get_logger method is available in all object + get_logger = get_logger + + def __init__( + self, + space=[0, 1], + get_value=None, + name="", + symbol="", + unit="", + setter=None, + getter=None, + init_dict=None, + init_str=None, + ): + """Constructor of the class. Can be use in three ways : + - __init__ (arg1 = 1, arg3 = 5) every parameters have name and default values + for pyleecan type, -1 will call the default constructor + - __init__ (init_dict = d) d must be a dictionary with property names as keys + - __init__ (init_str = s) s must be a string + s is the file path to load + + ndarray or list can be given for Vector and Matrix + object or dict can be given for pyleecan Object""" + + if init_str is not None: # Load from a file + init_dict = load_init_dict(init_str)[1] + if init_dict is not None: # Initialisation by dict + assert type(init_dict) is dict + # Overwrite default value with init_dict content + if "space" in list(init_dict.keys()): + space = init_dict["space"] + if "get_value" in list(init_dict.keys()): + get_value = init_dict["get_value"] + if "name" in list(init_dict.keys()): + name = init_dict["name"] + if "symbol" in list(init_dict.keys()): + symbol = init_dict["symbol"] + if "unit" in list(init_dict.keys()): + unit = init_dict["unit"] + if "setter" in list(init_dict.keys()): + setter = init_dict["setter"] + if "getter" in list(init_dict.keys()): + getter = init_dict["getter"] + # Set the properties (value check and convertion are done in setter) + # Call OptiDesignVar init + super(OptiDesignVarInterval, self).__init__( + space=space, + get_value=get_value, + name=name, + symbol=symbol, + unit=unit, + setter=setter, + getter=getter, + ) + # The class is frozen (in OptiDesignVar init), for now it's impossible to + # add new properties + + def __str__(self): + """Convert this object in a readeable string (for print)""" + + OptiDesignVarInterval_str = "" + # Get the properties inherited from OptiDesignVar + OptiDesignVarInterval_str += super(OptiDesignVarInterval, self).__str__() + return OptiDesignVarInterval_str + + def __eq__(self, other): + """Compare two objects (skip parent)""" + + if type(other) != type(self): + return False + + # Check the properties inherited from OptiDesignVar + if not super(OptiDesignVarInterval, self).__eq__(other): + return False + return True + + def compare(self, other, name="self", ignore_list=None, is_add_value=False): + """Compare two objects and return list of differences""" + + if ignore_list is None: + ignore_list = list() + if type(other) != type(self): + return ["type(" + name + ")"] + diff_list = list() + + # Check the properties inherited from OptiDesignVar + diff_list.extend( + super(OptiDesignVarInterval, self).compare( + other, name=name, ignore_list=ignore_list, is_add_value=is_add_value + ) + ) + # Filter ignore differences + diff_list = list(filter(lambda x: x not in ignore_list, diff_list)) + return diff_list + + def __sizeof__(self): + """Return the size in memory of the object (including all subobject)""" + + S = 0 # Full size of the object + + # Get size of the properties inherited from OptiDesignVar + S += super(OptiDesignVarInterval, self).__sizeof__() + return S + + def as_dict(self, type_handle_ndarray=0, keep_function=False, **kwargs): + """ + Convert this object in a json serializable dict (can be use in __init__). + type_handle_ndarray: int + How to handle ndarray (0: tolist, 1: copy, 2: nothing) + keep_function : bool + True to keep the function object, else return str + Optional keyword input parameter is for internal use only + and may prevent json serializability. + """ + + # Get the properties inherited from OptiDesignVar + OptiDesignVarInterval_dict = super(OptiDesignVarInterval, self).as_dict( + type_handle_ndarray=type_handle_ndarray, + keep_function=keep_function, + **kwargs + ) + # The class name is added to the dict for deserialisation purpose + # Overwrite the mother class name + OptiDesignVarInterval_dict["__class__"] = "OptiDesignVarInterval" + return OptiDesignVarInterval_dict + + def copy(self): + """Creates a deepcopy of the object""" + + # Handle deepcopy of all the properties + if self.space is None: + space_val = None + else: + space_val = self.space.copy() + if self._get_value_str is not None: + get_value_val = self._get_value_str + else: + get_value_val = self._get_value_func + name_val = self.name + symbol_val = self.symbol + unit_val = self.unit + if self._setter_str is not None: + setter_val = self._setter_str + else: + setter_val = self._setter_func + if self._getter_str is not None: + getter_val = self._getter_str + else: + getter_val = self._getter_func + # Creates new object of the same type with the copied properties + obj_copy = type(self)( + space=space_val, + get_value=get_value_val, + name=name_val, + symbol=symbol_val, + unit=unit_val, + setter=setter_val, + getter=getter_val, + ) + return obj_copy + + def _set_None(self): + """Set all the properties to None (except pyleecan object)""" + + # Set to None the properties inherited from OptiDesignVar + super(OptiDesignVarInterval, self)._set_None() diff --git a/pyleecan/Classes/OptiDesignVarSet.py b/pyleecan/Classes/OptiDesignVarSet.py new file mode 100644 index 000000000..f6a913b4b --- /dev/null +++ b/pyleecan/Classes/OptiDesignVarSet.py @@ -0,0 +1,200 @@ +# -*- coding: utf-8 -*- +# File generated according to Generator/ClassesRef/Optimization/OptiDesignVarSet.csv +# WARNING! All changes made in this file will be lost! +"""Method code available at https://github.com/Eomys/pyleecan/tree/master/pyleecan/Methods/Optimization/OptiDesignVarSet +""" + +from os import linesep +from sys import getsizeof +from logging import getLogger +from ._check import check_var, raise_ +from ..Functions.get_logger import get_logger +from ..Functions.save import save +from ..Functions.load import load_init_dict +from ..Functions.Load.import_class import import_class +from copy import deepcopy +from .OptiDesignVar import OptiDesignVar + +from ntpath import basename +from os.path import isfile +from ._check import CheckTypeError +import numpy as np +import random +from numpy import isnan +from ._check import InitUnKnowClassError + + +class OptiDesignVarSet(OptiDesignVar): + """Optimization""" + + VERSION = 1 + + # generic save method is available in all object + save = save + # get_logger method is available in all object + get_logger = get_logger + + def __init__( + self, + space=[0, 1], + get_value=None, + name="", + symbol="", + unit="", + setter=None, + getter=None, + init_dict=None, + init_str=None, + ): + """Constructor of the class. Can be use in three ways : + - __init__ (arg1 = 1, arg3 = 5) every parameters have name and default values + for pyleecan type, -1 will call the default constructor + - __init__ (init_dict = d) d must be a dictionary with property names as keys + - __init__ (init_str = s) s must be a string + s is the file path to load + + ndarray or list can be given for Vector and Matrix + object or dict can be given for pyleecan Object""" + + if init_str is not None: # Load from a file + init_dict = load_init_dict(init_str)[1] + if init_dict is not None: # Initialisation by dict + assert type(init_dict) is dict + # Overwrite default value with init_dict content + if "space" in list(init_dict.keys()): + space = init_dict["space"] + if "get_value" in list(init_dict.keys()): + get_value = init_dict["get_value"] + if "name" in list(init_dict.keys()): + name = init_dict["name"] + if "symbol" in list(init_dict.keys()): + symbol = init_dict["symbol"] + if "unit" in list(init_dict.keys()): + unit = init_dict["unit"] + if "setter" in list(init_dict.keys()): + setter = init_dict["setter"] + if "getter" in list(init_dict.keys()): + getter = init_dict["getter"] + # Set the properties (value check and convertion are done in setter) + # Call OptiDesignVar init + super(OptiDesignVarSet, self).__init__( + space=space, + get_value=get_value, + name=name, + symbol=symbol, + unit=unit, + setter=setter, + getter=getter, + ) + # The class is frozen (in OptiDesignVar init), for now it's impossible to + # add new properties + + def __str__(self): + """Convert this object in a readeable string (for print)""" + + OptiDesignVarSet_str = "" + # Get the properties inherited from OptiDesignVar + OptiDesignVarSet_str += super(OptiDesignVarSet, self).__str__() + return OptiDesignVarSet_str + + def __eq__(self, other): + """Compare two objects (skip parent)""" + + if type(other) != type(self): + return False + + # Check the properties inherited from OptiDesignVar + if not super(OptiDesignVarSet, self).__eq__(other): + return False + return True + + def compare(self, other, name="self", ignore_list=None, is_add_value=False): + """Compare two objects and return list of differences""" + + if ignore_list is None: + ignore_list = list() + if type(other) != type(self): + return ["type(" + name + ")"] + diff_list = list() + + # Check the properties inherited from OptiDesignVar + diff_list.extend( + super(OptiDesignVarSet, self).compare( + other, name=name, ignore_list=ignore_list, is_add_value=is_add_value + ) + ) + # Filter ignore differences + diff_list = list(filter(lambda x: x not in ignore_list, diff_list)) + return diff_list + + def __sizeof__(self): + """Return the size in memory of the object (including all subobject)""" + + S = 0 # Full size of the object + + # Get size of the properties inherited from OptiDesignVar + S += super(OptiDesignVarSet, self).__sizeof__() + return S + + def as_dict(self, type_handle_ndarray=0, keep_function=False, **kwargs): + """ + Convert this object in a json serializable dict (can be use in __init__). + type_handle_ndarray: int + How to handle ndarray (0: tolist, 1: copy, 2: nothing) + keep_function : bool + True to keep the function object, else return str + Optional keyword input parameter is for internal use only + and may prevent json serializability. + """ + + # Get the properties inherited from OptiDesignVar + OptiDesignVarSet_dict = super(OptiDesignVarSet, self).as_dict( + type_handle_ndarray=type_handle_ndarray, + keep_function=keep_function, + **kwargs + ) + # The class name is added to the dict for deserialisation purpose + # Overwrite the mother class name + OptiDesignVarSet_dict["__class__"] = "OptiDesignVarSet" + return OptiDesignVarSet_dict + + def copy(self): + """Creates a deepcopy of the object""" + + # Handle deepcopy of all the properties + if self.space is None: + space_val = None + else: + space_val = self.space.copy() + if self._get_value_str is not None: + get_value_val = self._get_value_str + else: + get_value_val = self._get_value_func + name_val = self.name + symbol_val = self.symbol + unit_val = self.unit + if self._setter_str is not None: + setter_val = self._setter_str + else: + setter_val = self._setter_func + if self._getter_str is not None: + getter_val = self._getter_str + else: + getter_val = self._getter_func + # Creates new object of the same type with the copied properties + obj_copy = type(self)( + space=space_val, + get_value=get_value_val, + name=name_val, + symbol=symbol_val, + unit=unit_val, + setter=setter_val, + getter=getter_val, + ) + return obj_copy + + def _set_None(self): + """Set all the properties to None (except pyleecan object)""" + + # Set to None the properties inherited from OptiDesignVar + super(OptiDesignVarSet, self)._set_None() diff --git a/pyleecan/Classes/import_all.py b/pyleecan/Classes/import_all.py index 8b033a20e..d1d6ce799 100644 --- a/pyleecan/Classes/import_all.py +++ b/pyleecan/Classes/import_all.py @@ -139,6 +139,8 @@ from ..Classes.OptiBayesAlgSmoot import OptiBayesAlgSmoot from ..Classes.OptiConstraint import OptiConstraint from ..Classes.OptiDesignVar import OptiDesignVar +from ..Classes.OptiDesignVarInterval import OptiDesignVarInterval +from ..Classes.OptiDesignVarSet import OptiDesignVarSet from ..Classes.OptiGenAlg import OptiGenAlg from ..Classes.OptiGenAlgNsga2Deap import OptiGenAlgNsga2Deap from ..Classes.OptiObjective import OptiObjective diff --git a/pyleecan/Functions/load_switch.py b/pyleecan/Functions/load_switch.py index b4939b7b4..b9674353f 100644 --- a/pyleecan/Functions/load_switch.py +++ b/pyleecan/Functions/load_switch.py @@ -141,6 +141,8 @@ "OptiBayesAlgSmoot": OptiBayesAlgSmoot, "OptiConstraint": OptiConstraint, "OptiDesignVar": OptiDesignVar, + "OptiDesignVarInterval": OptiDesignVarInterval, + "OptiDesignVarSet": OptiDesignVarSet, "OptiGenAlg": OptiGenAlg, "OptiGenAlgNsga2Deap": OptiGenAlgNsga2Deap, "OptiObjective": OptiObjective, diff --git a/pyleecan/Generator/ClassesRef/Optimization/OptiDesignVar.csv b/pyleecan/Generator/ClassesRef/Optimization/OptiDesignVar.csv index 1f1216329..82948314e 100644 --- a/pyleecan/Generator/ClassesRef/Optimization/OptiDesignVar.csv +++ b/pyleecan/Generator/ClassesRef/Optimization/OptiDesignVar.csv @@ -1,4 +1,3 @@ Variable name,Unit,Description (EN),Size,Type,Default value,Minimum value,Maximum value,,Package,Inherit,Methods,Constante Name,Constante Value,Description classe,Classe fille -type_var,,Type of the variable interval or set.,1,str,interval,,,,Optimization,ParamExplorer,,VERSION,1,Optimization, -space,,Space of the variable,2,list,"[0,1]",,,,,,,,,, +space,,Space of the variable,2,list,"[0,1]",,,,Optimization,ParamExplorer,,VERSION,1,Abstract class for OptiDesignVar (Optimization), get_value,,Function of the space to initiate the variable,1,function,None,,,,,,,,,, diff --git a/pyleecan/Generator/ClassesRef/Optimization/OptiDesignVarInterval.csv b/pyleecan/Generator/ClassesRef/Optimization/OptiDesignVarInterval.csv new file mode 100644 index 000000000..12486a4ec --- /dev/null +++ b/pyleecan/Generator/ClassesRef/Optimization/OptiDesignVarInterval.csv @@ -0,0 +1,2 @@ +Variable name,Unit,Description (EN),Size,Type,Default value,Minimum value,Maximum value,,Package,Inherit,Methods,Constante Name,Constante Value,Description classe,Classe fille +,,,,,,,,,Optimization,OptiDesignVar,,VERSION,1,Optimization, diff --git a/pyleecan/Generator/ClassesRef/Optimization/OptiDesignVarSet.csv b/pyleecan/Generator/ClassesRef/Optimization/OptiDesignVarSet.csv new file mode 100644 index 000000000..12486a4ec --- /dev/null +++ b/pyleecan/Generator/ClassesRef/Optimization/OptiDesignVarSet.csv @@ -0,0 +1,2 @@ +Variable name,Unit,Description (EN),Size,Type,Default value,Minimum value,Maximum value,,Package,Inherit,Methods,Constante Name,Constante Value,Description classe,Classe fille +,,,,,,,,,Optimization,OptiDesignVar,,VERSION,1,Optimization, diff --git a/pyleecan/Methods/Optimization/OptiBayesAlgSmoot/check_optimization_input.py b/pyleecan/Methods/Optimization/OptiBayesAlgSmoot/check_optimization_input.py index 4a079c42f..f7aaecd47 100644 --- a/pyleecan/Methods/Optimization/OptiBayesAlgSmoot/check_optimization_input.py +++ b/pyleecan/Methods/Optimization/OptiBayesAlgSmoot/check_optimization_input.py @@ -1,6 +1,8 @@ from logging import Logger, FileHandler, Formatter, INFO, NOTSET from datetime import datetime from ....Classes.OptiObjective import OptiObjective +from ....Classes.OptiDesignVarSet import OptiDesignVarSet +from ....Classes.OptiDesignVarInterval import OptiDesignVarInterval class OptimizationAttributeError(Exception): @@ -70,9 +72,9 @@ def check_optimization_input(self): ) else: for design_var in self.problem.design_var: - if design_var.type_var not in ["set", "interval"]: - mess = 'The design variable \'{}\' has a wrong type_var got {} expected "set" or "interval".'.format( - design_var.name, design_var.type_var + if not isinstance(design_var, OptiDesignVarInterval) and not isinstance(design_var, OptiDesignVarSet): + mess = 'The design variable \'{}\' is expected to be an OptiDesignVarSet or an OptiDesignVarInterval.'.format( + design_var.name ) raise OptimizationAttributeError(mess) elif design_var.symbol in [None, ""]: @@ -100,9 +102,7 @@ def check_optimization_input(self): raise OptimizationAttributeError(mess) # Check getter elif not callable(cstr.keeper): - mess = ( - "The constraint '{}' function keeper is not callable.".format( - cstr.name - ) + mess = "The constraint '{}' function keeper is not callable.".format( + cstr.name ) raise OptimizationAttributeError(mess) diff --git a/pyleecan/Methods/Optimization/OptiGenAlgNsga2Deap/check_optimization_input.py b/pyleecan/Methods/Optimization/OptiGenAlgNsga2Deap/check_optimization_input.py index 8c16e957f..c9173b00c 100644 --- a/pyleecan/Methods/Optimization/OptiGenAlgNsga2Deap/check_optimization_input.py +++ b/pyleecan/Methods/Optimization/OptiGenAlgNsga2Deap/check_optimization_input.py @@ -1,6 +1,8 @@ from logging import Logger, FileHandler, Formatter, INFO, NOTSET from datetime import datetime from ....Classes.OptiObjective import OptiObjective +from ....Classes.OptiDesignVarSet import OptiDesignVarSet +from ....Classes.OptiDesignVarInterval import OptiDesignVarInterval class OptimizationAttributeError(Exception): @@ -79,9 +81,9 @@ def check_optimization_input(self): ) else: for design_var in self.problem.design_var: - if design_var.type_var not in ["set", "interval"]: - mess = 'The design variable \'{}\' has a wrong type_var got {} expected "set" or "interval".'.format( - design_var.name, design_var.type_var + if not isinstance(design_var, OptiDesignVarInterval) and not isinstance(design_var, OptiDesignVarSet): + mess = 'The design variable \'{}\' is expected to be an OptiDesignVarSet or an OptiDesignVarInterval.'.format( + design_var.name ) raise OptimizationAttributeError(mess) elif design_var.symbol in [None, ""]: @@ -109,9 +111,7 @@ def check_optimization_input(self): raise OptimizationAttributeError(mess) # Check getter elif not callable(cstr.keeper): - mess = ( - "The constraint '{}' function keeper is not callable.".format( - cstr.name - ) + mess = "The constraint '{}' function keeper is not callable.".format( + cstr.name ) raise OptimizationAttributeError(mess) diff --git a/pyleecan/Methods/Optimization/OptiGenAlgNsga2Deap/mutate.py b/pyleecan/Methods/Optimization/OptiGenAlgNsga2Deap/mutate.py index d9c259577..8be267798 100644 --- a/pyleecan/Methods/Optimization/OptiGenAlgNsga2Deap/mutate.py +++ b/pyleecan/Methods/Optimization/OptiGenAlgNsga2Deap/mutate.py @@ -1,6 +1,8 @@ import random from collections.abc import Iterable from deap.tools import mutPolynomialBounded +from ....Classes.OptiDesignVarInterval import OptiDesignVarInterval +from ....Classes.OptiDesignVarSet import OptiDesignVarSet def mutate(self, indiv): @@ -28,7 +30,7 @@ def mutate(self, indiv): is_mutation = True if self.mutator == None: - if design_var.type_var == "interval": # Interval variable + if isinstance(design_var, OptiDesignVarInterval): # Interval variable # Using polynomial bounded mutation as in Deb and al., "A Fast and Elitist Multiobjective Genetic Algorithm: NSGA-II" if isinstance(indiv[k], Iterable): indiv[k] = mutPolynomialBounded( @@ -42,7 +44,7 @@ def mutate(self, indiv): else: # Uniform mutation indiv[k] = random.choice(design_var.space) else: # User defined mutator - if design_var.type_var == "interval": # Interval variable + if isinstance(design_var, OptiDesignVarInterval): # Interval variable indiv[k] = self.mutator(indiv[k]) else: # TODO Allow to redefine mutators for set From e936f0beced93c75a744c4a6b1e96e00db6ec262 Mon Sep 17 00:00:00 2001 From: BenjaminGabet Date: Mon, 5 Dec 2022 15:09:09 +0100 Subject: [PATCH 03/10] [NF] VarOpti has been created. VarParam is now an Abstract class. The old VarParam is now a VarParamSweep --- ...py => test_VarParamSweep_fct_save_load.py} | 10 +- Tests/Simulation/test_post_var_simu.py | 4 +- .../Multisimulation/test_multi_multi.py | 4 +- .../Multisimulation/test_slot_scale.py | 4 +- .../Optimization/test_opti_varopti.py | 86 +++ pyleecan/Classes/Class_Dict.json | 96 ++- pyleecan/Classes/VarOpti.py | 575 ++++++++++++++++++ pyleecan/Classes/VarParam.py | 55 -- pyleecan/Classes/VarParamSweep.py | 304 +++++++++ pyleecan/Classes/import_all.py | 2 + pyleecan/Functions/load_switch.py | 2 + .../ClassesRef/Simulation/VarOpti.csv | 4 + .../ClassesRef/Simulation/VarParam.csv | 5 +- .../ClassesRef/Simulation/VarParamSweep.csv | 4 + .../check_optimization_input.py | 6 +- .../check_optimization_input.py | 6 +- .../Optimization/OptiGenAlgNsga2Deap/solve.py | 10 +- pyleecan/Methods/Simulation/VarOpti/check.py | 125 ++++ .../Simulation/VarOpti/get_full_solver.py | 32 + pyleecan/Methods/Simulation/VarOpti/run.py | 9 + .../check_param.py | 8 +- .../generate_simulation_list.py | 0 .../get_simu_number.py | 4 +- .../Methods/Simulation/VarSimu/check_param.py | 2 +- 24 files changed, 1265 insertions(+), 92 deletions(-) rename Tests/Methods/Simulation/{test_VarParam_fct_save_load.py => test_VarParamSweep_fct_save_load.py} (91%) create mode 100644 Tests/Validation/Optimization/test_opti_varopti.py create mode 100644 pyleecan/Classes/VarOpti.py create mode 100644 pyleecan/Classes/VarParamSweep.py create mode 100644 pyleecan/Generator/ClassesRef/Simulation/VarOpti.csv create mode 100644 pyleecan/Generator/ClassesRef/Simulation/VarParamSweep.csv create mode 100644 pyleecan/Methods/Simulation/VarOpti/check.py create mode 100644 pyleecan/Methods/Simulation/VarOpti/get_full_solver.py create mode 100644 pyleecan/Methods/Simulation/VarOpti/run.py rename pyleecan/Methods/Simulation/{VarParam => VarParamSweep}/check_param.py (86%) rename pyleecan/Methods/Simulation/{VarParam => VarParamSweep}/generate_simulation_list.py (100%) rename pyleecan/Methods/Simulation/{VarParam => VarParamSweep}/get_simu_number.py (85%) diff --git a/Tests/Methods/Simulation/test_VarParam_fct_save_load.py b/Tests/Methods/Simulation/test_VarParamSweep_fct_save_load.py similarity index 91% rename from Tests/Methods/Simulation/test_VarParam_fct_save_load.py rename to Tests/Methods/Simulation/test_VarParamSweep_fct_save_load.py index ac705f723..d409f2a7d 100644 --- a/Tests/Methods/Simulation/test_VarParam_fct_save_load.py +++ b/Tests/Methods/Simulation/test_VarParamSweep_fct_save_load.py @@ -6,7 +6,7 @@ from pyleecan.Classes.OPdq import OPdq from pyleecan.Classes.Simu1 import Simu1 from pyleecan.Classes.InputCurrent import InputCurrent -from pyleecan.Classes.VarParam import VarParam +from pyleecan.Classes.VarParamSweep import VarParamSweep from pyleecan.Classes.Simu1 import Simu1 from pyleecan.Classes.DataKeeper import DataKeeper from pyleecan.Classes.ParamExplorerSet import ParamExplorerSet @@ -18,14 +18,14 @@ from pyleecan.definitions import DATA_DIR, RESULT_DIR -def test_VarParam_fct_save_load(): +def test_VarParamSweep_fct_save_load(): """Test to check keeper, setter and getter functions defined as path containing global variable """ machine = load(join(DATA_DIR, "Machine", "Toyota_Prius.json")) # First simulation creating femm file - simu = Simu1(name="test_VarParam_fct_save_load", machine=machine) + simu = Simu1(name="test_VarParamSweep_fct_save_load", machine=machine) result_folder = join(RESULT_DIR, simu.name) if not isdir(result_folder): @@ -54,7 +54,7 @@ def test_VarParam_fct_save_load(): ) # Generate parameter sweep - simu.var_simu = VarParam( + simu.var_simu = VarParamSweep( stop_if_error=True, is_keep_all_output=True, datakeeper_list=[ @@ -101,5 +101,5 @@ def test_VarParam_fct_save_load(): if __name__ == "__main__": - test_VarParam_fct_save_load() + test_VarParamSweep_fct_save_load() print("Done") diff --git a/Tests/Simulation/test_post_var_simu.py b/Tests/Simulation/test_post_var_simu.py index 1630efad0..be05b0f02 100644 --- a/Tests/Simulation/test_post_var_simu.py +++ b/Tests/Simulation/test_post_var_simu.py @@ -13,7 +13,7 @@ from pyleecan.Classes.PostMethod import PostMethod from pyleecan.Classes.Simu1 import Simu1 from pyleecan.Classes.InputCurrent import InputCurrent -from pyleecan.Classes.VarParam import VarParam +from pyleecan.Classes.VarParamSweep import VarParamSweep from pyleecan.Classes.ParamExplorerSet import ParamExplorerSet from pyleecan.Classes.DataKeeper import DataKeeper @@ -68,7 +68,7 @@ def test_post_var_simu(): keeper="lambda output: np.sqrt(output.simu.machine.stator.slot.W0)", ) - simu1.var_simu = VarParam( + simu1.var_simu = VarParamSweep( paramexplorer_list=[pe1], datakeeper_list=[dk1], stop_if_error=True, diff --git a/Tests/Validation/Multisimulation/test_multi_multi.py b/Tests/Validation/Multisimulation/test_multi_multi.py index 0244b9fea..acd94a87b 100644 --- a/Tests/Validation/Multisimulation/test_multi_multi.py +++ b/Tests/Validation/Multisimulation/test_multi_multi.py @@ -22,7 +22,7 @@ from pyleecan.Classes.PostPlot import PostPlot from pyleecan.Classes.Simu1 import Simu1 from pyleecan.Classes.VarLoadCurrent import VarLoadCurrent -from pyleecan.Classes.VarParam import VarParam +from pyleecan.Classes.VarParamSweep import VarParamSweep from pyleecan.definitions import DATA_DIR from pyleecan.Functions.load import load from Tests import save_validation_path as save_path @@ -184,7 +184,7 @@ def test_multi_multi(): varload.is_keep_all_output = False # Multi-simulation to change machine parameters - multisim = VarParam( + multisim = VarParamSweep( stop_if_error=True, is_reuse_femm_file=False, ) diff --git a/Tests/Validation/Multisimulation/test_slot_scale.py b/Tests/Validation/Multisimulation/test_slot_scale.py index 402d04bfe..32071b249 100644 --- a/Tests/Validation/Multisimulation/test_slot_scale.py +++ b/Tests/Validation/Multisimulation/test_slot_scale.py @@ -1,6 +1,6 @@ # Multisimulation objects from pyleecan.Classes.OPdq import OPdq -from pyleecan.Classes.VarParam import VarParam +from pyleecan.Classes.VarParamSweep import VarParamSweep from pyleecan.Classes.ParamExplorerSet import ParamExplorerSet from pyleecan.Classes.DataKeeper import DataKeeper import numpy as np @@ -68,7 +68,7 @@ def test_slot_scale(): ) # Multi-simulation to variate the slot size - multisim = VarParam( + multisim = VarParamSweep( stop_if_error=True, is_reuse_femm_file=False, ) diff --git a/Tests/Validation/Optimization/test_opti_varopti.py b/Tests/Validation/Optimization/test_opti_varopti.py new file mode 100644 index 000000000..1cc16373c --- /dev/null +++ b/Tests/Validation/Optimization/test_opti_varopti.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python +# coding: utf-8 +""" +Test Pyleecan optimization module using Binh and Korn Function + +Binh, T. and U. Korn, "MOBES: A multiobjective evolution strategy for constrained optimization problems. +In Proceedings of the third international Conference on Genetic Algorithms (Mendel97), ", Brno, Czech Republic, pp. 176-182, 1997 +""" +# Imports +from os.path import join +import pytest +from pyleecan.Classes.Simu1 import Simu1 +from pyleecan.Classes.DataKeeper import DataKeeper +from pyleecan.Classes.OptiDesignVarInterval import OptiDesignVarInterval +from pyleecan.Classes.OptiObjective import OptiObjective +from pyleecan.Classes.OptiProblem import OptiProblem +from pyleecan.Classes.OptiGenAlgNsga2Deap import OptiGenAlgNsga2Deap +from pyleecan.Classes.VarOpti import VarOpti + +import random + +from pyleecan.Functions.load import load +from pyleecan.definitions import DATA_DIR + + +@pytest.mark.SCIM +@pytest.mark.MagFEMM +@pytest.mark.SingleOP +def test_opti_varopti(): + # Defining reference Output + # Definition of the enforced output of the electrical module + Railway_Traction = load(join(DATA_DIR, "Machine", "Railway_Traction.json")) + + # Definition of the simulation + simu = Simu1(name="test_opti_datakeeper_list", machine=Railway_Traction, layer=0) + + # Design variable + my_vars = [ + OptiDesignVarInterval( + name="Rotor slot height", + symbol="RH0", + space=[0, 5], # May generate error in FEMM + get_value=lambda space: random.uniform(*space), + setter="simu.machine.rotor.slot.H0", + ), + OptiDesignVarInterval( + name="Stator slot height", + symbol="SH0", + space=[0, 3], # May generate error in FEMM + get_value=lambda space: random.uniform(*space), + setter="simu.machine.stator.slot.H0", + ), + ] + + # Objectives + objs = [ + OptiObjective( + name="Minimization of the rotor slot width", + symbol="R_s_w0", + unit="m", + keeper="lambda output: output.simu.machine.rotor.slot.W0", + ) + ] + + datakeeper_list = [ + DataKeeper( + name="Minimization of the rotor slot width", + symbol="R_s_w0_bis", + unit="m", + keeper="lambda output: output.simu.machine.rotor.slot.W0", + ) + ] + + # Solving the problem + solver = OptiGenAlgNsga2Deap(size_pop=4, nb_gen=2, p_mutate=0) + + # Creating a VarOpti and launch the simulation + simu.var_simu = VarOpti(paramexplorer_list=my_vars, objective_list=objs, datakeeper_list=datakeeper_list, solver=solver, var_simu=simu.var_simu) + simu.var_simu.check() + res = simu.run() + + assert res["R_s_w0"].result == res["R_s_w0_bis"].result + + +if __name__ == "__main__": + test_opti_varopti() diff --git a/pyleecan/Classes/Class_Dict.json b/pyleecan/Classes/Class_Dict.json index cc2d1b41d..1e2b2b118 100644 --- a/pyleecan/Classes/Class_Dict.json +++ b/pyleecan/Classes/Class_Dict.json @@ -15435,7 +15435,7 @@ "path": "pyleecan/Generator/ClassesRef/Simulation/VarLoadVoltage.csv", "properties": [] }, - "VarParam": { + "VarOpti": { "constants": [ { "name": "VERSION", @@ -15443,17 +15443,72 @@ }, { "name": "NAME", - "value": "\"Parameter Sweep\"" + "value": "\"Optimization\"" } ], "daughters": [], - "desc": "Handle multisimulation by varying parameters", + "desc": "Handle Optimization multisimulation by varying parameters", "is_internal": false, "methods": [ - "check_param", - "generate_simulation_list", - "get_simu_number" + "check", + "run", + "get_full_solver" + ], + "mother": "VarParam", + "name": "VarOpti", + "package": "Simulation", + "path": "pyleecan/Generator/ClassesRef/Simulation/VarOpti.csv", + "properties": [ + { + "as_dict": "", + "desc": "List containing OptiObjective objects", + "max": "", + "min": "", + "name": "objective_list", + "type": "[OptiObjective]", + "unit": "-", + "value": -1 + }, + { + "as_dict": "", + "desc": "List containing OptiConstraint objects", + "max": "", + "min": "", + "name": "constraint_list", + "type": "[OptiConstraint]", + "unit": "-", + "value": -1 + }, + { + "as_dict": "", + "desc": "Object that solve an OptiProblem", + "max": "", + "min": "", + "name": "solver", + "type": "OptiSolver", + "unit": "-", + "value": null + } + ] + }, + "VarParam": { + "constants": [ + { + "name": "VERSION", + "value": "1" + }, + { + "name": "NAME", + "value": "\"Parameter Sweep\"" + } + ], + "daughters": [ + "VarOpti", + "VarParamSweep" ], + "desc": "Handle multisimulation by varying parameters", + "is_internal": false, + "methods": [], "mother": "VarSimu", "name": "VarParam", "package": "Simulation", @@ -15471,6 +15526,31 @@ } ] }, + "VarParamSweep": { + "constants": [ + { + "name": "VERSION", + "value": "1" + }, + { + "name": "NAME", + "value": "\"Parameter Sweep\"" + } + ], + "daughters": [], + "desc": "Handle multisimulation by varying parameters", + "is_internal": false, + "methods": [ + "check_param", + "generate_simulation_list", + "get_simu_number" + ], + "mother": "VarParam", + "name": "VarParamSweep", + "package": "Simulation", + "path": "pyleecan/Generator/ClassesRef/Simulation/VarParamSweep.csv", + "properties": [] + }, "VarSimu": { "constants": [ { @@ -15482,7 +15562,9 @@ "VarLoad", "VarLoadCurrent", "VarLoadVoltage", - "VarParam" + "VarOpti", + "VarParam", + "VarParamSweep" ], "desc": "Abstract class for the multi-simulation", "is_internal": false, diff --git a/pyleecan/Classes/VarOpti.py b/pyleecan/Classes/VarOpti.py new file mode 100644 index 000000000..de1560c8d --- /dev/null +++ b/pyleecan/Classes/VarOpti.py @@ -0,0 +1,575 @@ +# -*- coding: utf-8 -*- +# File generated according to Generator/ClassesRef/Simulation/VarOpti.csv +# WARNING! All changes made in this file will be lost! +"""Method code available at https://github.com/Eomys/pyleecan/tree/master/pyleecan/Methods/Simulation/VarOpti +""" + +from os import linesep +from sys import getsizeof +from logging import getLogger +from ._check import check_var, raise_ +from ..Functions.get_logger import get_logger +from ..Functions.save import save +from ..Functions.load import load_init_dict +from ..Functions.Load.import_class import import_class +from copy import deepcopy +from .VarParam import VarParam + +# Import all class method +# Try/catch to remove unnecessary dependencies in unused method +try: + from ..Methods.Simulation.VarOpti.check import check +except ImportError as error: + check = error + +try: + from ..Methods.Simulation.VarOpti.run import run +except ImportError as error: + run = error + +try: + from ..Methods.Simulation.VarOpti.get_full_solver import get_full_solver +except ImportError as error: + get_full_solver = error + + +from numpy import isnan +from ._check import InitUnKnowClassError + + +class VarOpti(VarParam): + """Handle Optimization multisimulation by varying parameters""" + + VERSION = 1 + NAME = "Optimization" + + # Check ImportError to remove unnecessary dependencies in unused method + # cf Methods.Simulation.VarOpti.check + if isinstance(check, ImportError): + check = property( + fget=lambda x: raise_( + ImportError("Can't use VarOpti method check: " + str(check)) + ) + ) + else: + check = check + # cf Methods.Simulation.VarOpti.run + if isinstance(run, ImportError): + run = property( + fget=lambda x: raise_( + ImportError("Can't use VarOpti method run: " + str(run)) + ) + ) + else: + run = run + # cf Methods.Simulation.VarOpti.get_full_solver + if isinstance(get_full_solver, ImportError): + get_full_solver = property( + fget=lambda x: raise_( + ImportError( + "Can't use VarOpti method get_full_solver: " + str(get_full_solver) + ) + ) + ) + else: + get_full_solver = get_full_solver + # generic save method is available in all object + save = save + # get_logger method is available in all object + get_logger = get_logger + + def __init__( + self, + objective_list=-1, + constraint_list=-1, + solver=None, + paramexplorer_list=-1, + name="", + desc="", + datakeeper_list=-1, + is_keep_all_output=False, + stop_if_error=False, + var_simu=None, + nb_simu=0, + is_reuse_femm_file=True, + postproc_list=-1, + pre_keeper_postproc_list=None, + post_keeper_postproc_list=None, + is_reuse_LUT=True, + init_dict=None, + init_str=None, + ): + """Constructor of the class. Can be use in three ways : + - __init__ (arg1 = 1, arg3 = 5) every parameters have name and default values + for pyleecan type, -1 will call the default constructor + - __init__ (init_dict = d) d must be a dictionary with property names as keys + - __init__ (init_str = s) s must be a string + s is the file path to load + + ndarray or list can be given for Vector and Matrix + object or dict can be given for pyleecan Object""" + + if init_str is not None: # Load from a file + init_dict = load_init_dict(init_str)[1] + if init_dict is not None: # Initialisation by dict + assert type(init_dict) is dict + # Overwrite default value with init_dict content + if "objective_list" in list(init_dict.keys()): + objective_list = init_dict["objective_list"] + if "constraint_list" in list(init_dict.keys()): + constraint_list = init_dict["constraint_list"] + if "solver" in list(init_dict.keys()): + solver = init_dict["solver"] + if "paramexplorer_list" in list(init_dict.keys()): + paramexplorer_list = init_dict["paramexplorer_list"] + if "name" in list(init_dict.keys()): + name = init_dict["name"] + if "desc" in list(init_dict.keys()): + desc = init_dict["desc"] + if "datakeeper_list" in list(init_dict.keys()): + datakeeper_list = init_dict["datakeeper_list"] + if "is_keep_all_output" in list(init_dict.keys()): + is_keep_all_output = init_dict["is_keep_all_output"] + if "stop_if_error" in list(init_dict.keys()): + stop_if_error = init_dict["stop_if_error"] + if "var_simu" in list(init_dict.keys()): + var_simu = init_dict["var_simu"] + if "nb_simu" in list(init_dict.keys()): + nb_simu = init_dict["nb_simu"] + if "is_reuse_femm_file" in list(init_dict.keys()): + is_reuse_femm_file = init_dict["is_reuse_femm_file"] + if "postproc_list" in list(init_dict.keys()): + postproc_list = init_dict["postproc_list"] + if "pre_keeper_postproc_list" in list(init_dict.keys()): + pre_keeper_postproc_list = init_dict["pre_keeper_postproc_list"] + if "post_keeper_postproc_list" in list(init_dict.keys()): + post_keeper_postproc_list = init_dict["post_keeper_postproc_list"] + if "is_reuse_LUT" in list(init_dict.keys()): + is_reuse_LUT = init_dict["is_reuse_LUT"] + # Set the properties (value check and convertion are done in setter) + self.objective_list = objective_list + self.constraint_list = constraint_list + self.solver = solver + # Call VarParam init + super(VarOpti, self).__init__( + paramexplorer_list=paramexplorer_list, + name=name, + desc=desc, + datakeeper_list=datakeeper_list, + is_keep_all_output=is_keep_all_output, + stop_if_error=stop_if_error, + var_simu=var_simu, + nb_simu=nb_simu, + is_reuse_femm_file=is_reuse_femm_file, + postproc_list=postproc_list, + pre_keeper_postproc_list=pre_keeper_postproc_list, + post_keeper_postproc_list=post_keeper_postproc_list, + is_reuse_LUT=is_reuse_LUT, + ) + # The class is frozen (in VarParam init), for now it's impossible to + # add new properties + + def __str__(self): + """Convert this object in a readeable string (for print)""" + + VarOpti_str = "" + # Get the properties inherited from VarParam + VarOpti_str += super(VarOpti, self).__str__() + if len(self.objective_list) == 0: + VarOpti_str += "objective_list = []" + linesep + for ii in range(len(self.objective_list)): + tmp = ( + self.objective_list[ii].__str__().replace(linesep, linesep + "\t") + + linesep + ) + VarOpti_str += "objective_list[" + str(ii) + "] =" + tmp + linesep + linesep + if len(self.constraint_list) == 0: + VarOpti_str += "constraint_list = []" + linesep + for ii in range(len(self.constraint_list)): + tmp = ( + self.constraint_list[ii].__str__().replace(linesep, linesep + "\t") + + linesep + ) + VarOpti_str += ( + "constraint_list[" + str(ii) + "] =" + tmp + linesep + linesep + ) + if self.solver is not None: + tmp = self.solver.__str__().replace(linesep, linesep + "\t").rstrip("\t") + VarOpti_str += "solver = " + tmp + else: + VarOpti_str += "solver = None" + linesep + linesep + return VarOpti_str + + def __eq__(self, other): + """Compare two objects (skip parent)""" + + if type(other) != type(self): + return False + + # Check the properties inherited from VarParam + if not super(VarOpti, self).__eq__(other): + return False + if other.objective_list != self.objective_list: + return False + if other.constraint_list != self.constraint_list: + return False + if other.solver != self.solver: + return False + return True + + def compare(self, other, name="self", ignore_list=None, is_add_value=False): + """Compare two objects and return list of differences""" + + if ignore_list is None: + ignore_list = list() + if type(other) != type(self): + return ["type(" + name + ")"] + diff_list = list() + + # Check the properties inherited from VarParam + diff_list.extend( + super(VarOpti, self).compare( + other, name=name, ignore_list=ignore_list, is_add_value=is_add_value + ) + ) + if (other.objective_list is None and self.objective_list is not None) or ( + other.objective_list is not None and self.objective_list is None + ): + diff_list.append(name + ".objective_list None mismatch") + elif self.objective_list is None: + pass + elif len(other.objective_list) != len(self.objective_list): + diff_list.append("len(" + name + ".objective_list)") + else: + for ii in range(len(other.objective_list)): + diff_list.extend( + self.objective_list[ii].compare( + other.objective_list[ii], + name=name + ".objective_list[" + str(ii) + "]", + ignore_list=ignore_list, + is_add_value=is_add_value, + ) + ) + if (other.constraint_list is None and self.constraint_list is not None) or ( + other.constraint_list is not None and self.constraint_list is None + ): + diff_list.append(name + ".constraint_list None mismatch") + elif self.constraint_list is None: + pass + elif len(other.constraint_list) != len(self.constraint_list): + diff_list.append("len(" + name + ".constraint_list)") + else: + for ii in range(len(other.constraint_list)): + diff_list.extend( + self.constraint_list[ii].compare( + other.constraint_list[ii], + name=name + ".constraint_list[" + str(ii) + "]", + ignore_list=ignore_list, + is_add_value=is_add_value, + ) + ) + if (other.solver is None and self.solver is not None) or ( + other.solver is not None and self.solver is None + ): + diff_list.append(name + ".solver None mismatch") + elif self.solver is not None: + diff_list.extend( + self.solver.compare( + other.solver, + name=name + ".solver", + ignore_list=ignore_list, + is_add_value=is_add_value, + ) + ) + # Filter ignore differences + diff_list = list(filter(lambda x: x not in ignore_list, diff_list)) + return diff_list + + def __sizeof__(self): + """Return the size in memory of the object (including all subobject)""" + + S = 0 # Full size of the object + + # Get size of the properties inherited from VarParam + S += super(VarOpti, self).__sizeof__() + if self.objective_list is not None: + for value in self.objective_list: + S += getsizeof(value) + if self.constraint_list is not None: + for value in self.constraint_list: + S += getsizeof(value) + S += getsizeof(self.solver) + return S + + def as_dict(self, type_handle_ndarray=0, keep_function=False, **kwargs): + """ + Convert this object in a json serializable dict (can be use in __init__). + type_handle_ndarray: int + How to handle ndarray (0: tolist, 1: copy, 2: nothing) + keep_function : bool + True to keep the function object, else return str + Optional keyword input parameter is for internal use only + and may prevent json serializability. + """ + + # Get the properties inherited from VarParam + VarOpti_dict = super(VarOpti, self).as_dict( + type_handle_ndarray=type_handle_ndarray, + keep_function=keep_function, + **kwargs + ) + if self.objective_list is None: + VarOpti_dict["objective_list"] = None + else: + VarOpti_dict["objective_list"] = list() + for obj in self.objective_list: + if obj is not None: + VarOpti_dict["objective_list"].append( + obj.as_dict( + type_handle_ndarray=type_handle_ndarray, + keep_function=keep_function, + **kwargs + ) + ) + else: + VarOpti_dict["objective_list"].append(None) + if self.constraint_list is None: + VarOpti_dict["constraint_list"] = None + else: + VarOpti_dict["constraint_list"] = list() + for obj in self.constraint_list: + if obj is not None: + VarOpti_dict["constraint_list"].append( + obj.as_dict( + type_handle_ndarray=type_handle_ndarray, + keep_function=keep_function, + **kwargs + ) + ) + else: + VarOpti_dict["constraint_list"].append(None) + if self.solver is None: + VarOpti_dict["solver"] = None + else: + VarOpti_dict["solver"] = self.solver.as_dict( + type_handle_ndarray=type_handle_ndarray, + keep_function=keep_function, + **kwargs + ) + # The class name is added to the dict for deserialisation purpose + # Overwrite the mother class name + VarOpti_dict["__class__"] = "VarOpti" + return VarOpti_dict + + def copy(self): + """Creates a deepcopy of the object""" + + # Handle deepcopy of all the properties + if self.objective_list is None: + objective_list_val = None + else: + objective_list_val = list() + for obj in self.objective_list: + objective_list_val.append(obj.copy()) + if self.constraint_list is None: + constraint_list_val = None + else: + constraint_list_val = list() + for obj in self.constraint_list: + constraint_list_val.append(obj.copy()) + if self.solver is None: + solver_val = None + else: + solver_val = self.solver.copy() + if self.paramexplorer_list is None: + paramexplorer_list_val = None + else: + paramexplorer_list_val = list() + for obj in self.paramexplorer_list: + paramexplorer_list_val.append(obj.copy()) + name_val = self.name + desc_val = self.desc + if self.datakeeper_list is None: + datakeeper_list_val = None + else: + datakeeper_list_val = list() + for obj in self.datakeeper_list: + datakeeper_list_val.append(obj.copy()) + is_keep_all_output_val = self.is_keep_all_output + stop_if_error_val = self.stop_if_error + if self.var_simu is None: + var_simu_val = None + else: + var_simu_val = self.var_simu.copy() + nb_simu_val = self.nb_simu + is_reuse_femm_file_val = self.is_reuse_femm_file + if self.postproc_list is None: + postproc_list_val = None + else: + postproc_list_val = list() + for obj in self.postproc_list: + postproc_list_val.append(obj.copy()) + if self.pre_keeper_postproc_list is None: + pre_keeper_postproc_list_val = None + else: + pre_keeper_postproc_list_val = list() + for obj in self.pre_keeper_postproc_list: + pre_keeper_postproc_list_val.append(obj.copy()) + if self.post_keeper_postproc_list is None: + post_keeper_postproc_list_val = None + else: + post_keeper_postproc_list_val = list() + for obj in self.post_keeper_postproc_list: + post_keeper_postproc_list_val.append(obj.copy()) + is_reuse_LUT_val = self.is_reuse_LUT + # Creates new object of the same type with the copied properties + obj_copy = type(self)( + objective_list=objective_list_val, + constraint_list=constraint_list_val, + solver=solver_val, + paramexplorer_list=paramexplorer_list_val, + name=name_val, + desc=desc_val, + datakeeper_list=datakeeper_list_val, + is_keep_all_output=is_keep_all_output_val, + stop_if_error=stop_if_error_val, + var_simu=var_simu_val, + nb_simu=nb_simu_val, + is_reuse_femm_file=is_reuse_femm_file_val, + postproc_list=postproc_list_val, + pre_keeper_postproc_list=pre_keeper_postproc_list_val, + post_keeper_postproc_list=post_keeper_postproc_list_val, + is_reuse_LUT=is_reuse_LUT_val, + ) + return obj_copy + + def _set_None(self): + """Set all the properties to None (except pyleecan object)""" + + self.objective_list = None + self.constraint_list = None + if self.solver is not None: + self.solver._set_None() + # Set to None the properties inherited from VarParam + super(VarOpti, self)._set_None() + + def _get_objective_list(self): + """getter of objective_list""" + if self._objective_list is not None: + for obj in self._objective_list: + if obj is not None: + obj.parent = self + return self._objective_list + + def _set_objective_list(self, value): + """setter of objective_list""" + if type(value) is list: + for ii, obj in enumerate(value): + if isinstance(obj, str): # Load from file + try: + obj = load_init_dict(obj)[1] + except Exception as e: + self.get_logger().error( + "Error while loading " + obj + ", setting None instead" + ) + obj = None + value[ii] = None + if type(obj) is dict: + class_obj = import_class( + "pyleecan.Classes", obj.get("__class__"), "objective_list" + ) + value[ii] = class_obj(init_dict=obj) + if value[ii] is not None: + value[ii].parent = self + if value == -1: + value = list() + check_var("objective_list", value, "[OptiObjective]") + self._objective_list = value + + objective_list = property( + fget=_get_objective_list, + fset=_set_objective_list, + doc=u"""List containing OptiObjective objects + + :Type: [OptiObjective] + """, + ) + + def _get_constraint_list(self): + """getter of constraint_list""" + if self._constraint_list is not None: + for obj in self._constraint_list: + if obj is not None: + obj.parent = self + return self._constraint_list + + def _set_constraint_list(self, value): + """setter of constraint_list""" + if type(value) is list: + for ii, obj in enumerate(value): + if isinstance(obj, str): # Load from file + try: + obj = load_init_dict(obj)[1] + except Exception as e: + self.get_logger().error( + "Error while loading " + obj + ", setting None instead" + ) + obj = None + value[ii] = None + if type(obj) is dict: + class_obj = import_class( + "pyleecan.Classes", obj.get("__class__"), "constraint_list" + ) + value[ii] = class_obj(init_dict=obj) + if value[ii] is not None: + value[ii].parent = self + if value == -1: + value = list() + check_var("constraint_list", value, "[OptiConstraint]") + self._constraint_list = value + + constraint_list = property( + fget=_get_constraint_list, + fset=_set_constraint_list, + doc=u"""List containing OptiConstraint objects + + :Type: [OptiConstraint] + """, + ) + + def _get_solver(self): + """getter of solver""" + return self._solver + + def _set_solver(self, value): + """setter of solver""" + if isinstance(value, str): # Load from file + try: + value = load_init_dict(value)[1] + except Exception as e: + self.get_logger().error( + "Error while loading " + value + ", setting None instead" + ) + value = None + if isinstance(value, dict) and "__class__" in value: + class_obj = import_class( + "pyleecan.Classes", value.get("__class__"), "solver" + ) + value = class_obj(init_dict=value) + elif type(value) is int and value == -1: # Default constructor + OptiSolver = import_class("pyleecan.Classes", "OptiSolver", "solver") + value = OptiSolver() + check_var("solver", value, "OptiSolver") + self._solver = value + + if self._solver is not None: + self._solver.parent = self + + solver = property( + fget=_get_solver, + fset=_set_solver, + doc=u"""Object that solve an OptiProblem + + :Type: OptiSolver + """, + ) diff --git a/pyleecan/Classes/VarParam.py b/pyleecan/Classes/VarParam.py index b9144bf56..5b3d5ac26 100644 --- a/pyleecan/Classes/VarParam.py +++ b/pyleecan/Classes/VarParam.py @@ -15,26 +15,6 @@ from copy import deepcopy from .VarSimu import VarSimu -# Import all class method -# Try/catch to remove unnecessary dependencies in unused method -try: - from ..Methods.Simulation.VarParam.check_param import check_param -except ImportError as error: - check_param = error - -try: - from ..Methods.Simulation.VarParam.generate_simulation_list import ( - generate_simulation_list, - ) -except ImportError as error: - generate_simulation_list = error - -try: - from ..Methods.Simulation.VarParam.get_simu_number import get_simu_number -except ImportError as error: - get_simu_number = error - - from numpy import isnan from ._check import InitUnKnowClassError @@ -45,41 +25,6 @@ class VarParam(VarSimu): VERSION = 1 NAME = "Parameter Sweep" - # Check ImportError to remove unnecessary dependencies in unused method - # cf Methods.Simulation.VarParam.check_param - if isinstance(check_param, ImportError): - check_param = property( - fget=lambda x: raise_( - ImportError( - "Can't use VarParam method check_param: " + str(check_param) - ) - ) - ) - else: - check_param = check_param - # cf Methods.Simulation.VarParam.generate_simulation_list - if isinstance(generate_simulation_list, ImportError): - generate_simulation_list = property( - fget=lambda x: raise_( - ImportError( - "Can't use VarParam method generate_simulation_list: " - + str(generate_simulation_list) - ) - ) - ) - else: - generate_simulation_list = generate_simulation_list - # cf Methods.Simulation.VarParam.get_simu_number - if isinstance(get_simu_number, ImportError): - get_simu_number = property( - fget=lambda x: raise_( - ImportError( - "Can't use VarParam method get_simu_number: " + str(get_simu_number) - ) - ) - ) - else: - get_simu_number = get_simu_number # generic save method is available in all object save = save # get_logger method is available in all object diff --git a/pyleecan/Classes/VarParamSweep.py b/pyleecan/Classes/VarParamSweep.py new file mode 100644 index 000000000..8047d5832 --- /dev/null +++ b/pyleecan/Classes/VarParamSweep.py @@ -0,0 +1,304 @@ +# -*- coding: utf-8 -*- +# File generated according to Generator/ClassesRef/Simulation/VarParamSweep.csv +# WARNING! All changes made in this file will be lost! +"""Method code available at https://github.com/Eomys/pyleecan/tree/master/pyleecan/Methods/Simulation/VarParamSweep +""" + +from os import linesep +from sys import getsizeof +from logging import getLogger +from ._check import check_var, raise_ +from ..Functions.get_logger import get_logger +from ..Functions.save import save +from ..Functions.load import load_init_dict +from ..Functions.Load.import_class import import_class +from copy import deepcopy +from .VarParam import VarParam + +# Import all class method +# Try/catch to remove unnecessary dependencies in unused method +try: + from ..Methods.Simulation.VarParamSweep.check_param import check_param +except ImportError as error: + check_param = error + +try: + from ..Methods.Simulation.VarParamSweep.generate_simulation_list import ( + generate_simulation_list, + ) +except ImportError as error: + generate_simulation_list = error + +try: + from ..Methods.Simulation.VarParamSweep.get_simu_number import get_simu_number +except ImportError as error: + get_simu_number = error + + +from numpy import isnan +from ._check import InitUnKnowClassError + + +class VarParamSweep(VarParam): + """Handle multisimulation by varying parameters""" + + VERSION = 1 + NAME = "Parameter Sweep" + + # Check ImportError to remove unnecessary dependencies in unused method + # cf Methods.Simulation.VarParamSweep.check_param + if isinstance(check_param, ImportError): + check_param = property( + fget=lambda x: raise_( + ImportError( + "Can't use VarParamSweep method check_param: " + str(check_param) + ) + ) + ) + else: + check_param = check_param + # cf Methods.Simulation.VarParamSweep.generate_simulation_list + if isinstance(generate_simulation_list, ImportError): + generate_simulation_list = property( + fget=lambda x: raise_( + ImportError( + "Can't use VarParamSweep method generate_simulation_list: " + + str(generate_simulation_list) + ) + ) + ) + else: + generate_simulation_list = generate_simulation_list + # cf Methods.Simulation.VarParamSweep.get_simu_number + if isinstance(get_simu_number, ImportError): + get_simu_number = property( + fget=lambda x: raise_( + ImportError( + "Can't use VarParamSweep method get_simu_number: " + + str(get_simu_number) + ) + ) + ) + else: + get_simu_number = get_simu_number + # generic save method is available in all object + save = save + # get_logger method is available in all object + get_logger = get_logger + + def __init__( + self, + paramexplorer_list=-1, + name="", + desc="", + datakeeper_list=-1, + is_keep_all_output=False, + stop_if_error=False, + var_simu=None, + nb_simu=0, + is_reuse_femm_file=True, + postproc_list=-1, + pre_keeper_postproc_list=None, + post_keeper_postproc_list=None, + is_reuse_LUT=True, + init_dict=None, + init_str=None, + ): + """Constructor of the class. Can be use in three ways : + - __init__ (arg1 = 1, arg3 = 5) every parameters have name and default values + for pyleecan type, -1 will call the default constructor + - __init__ (init_dict = d) d must be a dictionary with property names as keys + - __init__ (init_str = s) s must be a string + s is the file path to load + + ndarray or list can be given for Vector and Matrix + object or dict can be given for pyleecan Object""" + + if init_str is not None: # Load from a file + init_dict = load_init_dict(init_str)[1] + if init_dict is not None: # Initialisation by dict + assert type(init_dict) is dict + # Overwrite default value with init_dict content + if "paramexplorer_list" in list(init_dict.keys()): + paramexplorer_list = init_dict["paramexplorer_list"] + if "name" in list(init_dict.keys()): + name = init_dict["name"] + if "desc" in list(init_dict.keys()): + desc = init_dict["desc"] + if "datakeeper_list" in list(init_dict.keys()): + datakeeper_list = init_dict["datakeeper_list"] + if "is_keep_all_output" in list(init_dict.keys()): + is_keep_all_output = init_dict["is_keep_all_output"] + if "stop_if_error" in list(init_dict.keys()): + stop_if_error = init_dict["stop_if_error"] + if "var_simu" in list(init_dict.keys()): + var_simu = init_dict["var_simu"] + if "nb_simu" in list(init_dict.keys()): + nb_simu = init_dict["nb_simu"] + if "is_reuse_femm_file" in list(init_dict.keys()): + is_reuse_femm_file = init_dict["is_reuse_femm_file"] + if "postproc_list" in list(init_dict.keys()): + postproc_list = init_dict["postproc_list"] + if "pre_keeper_postproc_list" in list(init_dict.keys()): + pre_keeper_postproc_list = init_dict["pre_keeper_postproc_list"] + if "post_keeper_postproc_list" in list(init_dict.keys()): + post_keeper_postproc_list = init_dict["post_keeper_postproc_list"] + if "is_reuse_LUT" in list(init_dict.keys()): + is_reuse_LUT = init_dict["is_reuse_LUT"] + # Set the properties (value check and convertion are done in setter) + # Call VarParam init + super(VarParamSweep, self).__init__( + paramexplorer_list=paramexplorer_list, + name=name, + desc=desc, + datakeeper_list=datakeeper_list, + is_keep_all_output=is_keep_all_output, + stop_if_error=stop_if_error, + var_simu=var_simu, + nb_simu=nb_simu, + is_reuse_femm_file=is_reuse_femm_file, + postproc_list=postproc_list, + pre_keeper_postproc_list=pre_keeper_postproc_list, + post_keeper_postproc_list=post_keeper_postproc_list, + is_reuse_LUT=is_reuse_LUT, + ) + # The class is frozen (in VarParam init), for now it's impossible to + # add new properties + + def __str__(self): + """Convert this object in a readeable string (for print)""" + + VarParamSweep_str = "" + # Get the properties inherited from VarParam + VarParamSweep_str += super(VarParamSweep, self).__str__() + return VarParamSweep_str + + def __eq__(self, other): + """Compare two objects (skip parent)""" + + if type(other) != type(self): + return False + + # Check the properties inherited from VarParam + if not super(VarParamSweep, self).__eq__(other): + return False + return True + + def compare(self, other, name="self", ignore_list=None, is_add_value=False): + """Compare two objects and return list of differences""" + + if ignore_list is None: + ignore_list = list() + if type(other) != type(self): + return ["type(" + name + ")"] + diff_list = list() + + # Check the properties inherited from VarParam + diff_list.extend( + super(VarParamSweep, self).compare( + other, name=name, ignore_list=ignore_list, is_add_value=is_add_value + ) + ) + # Filter ignore differences + diff_list = list(filter(lambda x: x not in ignore_list, diff_list)) + return diff_list + + def __sizeof__(self): + """Return the size in memory of the object (including all subobject)""" + + S = 0 # Full size of the object + + # Get size of the properties inherited from VarParam + S += super(VarParamSweep, self).__sizeof__() + return S + + def as_dict(self, type_handle_ndarray=0, keep_function=False, **kwargs): + """ + Convert this object in a json serializable dict (can be use in __init__). + type_handle_ndarray: int + How to handle ndarray (0: tolist, 1: copy, 2: nothing) + keep_function : bool + True to keep the function object, else return str + Optional keyword input parameter is for internal use only + and may prevent json serializability. + """ + + # Get the properties inherited from VarParam + VarParamSweep_dict = super(VarParamSweep, self).as_dict( + type_handle_ndarray=type_handle_ndarray, + keep_function=keep_function, + **kwargs + ) + # The class name is added to the dict for deserialisation purpose + # Overwrite the mother class name + VarParamSweep_dict["__class__"] = "VarParamSweep" + return VarParamSweep_dict + + def copy(self): + """Creates a deepcopy of the object""" + + # Handle deepcopy of all the properties + if self.paramexplorer_list is None: + paramexplorer_list_val = None + else: + paramexplorer_list_val = list() + for obj in self.paramexplorer_list: + paramexplorer_list_val.append(obj.copy()) + name_val = self.name + desc_val = self.desc + if self.datakeeper_list is None: + datakeeper_list_val = None + else: + datakeeper_list_val = list() + for obj in self.datakeeper_list: + datakeeper_list_val.append(obj.copy()) + is_keep_all_output_val = self.is_keep_all_output + stop_if_error_val = self.stop_if_error + if self.var_simu is None: + var_simu_val = None + else: + var_simu_val = self.var_simu.copy() + nb_simu_val = self.nb_simu + is_reuse_femm_file_val = self.is_reuse_femm_file + if self.postproc_list is None: + postproc_list_val = None + else: + postproc_list_val = list() + for obj in self.postproc_list: + postproc_list_val.append(obj.copy()) + if self.pre_keeper_postproc_list is None: + pre_keeper_postproc_list_val = None + else: + pre_keeper_postproc_list_val = list() + for obj in self.pre_keeper_postproc_list: + pre_keeper_postproc_list_val.append(obj.copy()) + if self.post_keeper_postproc_list is None: + post_keeper_postproc_list_val = None + else: + post_keeper_postproc_list_val = list() + for obj in self.post_keeper_postproc_list: + post_keeper_postproc_list_val.append(obj.copy()) + is_reuse_LUT_val = self.is_reuse_LUT + # Creates new object of the same type with the copied properties + obj_copy = type(self)( + paramexplorer_list=paramexplorer_list_val, + name=name_val, + desc=desc_val, + datakeeper_list=datakeeper_list_val, + is_keep_all_output=is_keep_all_output_val, + stop_if_error=stop_if_error_val, + var_simu=var_simu_val, + nb_simu=nb_simu_val, + is_reuse_femm_file=is_reuse_femm_file_val, + postproc_list=postproc_list_val, + pre_keeper_postproc_list=pre_keeper_postproc_list_val, + post_keeper_postproc_list=post_keeper_postproc_list_val, + is_reuse_LUT=is_reuse_LUT_val, + ) + return obj_copy + + def _set_None(self): + """Set all the properties to None (except pyleecan object)""" + + # Set to None the properties inherited from VarParam + super(VarParamSweep, self)._set_None() diff --git a/pyleecan/Classes/import_all.py b/pyleecan/Classes/import_all.py index d1d6ce799..96f2432ef 100644 --- a/pyleecan/Classes/import_all.py +++ b/pyleecan/Classes/import_all.py @@ -232,7 +232,9 @@ from ..Classes.VarLoad import VarLoad from ..Classes.VarLoadCurrent import VarLoadCurrent from ..Classes.VarLoadVoltage import VarLoadVoltage +from ..Classes.VarOpti import VarOpti from ..Classes.VarParam import VarParam +from ..Classes.VarParamSweep import VarParamSweep from ..Classes.VarSimu import VarSimu from ..Classes.VentilationCirc import VentilationCirc from ..Classes.VentilationPolar import VentilationPolar diff --git a/pyleecan/Functions/load_switch.py b/pyleecan/Functions/load_switch.py index b9674353f..c1c644edc 100644 --- a/pyleecan/Functions/load_switch.py +++ b/pyleecan/Functions/load_switch.py @@ -234,7 +234,9 @@ "VarLoad": VarLoad, "VarLoadCurrent": VarLoadCurrent, "VarLoadVoltage": VarLoadVoltage, + "VarOpti": VarOpti, "VarParam": VarParam, + "VarParamSweep": VarParamSweep, "VarSimu": VarSimu, "VentilationCirc": VentilationCirc, "VentilationPolar": VentilationPolar, diff --git a/pyleecan/Generator/ClassesRef/Simulation/VarOpti.csv b/pyleecan/Generator/ClassesRef/Simulation/VarOpti.csv new file mode 100644 index 000000000..1a8056c68 --- /dev/null +++ b/pyleecan/Generator/ClassesRef/Simulation/VarOpti.csv @@ -0,0 +1,4 @@ +Variable name,Unit,Description (EN),Size,Type,Default value,Minimum value,Maximum value,,Package,Inherit,Methods,Constant Name,Constant Value,Class description +objective_list,-,List containing OptiObjective objects,0,[OptiObjective],-1,,,,Simulation,VarParam,check,VERSION,1,Handle Optimization multisimulation by varying parameters +constraint_list,-,List containing OptiConstraint objects,0,[OptiConstraint],-1,,,,,,run,NAME,"""Optimization""", +solver,-,Object that solve an OptiProblem,0,OptiSolver,None,,,,,,get_full_solver,,, diff --git a/pyleecan/Generator/ClassesRef/Simulation/VarParam.csv b/pyleecan/Generator/ClassesRef/Simulation/VarParam.csv index 6822a4f41..95bd27ee8 100644 --- a/pyleecan/Generator/ClassesRef/Simulation/VarParam.csv +++ b/pyleecan/Generator/ClassesRef/Simulation/VarParam.csv @@ -1,4 +1,3 @@ Variable name,Unit,Description (EN),Size,Type,Default value,Minimum value,Maximum value,,Package,Inherit,Methods,Constant Name,Constant Value,Class description -paramexplorer_list,-,List containing ParamSetter to define every simulation,0,[ParamExplorer],,,,,Simulation,VarSimu,check_param,VERSION,1,Handle multisimulation by varying parameters -,,,,,,,,,,,generate_simulation_list,NAME,"""Parameter Sweep""", -,,,,,,,,,,,get_simu_number,,, +paramexplorer_list,-,List containing ParamSetter to define every simulation,0,[ParamExplorer],,,,,Simulation,VarSimu,,VERSION,1,Handle multisimulation by varying parameters +,,,,,,,,,,,,NAME,"""Parameter Sweep""", diff --git a/pyleecan/Generator/ClassesRef/Simulation/VarParamSweep.csv b/pyleecan/Generator/ClassesRef/Simulation/VarParamSweep.csv new file mode 100644 index 000000000..33290e087 --- /dev/null +++ b/pyleecan/Generator/ClassesRef/Simulation/VarParamSweep.csv @@ -0,0 +1,4 @@ +Variable name,Unit,Description (EN),Size,Type,Default value,Minimum value,Maximum value,,Package,Inherit,Methods,Constant Name,Constant Value,Class description +,,,,,,,,,Simulation,VarParam,check_param,VERSION,1,Handle multisimulation by varying parameters +,,,,,,,,,,,generate_simulation_list,NAME,"""Parameter Sweep""", +,,,,,,,,,,,get_simu_number,,, diff --git a/pyleecan/Methods/Optimization/OptiBayesAlgSmoot/check_optimization_input.py b/pyleecan/Methods/Optimization/OptiBayesAlgSmoot/check_optimization_input.py index f7aaecd47..2ff8922dc 100644 --- a/pyleecan/Methods/Optimization/OptiBayesAlgSmoot/check_optimization_input.py +++ b/pyleecan/Methods/Optimization/OptiBayesAlgSmoot/check_optimization_input.py @@ -72,8 +72,10 @@ def check_optimization_input(self): ) else: for design_var in self.problem.design_var: - if not isinstance(design_var, OptiDesignVarInterval) and not isinstance(design_var, OptiDesignVarSet): - mess = 'The design variable \'{}\' is expected to be an OptiDesignVarSet or an OptiDesignVarInterval.'.format( + if not isinstance(design_var, OptiDesignVarInterval) and not isinstance( + design_var, OptiDesignVarSet + ): + mess = "The design variable '{}' is expected to be an OptiDesignVarSet or an OptiDesignVarInterval.".format( design_var.name ) raise OptimizationAttributeError(mess) diff --git a/pyleecan/Methods/Optimization/OptiGenAlgNsga2Deap/check_optimization_input.py b/pyleecan/Methods/Optimization/OptiGenAlgNsga2Deap/check_optimization_input.py index c9173b00c..a414dbec9 100644 --- a/pyleecan/Methods/Optimization/OptiGenAlgNsga2Deap/check_optimization_input.py +++ b/pyleecan/Methods/Optimization/OptiGenAlgNsga2Deap/check_optimization_input.py @@ -81,8 +81,10 @@ def check_optimization_input(self): ) else: for design_var in self.problem.design_var: - if not isinstance(design_var, OptiDesignVarInterval) and not isinstance(design_var, OptiDesignVarSet): - mess = 'The design variable \'{}\' is expected to be an OptiDesignVarSet or an OptiDesignVarInterval.'.format( + if not isinstance(design_var, OptiDesignVarInterval) and not isinstance( + design_var, OptiDesignVarSet + ): + mess = "The design variable '{}' is expected to be an OptiDesignVarSet or an OptiDesignVarInterval.".format( design_var.name ) raise OptimizationAttributeError(mess) diff --git a/pyleecan/Methods/Optimization/OptiGenAlgNsga2Deap/solve.py b/pyleecan/Methods/Optimization/OptiGenAlgNsga2Deap/solve.py index 56b2734e0..e40d9aac1 100644 --- a/pyleecan/Methods/Optimization/OptiGenAlgNsga2Deap/solve.py +++ b/pyleecan/Methods/Optimization/OptiGenAlgNsga2Deap/solve.py @@ -22,7 +22,7 @@ def create_setter(accessor, attribute): return lambda simu, val: setattr(eval(accessor), attribute, val) -def solve(self): +def solve(self, xoutput=None): """Method to perform NSGA-II using DEAP tools Parameters @@ -34,6 +34,8 @@ def solve(self): ------- multi_output : OutputMultiOpti class containing the results + xoutput : XOutput + class containing the results of the simulations """ logger = self.get_logger() @@ -67,10 +69,8 @@ class containing the results self.create_toolbox() # Add the reference output to multi_output - if isinstance(self.problem.simu.parent, Output): - xoutput = XOutput( - init_dict=self.problem.simu.parent.as_dict(keep_function=True) - ) + if xoutput is not None: + xoutput = xoutput else: xoutput = XOutput(simu=self.problem.simu.copy()) diff --git a/pyleecan/Methods/Simulation/VarOpti/check.py b/pyleecan/Methods/Simulation/VarOpti/check.py new file mode 100644 index 000000000..597c09c45 --- /dev/null +++ b/pyleecan/Methods/Simulation/VarOpti/check.py @@ -0,0 +1,125 @@ +from ....Functions.Load.import_class import import_class + + +class VarOptiError(Exception): + pass + + +class VarOptiObjectiveError(Exception): + pass + + +class VarOptiConstraintError(Exception): + pass + + +class VarOptiDesignVarError(Exception): + pass + + +class VarOptiSolverError(Exception): + pass + + +class VarOptiDataKeeperError(Exception): + pass + + +def check(self): + """Check VarOpti parameters validity""" + + Simu1 = import_class("pyleecan.Classes", "Simu1") + OptiObjective = import_class("pyleecan.Classes", "OptiObjective") + OptiConstraint = import_class("pyleecan.Classes", "OptiConstraint") + OptiDesignVarSet = import_class("pyleecan.Classes", "OptiDesignVarSet") + OptiBayesAlgSmoot = import_class("pyleecan.Classes", "OptiBayesAlgSmoot") + OptiGenAlgNsga2Deap = import_class("pyleecan.Classes", "OptiGenAlgNsga2Deap") + OptiDesignVarInterval = import_class("pyleecan.Classes", "OptiDesignVarInterval") + + # Check that VarOpti is always in the first layer of var_simu + if not isinstance(self.parent, Simu1): + raise VarOptiError("VarOpti object must be the very first layer in var_simu") + + # Check objectives + if self.objective_list == -1 or not isinstance(self.objective_list, list): + raise VarOptiError("VarOpti object must have a list in objective_list") + elif len(self.objective_list) == 0: + raise VarOptiError( + "VarOpti object must have at least one objective in objective_list" + ) + else: + for objective in self.objective_list: + if not isinstance(objective, OptiObjective): + raise VarOptiError( + "VarOpti object must have only OptiObjective objects in objective_list" + ) + elif objective.symbol in ["", None]: + raise VarOptiObjectiveError("OptiObjective.symbol cannot be empty") + elif objective.keeper is None: + raise VarOptiObjectiveError("OptiObjective.keeper must be defined") + + # Check constraints + if self.constraint_list == -1 or not isinstance(self.constraint_list, list): + raise VarOptiError("VarOpti object must have a list in constraint_list") + elif not len(self.constraint_list) == 0: + for constraint in self.constraint_list: + if not isinstance(constraint, OptiConstraint): + raise VarOptiError( + "VarOpti object must have only OptiConstraint objects in constraint_list" + ) + elif constraint.symbol in ["", None]: + raise VarOptiConstraintError("OptiConstraint.symbol cannot be empty") + elif constraint.keeper is None: + raise VarOptiConstraintError("OptiConstraint.keeper must be defined") + + # Check design variables + if self.paramexplorer_list == -1 or not isinstance(self.paramexplorer_list, list): + raise VarOptiError("VarOpti object must have a list in paramexplorer_list") + elif len(self.paramexplorer_list) == 0: + raise VarOptiError( + "VarOpti object must have at least one objective in paramexplorer_list" + ) + else: + for design_var in self.paramexplorer_list: + if not isinstance(design_var, OptiDesignVarInterval) and not isinstance( + design_var, OptiDesignVarSet + ): + raise VarOptiError( + "VarOpti object must have only OptiDesignVarInterval or OptiDesignVarSet objects in paramexplorer_list" + ) + elif design_var.symbol in ["", None]: + raise VarOptiDesignVarError( + "OptiDesignVarSet.symbol or OptiDesignVarInterval.symbol cannot be empty" + ) + elif design_var.setter is None: + raise VarOptiDesignVarError( + "OptiDesignVarSet.setter or OptiDesignVarInterval.setter must be defined" + ) + + # Keep every output if there is no DataKeeper defined + if len(self.datakeeper_list) == 0 and self.is_keep_all_output is False: + logger = self.get_logger() + logger.warning( + "No datakeeper has been define in VarParamSweep, setting is_keep_all_output as True." + ) + self.is_keep_all_output = True + + # Check DataKeepers + for datakeeper in self.datakeeper_list: + if datakeeper.symbol in ["", None]: + raise VarOptiDataKeeperError("DataKeeper.symbol cannot be empty") + elif datakeeper.keeper is None: + raise VarOptiDataKeeperError("DataKeeper.keeper must be defined") + + # Check solver + if self.solver is None: + raise VarOptiSolverError("VarOpti object must have a solver") + elif not isinstance(self.solver, OptiGenAlgNsga2Deap) and not isinstance( + self.solver, OptiBayesAlgSmoot + ): + raise VarOptiSolverError( + "VarOpti object must have only a solver of type OptiGenAlgNsga2Deap or OptiBayesAlgSmoot" + ) + + solver = self.get_full_solver() + solver.check_optimization_input() diff --git a/pyleecan/Methods/Simulation/VarOpti/get_full_solver.py b/pyleecan/Methods/Simulation/VarOpti/get_full_solver.py new file mode 100644 index 000000000..68411ba72 --- /dev/null +++ b/pyleecan/Methods/Simulation/VarOpti/get_full_solver.py @@ -0,0 +1,32 @@ +from ....Classes.OptiProblem import OptiProblem + +def evaluate(output): + """Skip calculations""" + pass + +def get_full_solver(self): + """Method to return a fully setted solver""" + + # Create reference simulation + ref_simu = self.parent.copy() + ref_simu.var_simu = self.var_simu # var_simu default is None + ref_simu.index = None + ref_simu.layer = self.parent.layer + 1 + + # Creation of the problem + problem = OptiProblem( + simu=ref_simu, + design_var=self.paramexplorer_list, + obj_func=self.objective_list, + datakeeper_list=self.datakeeper_list, + constraint=self.constraint_list, + eval_func=evaluate + ) + + # Reset the parent because when put into problem, parent of simu becomes OptiProblem instead of OutPut + problem.simu.parent = self.parent.parent + # Copy the solver to don't rewrite it and give the problem + solver = self.solver.copy() + solver.problem = problem + + return solver \ No newline at end of file diff --git a/pyleecan/Methods/Simulation/VarOpti/run.py b/pyleecan/Methods/Simulation/VarOpti/run.py new file mode 100644 index 000000000..473ad4960 --- /dev/null +++ b/pyleecan/Methods/Simulation/VarOpti/run.py @@ -0,0 +1,9 @@ +def run(self): + """Run method for VarOpti to solve the problem""" + + solver = self.get_full_solver() + + # Launch simulations + xoutput = solver.solve(xoutput=self.parent.parent) + + return xoutput diff --git a/pyleecan/Methods/Simulation/VarParam/check_param.py b/pyleecan/Methods/Simulation/VarParamSweep/check_param.py similarity index 86% rename from pyleecan/Methods/Simulation/VarParam/check_param.py rename to pyleecan/Methods/Simulation/VarParamSweep/check_param.py index 6fde62ea6..7d9eb769c 100644 --- a/pyleecan/Methods/Simulation/VarParam/check_param.py +++ b/pyleecan/Methods/Simulation/VarParamSweep/check_param.py @@ -5,7 +5,7 @@ class ParamExplorerError(Exception): pass -class VarParamError(Exception): +class VarParamSweepError(Exception): pass @@ -14,12 +14,12 @@ class DataKeeperError(Exception): def check_param(self): - """Check VarParam parameters validity + """Check VarParamSweep parameters validity Raises ------ ParamExplorerError: Error in ParamExplorer setting - VarParamError: Error in VarParam general setting + VarParamSweepError: Error in VarParamSweep general setting DataKeeperError: Error in DataKeeper setting """ # run the base class check first @@ -44,7 +44,7 @@ def check_param(self): if len(self.datakeeper_list) == 0 and self.is_keep_all_output is False: logger = self.get_logger() logger.warning( - "No datakeeper has been define in VarParam, setting is_keep_all_output as True." + "No datakeeper has been define in VarParamSweep, setting is_keep_all_output as True." ) self.is_keep_all_output = True diff --git a/pyleecan/Methods/Simulation/VarParam/generate_simulation_list.py b/pyleecan/Methods/Simulation/VarParamSweep/generate_simulation_list.py similarity index 100% rename from pyleecan/Methods/Simulation/VarParam/generate_simulation_list.py rename to pyleecan/Methods/Simulation/VarParamSweep/generate_simulation_list.py diff --git a/pyleecan/Methods/Simulation/VarParam/get_simu_number.py b/pyleecan/Methods/Simulation/VarParamSweep/get_simu_number.py similarity index 85% rename from pyleecan/Methods/Simulation/VarParam/get_simu_number.py rename to pyleecan/Methods/Simulation/VarParamSweep/get_simu_number.py index 361380ef7..0c1601f05 100644 --- a/pyleecan/Methods/Simulation/VarParam/get_simu_number.py +++ b/pyleecan/Methods/Simulation/VarParamSweep/get_simu_number.py @@ -3,8 +3,8 @@ def get_simu_number(self): Parameters ---------- - self : VarParam - A VarParam object + self : VarParamSweep + A VarParamSweep object Returns ------- diff --git a/pyleecan/Methods/Simulation/VarSimu/check_param.py b/pyleecan/Methods/Simulation/VarSimu/check_param.py index 235319316..10d315895 100644 --- a/pyleecan/Methods/Simulation/VarSimu/check_param.py +++ b/pyleecan/Methods/Simulation/VarSimu/check_param.py @@ -6,7 +6,7 @@ class VarSimuError(Exception): def check_param(self): - """Check VarParam parameters validity""" + """Check VarParamSweep parameters validity""" if type(self).__name__ == "VarSimu": raise VarSimuError( "VarSimu is an abstract class, please create one of its daughters." From c869ccfc33291ad42ae996ea6820b0d8fc652045 Mon Sep 17 00:00:00 2001 From: BenjaminGabet Date: Tue, 6 Dec 2022 10:50:08 +0100 Subject: [PATCH 04/10] [NF] Test VarOpti created --- .../Optimization/test_opti_varopti.py | 182 ++++++++++++++---- pyleecan/Methods/Simulation/VarOpti/check.py | 2 +- .../Simulation/VarOpti/get_full_solver.py | 7 - 3 files changed, 143 insertions(+), 48 deletions(-) diff --git a/Tests/Validation/Optimization/test_opti_varopti.py b/Tests/Validation/Optimization/test_opti_varopti.py index 1cc16373c..b311ce269 100644 --- a/Tests/Validation/Optimization/test_opti_varopti.py +++ b/Tests/Validation/Optimization/test_opti_varopti.py @@ -9,78 +9,180 @@ # Imports from os.path import join import pytest +from pyleecan.Classes.MagFEMM import MagFEMM from pyleecan.Classes.Simu1 import Simu1 +from pyleecan.Classes.OPdq import OPdq from pyleecan.Classes.DataKeeper import DataKeeper from pyleecan.Classes.OptiDesignVarInterval import OptiDesignVarInterval +from pyleecan.Classes.OptiDesignVarSet import OptiDesignVarSet from pyleecan.Classes.OptiObjective import OptiObjective -from pyleecan.Classes.OptiProblem import OptiProblem +from pyleecan.Classes.OptiConstraint import OptiConstraint from pyleecan.Classes.OptiGenAlgNsga2Deap import OptiGenAlgNsga2Deap +from pyleecan.Classes.ImportMatrixVal import ImportMatrixVal +from pyleecan.Classes.ImportGenVectLin import ImportGenVectLin +from pyleecan.Classes.InputCurrent import InputCurrent from pyleecan.Classes.VarOpti import VarOpti - -import random +from pyleecan.Classes.Output import Output from pyleecan.Functions.load import load from pyleecan.definitions import DATA_DIR +import matplotlib.pyplot as plt +import matplotlib.image as img +import numpy as np +import random +from Tests import save_validation_path as save_path +from pyleecan.definitions import DATA_DIR, TEST_DIR +def harm1(output): + """Return the first torque harmonic """ + harm_list = output.mag.Tem.get_magnitude_along("freqs")["T_{em}"] + + # Return the first torque harmonic + return harm_list[1] @pytest.mark.SCIM @pytest.mark.MagFEMM -@pytest.mark.SingleOP def test_opti_varopti(): # Defining reference Output # Definition of the enforced output of the electrical module - Railway_Traction = load(join(DATA_DIR, "Machine", "Railway_Traction.json")) + # Import the machine from a script + Toyota_Prius = load(join(DATA_DIR, "Machine", "Toyota_Prius.json")) + Toyota_Prius.plot() + rotor_speed = 2000 # [rpm] - # Definition of the simulation - simu = Simu1(name="test_opti_datakeeper_list", machine=Railway_Traction, layer=0) + # Create the Simulation + simu_ref = Simu1(name="EM_SIPMSM_AL_001", machine=Toyota_Prius, layer=0) - # Design variable - my_vars = [ - OptiDesignVarInterval( - name="Rotor slot height", - symbol="RH0", - space=[0, 5], # May generate error in FEMM - get_value=lambda space: random.uniform(*space), - setter="simu.machine.rotor.slot.H0", + # Defining Simulation Input + simu_ref.input = InputCurrent() + + # time discretization [s] + simu_ref.input.Nt_tot = 16 + + # Angular discretization along the airgap circonference for flux density calculation + simu_ref.input.Na_tot = 1024 + + # Defining Operating Point + simu_ref.input.OP = OPdq() + simu_ref.input.OP.N0 = rotor_speed # Rotor speed as a function of time [rpm] + # Stator sinusoidal currents + simu_ref.input.OP.Id_ref = -100 # [Arms] + simu_ref.input.OP.Iq_ref = 200 # [Arms] + + # Definition of the magnetic simulation (is_mmfr=False => no flux from the magnets) + simu_ref.mag = MagFEMM( + type_BH_stator=0, # 0 to use the B(H) curve, + # 1 to use linear B(H) curve according to mur_lin, + # 2 to enforce infinite permeability (mur_lin =100000) + type_BH_rotor=0, # 0 to use the B(H) curve, + # 1 to use linear B(H) curve according to mur_lin, + # 2 to enforce infinite permeability (mur_lin =100000) + file_name = "", # Name of the file to save the FEMM model + is_periodicity_a=True, # Use Angular periodicity + is_periodicity_t=True, # Use time periodicity, + is_sliding_band=True, + # Kmesh_fineness = 0.2, # Decrease mesh precision + # Kgeo_fineness = 0.2, # Decrease mesh precision + ) + + # We only use the magnetic part + simu_ref.force = None + simu_ref.struct = None + + my_obj = [ + OptiObjective( + name="Maximization of the average torque", + symbol="Tem_av", + unit="N.m", + keeper="lambda output: -abs(output.mag.Tem_av)", # keeper can be saved ), - OptiDesignVarInterval( - name="Stator slot height", - symbol="SH0", - space=[0, 3], # May generate error in FEMM - get_value=lambda space: random.uniform(*space), - setter="simu.machine.stator.slot.H0", + OptiObjective( + name="Minimization of the first torque harmonic", + symbol="Tem_h1", + unit="N.m", + keeper=harm1, # keeper will be cleaned in save ), ] - # Objectives - objs = [ - OptiObjective( - name="Minimization of the rotor slot width", - symbol="R_s_w0", - unit="m", - keeper="lambda output: output.simu.machine.rotor.slot.W0", - ) + # Design variables + my_design_var = [ + OptiDesignVarInterval( + name="Stator slot opening", + symbol = "SW0", + unit = "m", + space=[ + 0 * simu_ref.machine.stator.slot.W2, + simu_ref.machine.stator.slot.W2, + ], + get_value="lambda space: random.uniform(*space)", # To initiate randomly the first generation + setter="simu.machine.stator.slot.W0", # Variable to edit + ), + OptiDesignVarSet( + name= "Rotor ext radius", + symbol = "Rext", + unit = "m", + space=[ + 0.998 * simu_ref.machine.rotor.Rext, + 0.999 * simu_ref.machine.rotor.Rext, + simu_ref.machine.rotor.Rext, + 1.001 * simu_ref.machine.rotor.Rext, + ], + get_value="lambda space: random.choice(space)", + setter = "simu.machine.rotor.Rext" + ), ] - datakeeper_list = [ - DataKeeper( - name="Minimization of the rotor slot width", - symbol="R_s_w0_bis", - unit="m", - keeper="lambda output: output.simu.machine.rotor.slot.W0", + my_constraint = [ + OptiConstraint( + name = "const1", + type_const = "<=", + value = 700, + keeper = "lambda output: abs(output.mag.Tem_rip_pp)", ) ] # Solving the problem - solver = OptiGenAlgNsga2Deap(size_pop=4, nb_gen=2, p_mutate=0) + solver = OptiGenAlgNsga2Deap(size_pop=8, nb_gen=8, p_mutate=0.5) # Creating a VarOpti and launch the simulation - simu.var_simu = VarOpti(paramexplorer_list=my_vars, objective_list=objs, datakeeper_list=datakeeper_list, solver=solver, var_simu=simu.var_simu) - simu.var_simu.check() - res = simu.run() + simu_ref.var_simu = VarOpti(paramexplorer_list=my_design_var, objective_list=my_obj, constraint_list=my_constraint, solver=solver, var_simu=simu_ref.var_simu) + simu_ref.var_simu.check() + res = simu_ref.run() + + # Create a figure containing 4 subfigures (axes) + fig, axs = plt.subplots(2,2, figsize=(8,8)) + + # Plot every individual in the fitness space + res.plot_generation( + x_symbol = "Tem_av", # symbol of the first objective function or design variable + y_symbol = "Tem_h1", # symbol of the second objective function or design variable + ax = axs[0,0] # ax to plot + ) + + # Plot every individual in the design space + res.plot_generation( + x_symbol = "SW0", + y_symbol = "Rext", + ax = axs[0,1] + ) + + # Plot pareto front in fitness space + res.plot_pareto( + x_symbol = "Tem_av", + y_symbol = "Tem_h1", + ax = axs[1,0] + ) + + # Plot pareto front in design space + res.plot_pareto( + x_symbol = "SW0", + y_symbol = "Rext", + ax = axs[1,1] + ) - assert res["R_s_w0"].result == res["R_s_w0_bis"].result + fig.tight_layout() + fig.savefig(join(save_path, "test_opti_varopti.png")) if __name__ == "__main__": test_opti_varopti() diff --git a/pyleecan/Methods/Simulation/VarOpti/check.py b/pyleecan/Methods/Simulation/VarOpti/check.py index 597c09c45..3b3191af1 100644 --- a/pyleecan/Methods/Simulation/VarOpti/check.py +++ b/pyleecan/Methods/Simulation/VarOpti/check.py @@ -67,7 +67,7 @@ def check(self): raise VarOptiError( "VarOpti object must have only OptiConstraint objects in constraint_list" ) - elif constraint.symbol in ["", None]: + elif constraint.value in ["", None]: raise VarOptiConstraintError("OptiConstraint.symbol cannot be empty") elif constraint.keeper is None: raise VarOptiConstraintError("OptiConstraint.keeper must be defined") diff --git a/pyleecan/Methods/Simulation/VarOpti/get_full_solver.py b/pyleecan/Methods/Simulation/VarOpti/get_full_solver.py index 68411ba72..1dead4982 100644 --- a/pyleecan/Methods/Simulation/VarOpti/get_full_solver.py +++ b/pyleecan/Methods/Simulation/VarOpti/get_full_solver.py @@ -1,9 +1,5 @@ from ....Classes.OptiProblem import OptiProblem -def evaluate(output): - """Skip calculations""" - pass - def get_full_solver(self): """Method to return a fully setted solver""" @@ -20,11 +16,8 @@ def get_full_solver(self): obj_func=self.objective_list, datakeeper_list=self.datakeeper_list, constraint=self.constraint_list, - eval_func=evaluate ) - # Reset the parent because when put into problem, parent of simu becomes OptiProblem instead of OutPut - problem.simu.parent = self.parent.parent # Copy the solver to don't rewrite it and give the problem solver = self.solver.copy() solver.problem = problem From 3816b4224dd60ffaca3f93adea5dd6dd1c018dbe Mon Sep 17 00:00:00 2001 From: BenjaminGabet Date: Wed, 7 Dec 2022 16:13:17 +0100 Subject: [PATCH 05/10] [NF] Adding Retrocompatibility for Optimisation rework. And test for it --- .../OptiConstraint_and_OptiDesignVar_old.json | 1551 ++++++++++++++++ .../OptiConstraint_and_OptiDesignVar_ref.json | 1561 +++++++++++++++++ .../VarParam/VarParam_old.json | 43 + .../VarParam/VarParam_ref.json | 43 + Tests/Functions/test_retrocompatibility.py | 47 + .../Optimization/test_opti_varopti.py | 2 - pyleecan/Functions/Load/retrocompatibility.py | 107 ++ setup.py | 2 +- 8 files changed, 3353 insertions(+), 3 deletions(-) create mode 100644 Tests/Data/Retrocompatibility/Optimisation/OptiConstraint_and_OptiDesignVar_old.json create mode 100644 Tests/Data/Retrocompatibility/Optimisation/OptiConstraint_and_OptiDesignVar_ref.json create mode 100644 Tests/Data/Retrocompatibility/VarParam/VarParam_old.json create mode 100644 Tests/Data/Retrocompatibility/VarParam/VarParam_ref.json diff --git a/Tests/Data/Retrocompatibility/Optimisation/OptiConstraint_and_OptiDesignVar_old.json b/Tests/Data/Retrocompatibility/Optimisation/OptiConstraint_and_OptiDesignVar_old.json new file mode 100644 index 000000000..08215ed47 --- /dev/null +++ b/Tests/Data/Retrocompatibility/Optimisation/OptiConstraint_and_OptiDesignVar_old.json @@ -0,0 +1,1551 @@ +{ + "__class__": "OptiGenAlgNsga2Deap", + "__save_date__": "2022_12_07 13h57min15s ", + "__version__": "pyleecan_1.4.1", + "crossover": null, + "is_keep_all_output": false, + "logger_name": "Pyleecan.OptiSolver", + "mutator": null, + "nb_gen": 40, + "p_cross": 0.9, + "p_mutate": 0.5, + "problem": { + "__class__": "OptiProblem", + "constraint": [ + { + "__class__": "OptiConstraint", + "get_variable": "lambda output: (output.simu.machine.rotor.slot.H0 - 5) ** 2 + output.simu.machine.stator.slot.H0 ** 2", + "name": "first", + "type_const": "<=", + "value": 25 + }, + { + "__class__": "OptiConstraint", + "get_variable": "lambda output: (output.simu.machine.rotor.slot.H0 - 5) ** 2 + (output.simu.machine.stator.slot.H0 + 3) ** 2", + "name": "second", + "type_const": ">=", + "value": 7.7 + } + ], + "datakeeper_list": [], + "design_var": [ + { + "__class__": "OptiDesignVar", + "get_value": "lambda space: random.uniform(*space)", + "getter": null, + "name": "Rotor slot height", + "setter": "lambda simu, val: setattr(eval('simu.machine.rotor.slot'), 'H0', val)", + "space": [ + 0, + 5 + ], + "symbol": "RH0", + "type_var": "interval", + "unit": "" + }, + { + "__class__": "OptiDesignVar", + "get_value": "lambda space: random.uniform(*space)", + "getter": null, + "name": "Stator slot height", + "setter": "lambda simu, val: setattr(eval('simu.machine.stator.slot'), 'H0', val)", + "space": [ + 0, + 3 + ], + "symbol": "SH0", + "type_var": "interval", + "unit": "" + } + ], + "eval_func": null, + "obj_func": [ + { + "__class__": "OptiObjective", + "error_keeper": null, + "keeper": "lambda output: output.mag.Tem_av", + "name": "Maximization of the torque average", + "physic": null, + "result": [], + "result_ref": null, + "symbol": "obj1", + "unit": "N.m" + }, + { + "__class__": "OptiObjective", + "error_keeper": null, + "keeper": "lambda output: output.mag.Tem_rip_norm", + "name": "Minimization of the torque ripple", + "physic": null, + "result": [], + "result_ref": null, + "symbol": "obj2", + "unit": "N.m" + } + ], + "preprocessing": null, + "simu": { + "__class__": "Simu1", + "desc": "", + "elec": null, + "force": null, + "index": null, + "input": { + "Na_tot": 2048, + "Nrev": null, + "Nt_tot": 2048, + "OP": null, + "__class__": "Input", + "angle": null, + "t_final": null, + "time": null + }, + "layer": null, + "layer_log_warn": null, + "logger_name": "Pyleecan.Simulation", + "loss": null, + "machine": { + "__class__": "MachineSCIM", + "desc": "", + "frame": null, + "logger_name": "Pyleecan.Machine", + "name": "Railway_Traction", + "rotor": { + "Hscr": 0.02, + "Kf1": 0.95, + "Ksfill": null, + "L1": 0.35, + "Lscr": 0.015, + "Nrvd": 0, + "Rext": 0.131, + "Rint": 0.045, + "Wrvd": 0, + "__class__": "LamSquirrelCage", + "axial_vent": [ + { + "Alpha0": 0.3927, + "D0": 0.02, + "H0": 0.07, + "Zh": 8, + "__class__": "VentilationCirc", + "magnetization_dict_offset": null, + "mat_void": { + "HT": { + "Cp": 1, + "__class__": "MatHT", + "alpha": 0, + "lambda_x": 1, + "lambda_y": 1, + "lambda_z": 1 + }, + "__class__": "Material", + "desc": "Material description", + "eco": { + "__class__": "MatEconomical", + "cost_unit": 0.127, + "unit_name": "$" + }, + "elec": { + "__class__": "MatElectrical", + "alpha": 0, + "epsr": 1, + "rho": 0 + }, + "is_isotropic": false, + "mag": { + "BH_curve": { + "__class__": "ImportMatrix", + "is_transpose": false + }, + "Brm20": 0, + "LossData": { + "__class__": "ImportMatrix", + "is_transpose": false + }, + "ModelBH": { + "Bmax": 2.31, + "Hmax": null, + "__class__": "ModelBH", + "delta": 100 + }, + "Wlam": 0, + "__class__": "MatMagnetics", + "alpha_Br": 0, + "is_BH_extrapolate": false, + "mur_lin": 1 + }, + "name": "Material", + "path": "", + "struct": { + "Ex": 215000000000.0, + "Ey": 215000000000.0, + "Ez": 80000000000, + "Gxy": 0, + "Gxz": 2000000000, + "Gyz": 2000000000, + "__class__": "MatStructural", + "nu_xy": 0.3, + "nu_xz": 0.03, + "nu_yz": 0.03, + "rho": 7650 + } + } + } + ], + "bore": null, + "is_internal": true, + "is_stator": false, + "mat_type": { + "HT": { + "Cp": 1, + "__class__": "MatHT", + "alpha": 0, + "lambda_x": 1, + "lambda_y": 1, + "lambda_z": 1 + }, + "__class__": "Material", + "desc": "Lamination M400-50A", + "eco": { + "__class__": "MatEconomical", + "cost_unit": 0.127, + "unit_name": "$" + }, + "elec": { + "__class__": "MatElectrical", + "alpha": 0, + "epsr": 1, + "rho": 4.6e-07 + }, + "is_isotropic": false, + "mag": { + "BH_curve": { + "__class__": "ImportMatrixVal", + "is_transpose": false, + "value": [ + [ + 0.0, + 0.0 + ], + [ + 100.0, + 0.5 + ], + [ + 150.0, + 0.7 + ], + [ + 180.0, + 0.8 + ], + [ + 200.0, + 0.9 + ], + [ + 250.0, + 1.0 + ], + [ + 300.0, + 1.05 + ], + [ + 350.0, + 1.1 + ], + [ + 450.0, + 1.15 + ], + [ + 550.0, + 1.2 + ], + [ + 650.0, + 1.225 + ], + [ + 750.0, + 1.25 + ], + [ + 850.0, + 1.275 + ], + [ + 950.0, + 1.3 + ], + [ + 1100.0, + 1.325 + ], + [ + 1250.0, + 1.35 + ], + [ + 1400.0, + 1.375 + ], + [ + 1550.0, + 1.4 + ], + [ + 1700.0, + 1.425 + ], + [ + 1900.0, + 1.45 + ], + [ + 2150.0, + 1.475 + ], + [ + 2450.0, + 1.5 + ], + [ + 2750.0, + 1.525 + ], + [ + 3150.0, + 1.55 + ], + [ + 3600.0, + 1.575 + ], + [ + 4100.0, + 1.6 + ], + [ + 4700.0, + 1.625 + ], + [ + 5250.0, + 1.65 + ], + [ + 6000.0, + 1.675 + ], + [ + 6700.0, + 1.7 + ], + [ + 7500.0, + 1.725 + ], + [ + 8650.0, + 1.75 + ], + [ + 9500.0, + 1.775 + ], + [ + 10750.0, + 1.8 + ], + [ + 14500.0, + 1.85 + ], + [ + 19500.0, + 1.9 + ], + [ + 25000.0, + 1.95 + ], + [ + 33000.0, + 2.0 + ], + [ + 44000.0, + 2.05 + ], + [ + 57000.0, + 2.1 + ], + [ + 74000.0, + 2.15 + ], + [ + 96000.0, + 2.2 + ], + [ + 130000.0, + 2.25 + ], + [ + 170000.0, + 2.3 + ] + ] + }, + "Brm20": 0, + "LossData": { + "__class__": "ImportMatrix", + "is_transpose": false + }, + "ModelBH": { + "Bmax": 2.31, + "Hmax": null, + "__class__": "ModelBH", + "delta": 100 + }, + "Wlam": 0.0005, + "__class__": "MatMagnetics", + "alpha_Br": 0, + "is_BH_extrapolate": false, + "mur_lin": 2500.0 + }, + "name": "M400-50A", + "path": "M400-50A.json", + "struct": { + "Ex": 215000000000.0, + "Ey": 215000000000.0, + "Ez": 80000000000.0, + "Gxy": 0.0, + "Gxz": 2000000000.0, + "Gyz": 2000000000.0, + "__class__": "MatStructural", + "nu_xy": 0.3, + "nu_xz": 0.03, + "nu_yz": 0.03, + "rho": 7650.0 + } + }, + "notch": [], + "ring_mat": { + "HT": { + "Cp": 381.0, + "__class__": "MatHT", + "alpha": 0, + "lambda_x": 385.0, + "lambda_y": 385.0, + "lambda_z": 385.0 + }, + "__class__": "Material", + "desc": "COPPER WINDING", + "eco": { + "__class__": "MatEconomical", + "cost_unit": 60.0, + "unit_name": "$" + }, + "elec": { + "__class__": "MatElectrical", + "alpha": 0.003, + "epsr": 1, + "rho": 2.2e-08 + }, + "is_isotropic": true, + "mag": null, + "name": "Copper1", + "path": "Copper1.json", + "struct": { + "Ex": 115000000000.0, + "Ey": 115000000000.0, + "Ez": 115000000000.0, + "Gxy": null, + "Gxz": null, + "Gyz": null, + "__class__": "MatStructural", + "nu_xy": null, + "nu_xz": null, + "nu_yz": null, + "rho": 8900.0 + } + }, + "skew": null, + "slot": { + "H0": 0.003, + "H1": 0, + "H1_is_rad": false, + "H2": 0.02, + "W0": 0.003, + "W1": 0.013, + "W2": 0.01, + "Zs": 28, + "__class__": "SlotW21", + "is_bore": true, + "wedge_mat": null + }, + "winding": { + "Lewout": 0.017, + "Nlayer": 1, + "Npcp": 1, + "Nslot_shift_wind": 0, + "Ntcoil": 1, + "__class__": "WindingSC", + "coil_pitch": 0, + "conductor": { + "Hbar": 0.02, + "Wbar": 0.01, + "Wins": 0, + "__class__": "CondType21", + "cond_mat": { + "HT": { + "Cp": 381.0, + "__class__": "MatHT", + "alpha": 1.6e-05, + "lambda_x": 385.0, + "lambda_y": 385.0, + "lambda_z": 385.0 + }, + "__class__": "Material", + "desc": "COPPER WINDING", + "eco": { + "__class__": "MatEconomical", + "cost_unit": 60.0, + "unit_name": "$" + }, + "elec": { + "__class__": "MatElectrical", + "alpha": 0.003, + "epsr": 1, + "rho": 2.2e-08 + }, + "is_isotropic": true, + "mag": null, + "name": "Copper1", + "path": "Copper1.json", + "struct": { + "Ex": 115000000000.0, + "Ey": 115000000000.0, + "Ez": 115000000000.0, + "Gxy": null, + "Gxz": null, + "Gyz": null, + "__class__": "MatStructural", + "nu_xy": null, + "nu_xz": null, + "nu_yz": null, + "rho": 8900.0 + } + }, + "ins_mat": { + "HT": { + "Cp": 1, + "__class__": "MatHT", + "alpha": 0, + "lambda_x": 1, + "lambda_y": 1, + "lambda_z": 1 + }, + "__class__": "Material", + "desc": "Material description", + "eco": { + "__class__": "MatEconomical", + "cost_unit": 0.127, + "unit_name": "$" + }, + "elec": { + "__class__": "MatElectrical", + "alpha": 0, + "epsr": 1, + "rho": 0 + }, + "is_isotropic": false, + "mag": { + "BH_curve": { + "__class__": "ImportMatrix", + "is_transpose": false + }, + "Brm20": 0, + "LossData": { + "__class__": "ImportMatrix", + "is_transpose": false + }, + "ModelBH": { + "Bmax": 2.31, + "Hmax": null, + "__class__": "ModelBH", + "delta": 100 + }, + "Wlam": 0, + "__class__": "MatMagnetics", + "alpha_Br": 0, + "is_BH_extrapolate": false, + "mur_lin": 1 + }, + "name": "Material", + "path": "", + "struct": { + "Ex": 215000000000.0, + "Ey": 215000000000.0, + "Ez": 80000000000, + "Gxy": 0, + "Gxz": 2000000000, + "Gyz": 2000000000, + "__class__": "MatStructural", + "nu_xy": 0.3, + "nu_xz": 0.03, + "nu_yz": 0.03, + "rho": 7650 + } + } + }, + "end_winding": { + "Lew_enforced": 0, + "__class__": "EndWinding" + }, + "is_aper_a": null, + "is_change_layer": false, + "is_permute_B_C": false, + "is_reverse_layer": false, + "is_reverse_wind": false, + "p": 3, + "per_a": null, + "qs": 28, + "type_connection": 0, + "wind_mat": null + }, + "yoke": null + }, + "shaft": { + "Drsh": 0.09, + "Lshaft": 0.442, + "__class__": "Shaft", + "mat_type": { + "HT": { + "Cp": 1, + "__class__": "MatHT", + "alpha": 0, + "lambda_x": 1, + "lambda_y": 1, + "lambda_z": 1 + }, + "__class__": "Material", + "desc": "Lamination M400-50A", + "eco": { + "__class__": "MatEconomical", + "cost_unit": 0.127, + "unit_name": "$" + }, + "elec": { + "__class__": "MatElectrical", + "alpha": 0, + "epsr": 1, + "rho": 4.6e-07 + }, + "is_isotropic": false, + "mag": { + "BH_curve": { + "__class__": "ImportMatrixVal", + "is_transpose": false, + "value": [ + [ + 0.0, + 0.0 + ], + [ + 100.0, + 0.5 + ], + [ + 150.0, + 0.7 + ], + [ + 180.0, + 0.8 + ], + [ + 200.0, + 0.9 + ], + [ + 250.0, + 1.0 + ], + [ + 300.0, + 1.05 + ], + [ + 350.0, + 1.1 + ], + [ + 450.0, + 1.15 + ], + [ + 550.0, + 1.2 + ], + [ + 650.0, + 1.225 + ], + [ + 750.0, + 1.25 + ], + [ + 850.0, + 1.275 + ], + [ + 950.0, + 1.3 + ], + [ + 1100.0, + 1.325 + ], + [ + 1250.0, + 1.35 + ], + [ + 1400.0, + 1.375 + ], + [ + 1550.0, + 1.4 + ], + [ + 1700.0, + 1.425 + ], + [ + 1900.0, + 1.45 + ], + [ + 2150.0, + 1.475 + ], + [ + 2450.0, + 1.5 + ], + [ + 2750.0, + 1.525 + ], + [ + 3150.0, + 1.55 + ], + [ + 3600.0, + 1.575 + ], + [ + 4100.0, + 1.6 + ], + [ + 4700.0, + 1.625 + ], + [ + 5250.0, + 1.65 + ], + [ + 6000.0, + 1.675 + ], + [ + 6700.0, + 1.7 + ], + [ + 7500.0, + 1.725 + ], + [ + 8650.0, + 1.75 + ], + [ + 9500.0, + 1.775 + ], + [ + 10750.0, + 1.8 + ], + [ + 14500.0, + 1.85 + ], + [ + 19500.0, + 1.9 + ], + [ + 25000.0, + 1.95 + ], + [ + 33000.0, + 2.0 + ], + [ + 44000.0, + 2.05 + ], + [ + 57000.0, + 2.1 + ], + [ + 74000.0, + 2.15 + ], + [ + 96000.0, + 2.2 + ], + [ + 130000.0, + 2.25 + ], + [ + 170000.0, + 2.3 + ] + ] + }, + "Brm20": 0, + "LossData": { + "__class__": "ImportMatrix", + "is_transpose": false + }, + "ModelBH": { + "Bmax": 2.31, + "Hmax": null, + "__class__": "ModelBH", + "delta": 100 + }, + "Wlam": 0.0005, + "__class__": "MatMagnetics", + "alpha_Br": 0, + "is_BH_extrapolate": false, + "mur_lin": 2500.0 + }, + "name": "M400-50A", + "path": "M400-50A.json", + "struct": { + "Ex": 215000000000.0, + "Ey": 215000000000.0, + "Ez": 80000000000.0, + "Gxy": 0.0, + "Gxz": 2000000000.0, + "Gyz": 2000000000.0, + "__class__": "MatStructural", + "nu_xy": 0.3, + "nu_xz": 0.03, + "nu_yz": 0.03, + "rho": 7650.0 + } + } + }, + "stator": { + "Kf1": 0.95, + "Ksfill": null, + "L1": 0.35, + "Nrvd": 0, + "Rext": 0.2, + "Rint": 0.1325, + "Wrvd": 0, + "__class__": "LamSlotWind", + "axial_vent": [], + "bore": null, + "is_internal": false, + "is_stator": true, + "mat_type": { + "HT": { + "Cp": 1, + "__class__": "MatHT", + "alpha": 0, + "lambda_x": 1, + "lambda_y": 1, + "lambda_z": 1 + }, + "__class__": "Material", + "desc": "Lamination M400-50A", + "eco": { + "__class__": "MatEconomical", + "cost_unit": 0.127, + "unit_name": "$" + }, + "elec": { + "__class__": "MatElectrical", + "alpha": 0, + "epsr": 1, + "rho": 4.6e-07 + }, + "is_isotropic": false, + "mag": { + "BH_curve": { + "__class__": "ImportMatrixVal", + "is_transpose": false, + "value": [ + [ + 0.0, + 0.0 + ], + [ + 100.0, + 0.5 + ], + [ + 150.0, + 0.7 + ], + [ + 180.0, + 0.8 + ], + [ + 200.0, + 0.9 + ], + [ + 250.0, + 1.0 + ], + [ + 300.0, + 1.05 + ], + [ + 350.0, + 1.1 + ], + [ + 450.0, + 1.15 + ], + [ + 550.0, + 1.2 + ], + [ + 650.0, + 1.225 + ], + [ + 750.0, + 1.25 + ], + [ + 850.0, + 1.275 + ], + [ + 950.0, + 1.3 + ], + [ + 1100.0, + 1.325 + ], + [ + 1250.0, + 1.35 + ], + [ + 1400.0, + 1.375 + ], + [ + 1550.0, + 1.4 + ], + [ + 1700.0, + 1.425 + ], + [ + 1900.0, + 1.45 + ], + [ + 2150.0, + 1.475 + ], + [ + 2450.0, + 1.5 + ], + [ + 2750.0, + 1.525 + ], + [ + 3150.0, + 1.55 + ], + [ + 3600.0, + 1.575 + ], + [ + 4100.0, + 1.6 + ], + [ + 4700.0, + 1.625 + ], + [ + 5250.0, + 1.65 + ], + [ + 6000.0, + 1.675 + ], + [ + 6700.0, + 1.7 + ], + [ + 7500.0, + 1.725 + ], + [ + 8650.0, + 1.75 + ], + [ + 9500.0, + 1.775 + ], + [ + 10750.0, + 1.8 + ], + [ + 14500.0, + 1.85 + ], + [ + 19500.0, + 1.9 + ], + [ + 25000.0, + 1.95 + ], + [ + 33000.0, + 2.0 + ], + [ + 44000.0, + 2.05 + ], + [ + 57000.0, + 2.1 + ], + [ + 74000.0, + 2.15 + ], + [ + 96000.0, + 2.2 + ], + [ + 130000.0, + 2.25 + ], + [ + 170000.0, + 2.3 + ] + ] + }, + "Brm20": 0, + "LossData": { + "__class__": "ImportMatrix", + "is_transpose": false + }, + "ModelBH": { + "Bmax": 2.31, + "Hmax": null, + "__class__": "ModelBH", + "delta": 100 + }, + "Wlam": 0.0005, + "__class__": "MatMagnetics", + "alpha_Br": 0, + "is_BH_extrapolate": false, + "mur_lin": 2500.0 + }, + "name": "M400-50A", + "path": "M400-50A.json", + "struct": { + "Ex": 215000000000.0, + "Ey": 215000000000.0, + "Ez": 80000000000.0, + "Gxy": 0.0, + "Gxz": 2000000000.0, + "Gyz": 2000000000.0, + "__class__": "MatStructural", + "nu_xy": 0.3, + "nu_xz": 0.03, + "nu_yz": 0.03, + "rho": 7650.0 + } + }, + "notch": [], + "skew": null, + "slot": { + "H0": 0.001, + "H1": 0.0015, + "H1_is_rad": false, + "H2": 0.03, + "W0": 0.012, + "W1": 0.014, + "W2": 0.012, + "Zs": 36, + "__class__": "SlotW10", + "is_bore": true, + "wedge_mat": null + }, + "winding": { + "Lewout": 0.1541392, + "Nlayer": 2, + "Npcp": 2, + "Nslot_shift_wind": 0, + "Ntcoil": 7, + "__class__": "Winding", + "coil_pitch": 5, + "conductor": { + "Hwire": 0.002, + "Nwppc_rad": 1, + "Nwppc_tan": 1, + "Wins_coil": 0, + "Wins_wire": 0, + "Wwire": 0.01, + "__class__": "CondType11", + "alpha_ew": 58, + "cond_mat": { + "HT": { + "Cp": 381.0, + "__class__": "MatHT", + "alpha": 1.6e-05, + "lambda_x": 385.0, + "lambda_y": 385.0, + "lambda_z": 385.0 + }, + "__class__": "Material", + "desc": "COPPER WINDING", + "eco": { + "__class__": "MatEconomical", + "cost_unit": 60.0, + "unit_name": "$" + }, + "elec": { + "__class__": "MatElectrical", + "alpha": 0.00393, + "epsr": 1, + "rho": 1.73e-08 + }, + "is_isotropic": true, + "mag": null, + "name": "Copper1", + "path": "Copper1.json", + "struct": { + "Ex": 115000000000.0, + "Ey": 115000000000.0, + "Ez": 115000000000.0, + "Gxy": null, + "Gxz": null, + "Gyz": null, + "__class__": "MatStructural", + "nu_xy": null, + "nu_xz": null, + "nu_yz": null, + "rho": 8900.0 + } + }, + "ins_mat": { + "HT": { + "Cp": 671.0, + "__class__": "MatHT", + "alpha": 0, + "lambda_x": 0.2, + "lambda_y": 0.2, + "lambda_z": 0.2 + }, + "__class__": "Material", + "desc": "INSULATOR1", + "eco": { + "__class__": "MatEconomical", + "cost_unit": null, + "unit_name": "$" + }, + "elec": { + "__class__": "MatElectrical", + "alpha": 0, + "epsr": 1, + "rho": 0 + }, + "is_isotropic": true, + "mag": null, + "name": "Insulator1", + "path": "Insulator1.json", + "struct": { + "Ex": null, + "Ey": null, + "Ez": null, + "Gxy": null, + "Gxz": null, + "Gyz": null, + "__class__": "MatStructural", + "nu_xy": null, + "nu_xz": null, + "nu_yz": null, + "rho": 1200.0 + } + }, + "type_winding_shape": 0 + }, + "end_winding": { + "Lew_enforced": 0, + "__class__": "EndWinding" + }, + "is_aper_a": null, + "is_change_layer": false, + "is_permute_B_C": false, + "is_reverse_layer": false, + "is_reverse_wind": false, + "p": 3, + "per_a": null, + "qs": 3, + "type_connection": 0, + "wind_mat": null + }, + "yoke": null + }, + "type_machine": 1 + }, + "mag": null, + "name": "OptiConstraint_OptiDesignVar_old", + "path_result": null, + "postproc_list": [], + "struct": null, + "var_simu": null + } + }, + "selector": null, + "size_pop": 20, + "toolbox": null, + "xoutput": { + "__class__": "XOutput", + "elec": { + "Arms": null, + "Erms": null, + "Ir": null, + "Is": null, + "Jrms": null, + "OP": null, + "PWM": null, + "P_in": null, + "P_out": null, + "Pem_av": null, + "Pj_losses": null, + "Tem_av": null, + "Us": null, + "__class__": "OutElec", + "axes_dict": null, + "current_dir": null, + "eec": null, + "internal": null, + "logger_name": "pyleecan.Electrical", + "phase_dir": null + }, + "force": { + "AGSF": null, + "Rag": null, + "__class__": "OutForce", + "axes_dict": null, + "logger_name": "Pyleecan.Force", + "meshsolution": null + }, + "geo": { + "Lgap": null, + "Rgap_mec": null, + "Wgap_mag": null, + "Wgap_mec": null, + "__class__": "OutGeo", + "angle_rotor_initial": null, + "axes_dict": null, + "is_antiper_a": null, + "is_antiper_t_R": null, + "is_antiper_t_S": null, + "logger_name": "Pyleecan.OutGeo", + "per_a": null, + "per_t_R": null, + "per_t_S": null, + "rot_dir": null, + "rotor": null, + "stator": null + }, + "logger_name": "Pyleecan.Output", + "loss": { + "Pjoule": null, + "Pmagnet": null, + "Pprox": null, + "Protor": null, + "Pstator": null, + "__class__": "OutLoss", + "axes_dict": null, + "coeff_dict": {}, + "logger_name": "Pyleecan.Loss", + "loss_index": {}, + "loss_list": null, + "meshsol_list": null + }, + "mag": { + "B": null, + "Pem_av": null, + "Phi_wind": null, + "Phi_wind_slice": null, + "Phi_wind_stator": null, + "Rag": null, + "Slice": null, + "Tem": null, + "Tem_av": null, + "Tem_norm": 0.001, + "Tem_rip_norm": null, + "Tem_rip_pp": null, + "Tem_slice": null, + "__class__": "OutMag", + "axes_dict": null, + "emf": null, + "internal": null, + "logger_name": "Pyleecan.Magnetics", + "meshsolution": { + "__class__": "MeshSolution", + "dimension": 2, + "group": null, + "is_same_mesh": true, + "label": "", + "mesh": [], + "path": null, + "solution": [] + } + }, + "nb_simu": 0, + "output_list": [], + "paramexplorer_list": [], + "path_result": "", + "post": { + "__class__": "OutPost", + "legend_name": "", + "line_color": "" + }, + "simu": { + "__class__": "Simulation", + "desc": "", + "index": null, + "input": { + "Na_tot": 2048, + "Nrev": null, + "Nt_tot": 2048, + "OP": null, + "__class__": "Input", + "angle": null, + "t_final": null, + "time": null + }, + "layer": null, + "layer_log_warn": null, + "logger_name": "Pyleecan.Simulation", + "machine": { + "__class__": "Machine", + "desc": "", + "frame": { + "Lfra": 0.35, + "Rext": 0.2, + "Rint": 0.2, + "__class__": "Frame", + "mat_type": { + "HT": { + "Cp": 1, + "__class__": "MatHT", + "alpha": 0, + "lambda_x": 1, + "lambda_y": 1, + "lambda_z": 1 + }, + "__class__": "Material", + "desc": "Material description", + "eco": { + "__class__": "MatEconomical", + "cost_unit": 0.127, + "unit_name": "$" + }, + "elec": { + "__class__": "MatElectrical", + "alpha": 0, + "epsr": 1, + "rho": 0 + }, + "is_isotropic": false, + "mag": { + "BH_curve": { + "__class__": "ImportMatrix", + "is_transpose": false + }, + "Brm20": 0, + "LossData": { + "__class__": "ImportMatrix", + "is_transpose": false + }, + "ModelBH": { + "Bmax": 2.31, + "Hmax": null, + "__class__": "ModelBH", + "delta": 100 + }, + "Wlam": 0, + "__class__": "MatMagnetics", + "alpha_Br": 0, + "is_BH_extrapolate": false, + "mur_lin": 1 + }, + "name": "Material", + "path": "", + "struct": { + "Ex": 215000000000.0, + "Ey": 215000000000.0, + "Ez": 80000000000, + "Gxy": 0, + "Gxz": 2000000000, + "Gyz": 2000000000, + "__class__": "MatStructural", + "nu_xy": 0.3, + "nu_xz": 0.03, + "nu_yz": 0.03, + "rho": 7650 + } + } + }, + "logger_name": "Pyleecan.Machine", + "name": "default_machine", + "shaft": { + "Drsh": 0.045, + "Lshaft": 0.442, + "__class__": "Shaft", + "mat_type": { + "HT": { + "Cp": 1, + "__class__": "MatHT", + "alpha": 0, + "lambda_x": 1, + "lambda_y": 1, + "lambda_z": 1 + }, + "__class__": "Material", + "desc": "Material description", + "eco": { + "__class__": "MatEconomical", + "cost_unit": 0.127, + "unit_name": "$" + }, + "elec": { + "__class__": "MatElectrical", + "alpha": 0, + "epsr": 1, + "rho": 0 + }, + "is_isotropic": false, + "mag": { + "BH_curve": { + "__class__": "ImportMatrix", + "is_transpose": false + }, + "Brm20": 0, + "LossData": { + "__class__": "ImportMatrix", + "is_transpose": false + }, + "ModelBH": { + "Bmax": 2.31, + "Hmax": null, + "__class__": "ModelBH", + "delta": 100 + }, + "Wlam": 0, + "__class__": "MatMagnetics", + "alpha_Br": 0, + "is_BH_extrapolate": false, + "mur_lin": 1 + }, + "name": "Material", + "path": "", + "struct": { + "Ex": 215000000000.0, + "Ey": 215000000000.0, + "Ez": 80000000000, + "Gxy": 0, + "Gxz": 2000000000, + "Gyz": 2000000000, + "__class__": "MatStructural", + "nu_xy": 0.3, + "nu_xz": 0.03, + "nu_yz": 0.03, + "rho": 7650 + } + } + }, + "type_machine": 1 + }, + "name": "", + "path_result": null, + "postproc_list": [], + "var_simu": null + }, + "struct": { + "FEA_dict": null, + "__class__": "OutStruct", + "axes_dict": null, + "logger_name": "Pyleecan.Structural", + "meshsolution": { + "__class__": "MeshSolution", + "dimension": 2, + "group": null, + "is_same_mesh": true, + "label": "", + "mesh": [], + "path": null, + "solution": [] + } + }, + "xoutput_dict": {}, + "xoutput_ref": null, + "xoutput_ref_index": null + } +} \ No newline at end of file diff --git a/Tests/Data/Retrocompatibility/Optimisation/OptiConstraint_and_OptiDesignVar_ref.json b/Tests/Data/Retrocompatibility/Optimisation/OptiConstraint_and_OptiDesignVar_ref.json new file mode 100644 index 000000000..ed039c4a8 --- /dev/null +++ b/Tests/Data/Retrocompatibility/Optimisation/OptiConstraint_and_OptiDesignVar_ref.json @@ -0,0 +1,1561 @@ +{ + "__class__": "OptiGenAlgNsga2Deap", + "__save_date__": "2022_12_07 14h10min43s ", + "__version__": "pyleecan_1.4.1", + "crossover": null, + "is_keep_all_output": false, + "logger_name": "Pyleecan.OptiSolver", + "mutator": null, + "nb_gen": 40, + "p_cross": 0.9, + "p_mutate": 0.5, + "problem": { + "__class__": "OptiProblem", + "constraint": [ + { + "__class__": "OptiConstraint", + "error_keeper": null, + "keeper": "lambda output: (output.simu.machine.rotor.slot.H0 - 5) ** 2 + output.simu.machine.stator.slot.H0 ** 2", + "name": "first", + "physic": null, + "result": [], + "result_ref": null, + "symbol": "", + "type_const": "<=", + "unit": "", + "value": 25 + }, + { + "__class__": "OptiConstraint", + "error_keeper": null, + "keeper": "lambda output: (output.simu.machine.rotor.slot.H0 - 5) ** 2 + (output.simu.machine.stator.slot.H0 + 3) ** 2", + "name": "second", + "physic": null, + "result": [], + "result_ref": null, + "symbol": "", + "type_const": ">=", + "unit": "", + "value": 7.7 + } + ], + "datakeeper_list": [], + "design_var": [ + { + "__class__": "OptiDesignVarInterval", + "get_value": "lambda space: random.uniform(*space)", + "getter": null, + "name": "Rotor slot height", + "setter": "lambda simu, val: setattr(eval('simu.machine.rotor.slot'), 'H0', val)", + "space": [ + 0, + 5 + ], + "symbol": "RH0", + "unit": "" + }, + { + "__class__": "OptiDesignVarInterval", + "get_value": "lambda space: random.uniform(*space)", + "getter": null, + "name": "Stator slot height", + "setter": "lambda simu, val: setattr(eval('simu.machine.stator.slot'), 'H0', val)", + "space": [ + 0, + 3 + ], + "symbol": "SH0", + "unit": "" + } + ], + "eval_func": null, + "obj_func": [ + { + "__class__": "OptiObjective", + "error_keeper": null, + "keeper": "lambda output: output.mag.Tem_av", + "name": "Maximization of the torque average", + "physic": null, + "result": [], + "result_ref": null, + "symbol": "obj1", + "unit": "N.m" + }, + { + "__class__": "OptiObjective", + "error_keeper": null, + "keeper": "lambda output: output.mag.Tem_rip_norm", + "name": "Minimization of the torque ripple", + "physic": null, + "result": [], + "result_ref": null, + "symbol": "obj2", + "unit": "N.m" + } + ], + "preprocessing": null, + "simu": { + "__class__": "Simu1", + "desc": "", + "elec": null, + "force": null, + "index": null, + "input": { + "Na_tot": 2048, + "Nrev": null, + "Nt_tot": 2048, + "OP": null, + "__class__": "Input", + "angle": null, + "t_final": null, + "time": null + }, + "layer": null, + "layer_log_warn": null, + "logger_name": "Pyleecan.Simulation", + "loss": null, + "machine": { + "__class__": "MachineSCIM", + "desc": "", + "frame": null, + "logger_name": "Pyleecan.Machine", + "name": "Railway_Traction", + "rotor": { + "Hscr": 0.02, + "Kf1": 0.95, + "Ksfill": null, + "L1": 0.35, + "Lscr": 0.015, + "Nrvd": 0, + "Rext": 0.131, + "Rint": 0.045, + "Wrvd": 0, + "__class__": "LamSquirrelCage", + "axial_vent": [ + { + "Alpha0": 0.3927, + "D0": 0.02, + "H0": 0.07, + "Zh": 8, + "__class__": "VentilationCirc", + "magnetization_dict_offset": null, + "mat_void": { + "HT": { + "Cp": 1, + "__class__": "MatHT", + "alpha": 0, + "lambda_x": 1, + "lambda_y": 1, + "lambda_z": 1 + }, + "__class__": "Material", + "desc": "Material description", + "eco": { + "__class__": "MatEconomical", + "cost_unit": 0.127, + "unit_name": "$" + }, + "elec": { + "__class__": "MatElectrical", + "alpha": 0, + "epsr": 1, + "rho": 0 + }, + "is_isotropic": false, + "mag": { + "BH_curve": { + "__class__": "ImportMatrix", + "is_transpose": false + }, + "Brm20": 0, + "LossData": { + "__class__": "ImportMatrix", + "is_transpose": false + }, + "ModelBH": { + "Bmax": 2.31, + "Hmax": null, + "__class__": "ModelBH", + "delta": 100 + }, + "Wlam": 0, + "__class__": "MatMagnetics", + "alpha_Br": 0, + "is_BH_extrapolate": false, + "mur_lin": 1 + }, + "name": "Material", + "path": "", + "struct": { + "Ex": 215000000000.0, + "Ey": 215000000000.0, + "Ez": 80000000000, + "Gxy": 0, + "Gxz": 2000000000, + "Gyz": 2000000000, + "__class__": "MatStructural", + "nu_xy": 0.3, + "nu_xz": 0.03, + "nu_yz": 0.03, + "rho": 7650 + } + } + } + ], + "bore": null, + "is_internal": true, + "is_stator": false, + "mat_type": { + "HT": { + "Cp": 1, + "__class__": "MatHT", + "alpha": 0, + "lambda_x": 1, + "lambda_y": 1, + "lambda_z": 1 + }, + "__class__": "Material", + "desc": "Lamination M400-50A", + "eco": { + "__class__": "MatEconomical", + "cost_unit": 0.127, + "unit_name": "$" + }, + "elec": { + "__class__": "MatElectrical", + "alpha": 0, + "epsr": 1, + "rho": 4.6e-07 + }, + "is_isotropic": false, + "mag": { + "BH_curve": { + "__class__": "ImportMatrixVal", + "is_transpose": false, + "value": [ + [ + 0.0, + 0.0 + ], + [ + 100.0, + 0.5 + ], + [ + 150.0, + 0.7 + ], + [ + 180.0, + 0.8 + ], + [ + 200.0, + 0.9 + ], + [ + 250.0, + 1.0 + ], + [ + 300.0, + 1.05 + ], + [ + 350.0, + 1.1 + ], + [ + 450.0, + 1.15 + ], + [ + 550.0, + 1.2 + ], + [ + 650.0, + 1.225 + ], + [ + 750.0, + 1.25 + ], + [ + 850.0, + 1.275 + ], + [ + 950.0, + 1.3 + ], + [ + 1100.0, + 1.325 + ], + [ + 1250.0, + 1.35 + ], + [ + 1400.0, + 1.375 + ], + [ + 1550.0, + 1.4 + ], + [ + 1700.0, + 1.425 + ], + [ + 1900.0, + 1.45 + ], + [ + 2150.0, + 1.475 + ], + [ + 2450.0, + 1.5 + ], + [ + 2750.0, + 1.525 + ], + [ + 3150.0, + 1.55 + ], + [ + 3600.0, + 1.575 + ], + [ + 4100.0, + 1.6 + ], + [ + 4700.0, + 1.625 + ], + [ + 5250.0, + 1.65 + ], + [ + 6000.0, + 1.675 + ], + [ + 6700.0, + 1.7 + ], + [ + 7500.0, + 1.725 + ], + [ + 8650.0, + 1.75 + ], + [ + 9500.0, + 1.775 + ], + [ + 10750.0, + 1.8 + ], + [ + 14500.0, + 1.85 + ], + [ + 19500.0, + 1.9 + ], + [ + 25000.0, + 1.95 + ], + [ + 33000.0, + 2.0 + ], + [ + 44000.0, + 2.05 + ], + [ + 57000.0, + 2.1 + ], + [ + 74000.0, + 2.15 + ], + [ + 96000.0, + 2.2 + ], + [ + 130000.0, + 2.25 + ], + [ + 170000.0, + 2.3 + ] + ] + }, + "Brm20": 0, + "LossData": { + "__class__": "ImportMatrix", + "is_transpose": false + }, + "ModelBH": { + "Bmax": 2.31, + "Hmax": null, + "__class__": "ModelBH", + "delta": 100 + }, + "Wlam": 0.0005, + "__class__": "MatMagnetics", + "alpha_Br": 0, + "is_BH_extrapolate": false, + "mur_lin": 2500.0 + }, + "name": "M400-50A", + "path": "M400-50A.json", + "struct": { + "Ex": 215000000000.0, + "Ey": 215000000000.0, + "Ez": 80000000000.0, + "Gxy": 0.0, + "Gxz": 2000000000.0, + "Gyz": 2000000000.0, + "__class__": "MatStructural", + "nu_xy": 0.3, + "nu_xz": 0.03, + "nu_yz": 0.03, + "rho": 7650.0 + } + }, + "notch": [], + "ring_mat": { + "HT": { + "Cp": 381.0, + "__class__": "MatHT", + "alpha": 0, + "lambda_x": 385.0, + "lambda_y": 385.0, + "lambda_z": 385.0 + }, + "__class__": "Material", + "desc": "COPPER WINDING", + "eco": { + "__class__": "MatEconomical", + "cost_unit": 60.0, + "unit_name": "$" + }, + "elec": { + "__class__": "MatElectrical", + "alpha": 0.003, + "epsr": 1, + "rho": 2.2e-08 + }, + "is_isotropic": true, + "mag": null, + "name": "Copper1", + "path": "Copper1.json", + "struct": { + "Ex": 115000000000.0, + "Ey": 115000000000.0, + "Ez": 115000000000.0, + "Gxy": null, + "Gxz": null, + "Gyz": null, + "__class__": "MatStructural", + "nu_xy": null, + "nu_xz": null, + "nu_yz": null, + "rho": 8900.0 + } + }, + "skew": null, + "slot": { + "H0": 0.003, + "H1": 0, + "H1_is_rad": false, + "H2": 0.02, + "W0": 0.003, + "W1": 0.013, + "W2": 0.01, + "Zs": 28, + "__class__": "SlotW21", + "is_bore": true, + "wedge_mat": null + }, + "winding": { + "Lewout": 0.017, + "Nlayer": 1, + "Npcp": 1, + "Nslot_shift_wind": 0, + "Ntcoil": 1, + "__class__": "WindingSC", + "coil_pitch": 0, + "conductor": { + "Hbar": 0.02, + "Wbar": 0.01, + "Wins": 0, + "__class__": "CondType21", + "cond_mat": { + "HT": { + "Cp": 381.0, + "__class__": "MatHT", + "alpha": 1.6e-05, + "lambda_x": 385.0, + "lambda_y": 385.0, + "lambda_z": 385.0 + }, + "__class__": "Material", + "desc": "COPPER WINDING", + "eco": { + "__class__": "MatEconomical", + "cost_unit": 60.0, + "unit_name": "$" + }, + "elec": { + "__class__": "MatElectrical", + "alpha": 0.003, + "epsr": 1, + "rho": 2.2e-08 + }, + "is_isotropic": true, + "mag": null, + "name": "Copper1", + "path": "Copper1.json", + "struct": { + "Ex": 115000000000.0, + "Ey": 115000000000.0, + "Ez": 115000000000.0, + "Gxy": null, + "Gxz": null, + "Gyz": null, + "__class__": "MatStructural", + "nu_xy": null, + "nu_xz": null, + "nu_yz": null, + "rho": 8900.0 + } + }, + "ins_mat": { + "HT": { + "Cp": 1, + "__class__": "MatHT", + "alpha": 0, + "lambda_x": 1, + "lambda_y": 1, + "lambda_z": 1 + }, + "__class__": "Material", + "desc": "Material description", + "eco": { + "__class__": "MatEconomical", + "cost_unit": 0.127, + "unit_name": "$" + }, + "elec": { + "__class__": "MatElectrical", + "alpha": 0, + "epsr": 1, + "rho": 0 + }, + "is_isotropic": false, + "mag": { + "BH_curve": { + "__class__": "ImportMatrix", + "is_transpose": false + }, + "Brm20": 0, + "LossData": { + "__class__": "ImportMatrix", + "is_transpose": false + }, + "ModelBH": { + "Bmax": 2.31, + "Hmax": null, + "__class__": "ModelBH", + "delta": 100 + }, + "Wlam": 0, + "__class__": "MatMagnetics", + "alpha_Br": 0, + "is_BH_extrapolate": false, + "mur_lin": 1 + }, + "name": "Material", + "path": "", + "struct": { + "Ex": 215000000000.0, + "Ey": 215000000000.0, + "Ez": 80000000000, + "Gxy": 0, + "Gxz": 2000000000, + "Gyz": 2000000000, + "__class__": "MatStructural", + "nu_xy": 0.3, + "nu_xz": 0.03, + "nu_yz": 0.03, + "rho": 7650 + } + } + }, + "end_winding": { + "Lew_enforced": 0, + "__class__": "EndWinding" + }, + "is_aper_a": null, + "is_change_layer": false, + "is_permute_B_C": false, + "is_reverse_layer": false, + "is_reverse_wind": false, + "p": 3, + "per_a": null, + "qs": 28, + "type_connection": 0, + "wind_mat": null + }, + "yoke": null + }, + "shaft": { + "Drsh": 0.09, + "Lshaft": 0.442, + "__class__": "Shaft", + "mat_type": { + "HT": { + "Cp": 1, + "__class__": "MatHT", + "alpha": 0, + "lambda_x": 1, + "lambda_y": 1, + "lambda_z": 1 + }, + "__class__": "Material", + "desc": "Lamination M400-50A", + "eco": { + "__class__": "MatEconomical", + "cost_unit": 0.127, + "unit_name": "$" + }, + "elec": { + "__class__": "MatElectrical", + "alpha": 0, + "epsr": 1, + "rho": 4.6e-07 + }, + "is_isotropic": false, + "mag": { + "BH_curve": { + "__class__": "ImportMatrixVal", + "is_transpose": false, + "value": [ + [ + 0.0, + 0.0 + ], + [ + 100.0, + 0.5 + ], + [ + 150.0, + 0.7 + ], + [ + 180.0, + 0.8 + ], + [ + 200.0, + 0.9 + ], + [ + 250.0, + 1.0 + ], + [ + 300.0, + 1.05 + ], + [ + 350.0, + 1.1 + ], + [ + 450.0, + 1.15 + ], + [ + 550.0, + 1.2 + ], + [ + 650.0, + 1.225 + ], + [ + 750.0, + 1.25 + ], + [ + 850.0, + 1.275 + ], + [ + 950.0, + 1.3 + ], + [ + 1100.0, + 1.325 + ], + [ + 1250.0, + 1.35 + ], + [ + 1400.0, + 1.375 + ], + [ + 1550.0, + 1.4 + ], + [ + 1700.0, + 1.425 + ], + [ + 1900.0, + 1.45 + ], + [ + 2150.0, + 1.475 + ], + [ + 2450.0, + 1.5 + ], + [ + 2750.0, + 1.525 + ], + [ + 3150.0, + 1.55 + ], + [ + 3600.0, + 1.575 + ], + [ + 4100.0, + 1.6 + ], + [ + 4700.0, + 1.625 + ], + [ + 5250.0, + 1.65 + ], + [ + 6000.0, + 1.675 + ], + [ + 6700.0, + 1.7 + ], + [ + 7500.0, + 1.725 + ], + [ + 8650.0, + 1.75 + ], + [ + 9500.0, + 1.775 + ], + [ + 10750.0, + 1.8 + ], + [ + 14500.0, + 1.85 + ], + [ + 19500.0, + 1.9 + ], + [ + 25000.0, + 1.95 + ], + [ + 33000.0, + 2.0 + ], + [ + 44000.0, + 2.05 + ], + [ + 57000.0, + 2.1 + ], + [ + 74000.0, + 2.15 + ], + [ + 96000.0, + 2.2 + ], + [ + 130000.0, + 2.25 + ], + [ + 170000.0, + 2.3 + ] + ] + }, + "Brm20": 0, + "LossData": { + "__class__": "ImportMatrix", + "is_transpose": false + }, + "ModelBH": { + "Bmax": 2.31, + "Hmax": null, + "__class__": "ModelBH", + "delta": 100 + }, + "Wlam": 0.0005, + "__class__": "MatMagnetics", + "alpha_Br": 0, + "is_BH_extrapolate": false, + "mur_lin": 2500.0 + }, + "name": "M400-50A", + "path": "M400-50A.json", + "struct": { + "Ex": 215000000000.0, + "Ey": 215000000000.0, + "Ez": 80000000000.0, + "Gxy": 0.0, + "Gxz": 2000000000.0, + "Gyz": 2000000000.0, + "__class__": "MatStructural", + "nu_xy": 0.3, + "nu_xz": 0.03, + "nu_yz": 0.03, + "rho": 7650.0 + } + } + }, + "stator": { + "Kf1": 0.95, + "Ksfill": null, + "L1": 0.35, + "Nrvd": 0, + "Rext": 0.2, + "Rint": 0.1325, + "Wrvd": 0, + "__class__": "LamSlotWind", + "axial_vent": [], + "bore": null, + "is_internal": false, + "is_stator": true, + "mat_type": { + "HT": { + "Cp": 1, + "__class__": "MatHT", + "alpha": 0, + "lambda_x": 1, + "lambda_y": 1, + "lambda_z": 1 + }, + "__class__": "Material", + "desc": "Lamination M400-50A", + "eco": { + "__class__": "MatEconomical", + "cost_unit": 0.127, + "unit_name": "$" + }, + "elec": { + "__class__": "MatElectrical", + "alpha": 0, + "epsr": 1, + "rho": 4.6e-07 + }, + "is_isotropic": false, + "mag": { + "BH_curve": { + "__class__": "ImportMatrixVal", + "is_transpose": false, + "value": [ + [ + 0.0, + 0.0 + ], + [ + 100.0, + 0.5 + ], + [ + 150.0, + 0.7 + ], + [ + 180.0, + 0.8 + ], + [ + 200.0, + 0.9 + ], + [ + 250.0, + 1.0 + ], + [ + 300.0, + 1.05 + ], + [ + 350.0, + 1.1 + ], + [ + 450.0, + 1.15 + ], + [ + 550.0, + 1.2 + ], + [ + 650.0, + 1.225 + ], + [ + 750.0, + 1.25 + ], + [ + 850.0, + 1.275 + ], + [ + 950.0, + 1.3 + ], + [ + 1100.0, + 1.325 + ], + [ + 1250.0, + 1.35 + ], + [ + 1400.0, + 1.375 + ], + [ + 1550.0, + 1.4 + ], + [ + 1700.0, + 1.425 + ], + [ + 1900.0, + 1.45 + ], + [ + 2150.0, + 1.475 + ], + [ + 2450.0, + 1.5 + ], + [ + 2750.0, + 1.525 + ], + [ + 3150.0, + 1.55 + ], + [ + 3600.0, + 1.575 + ], + [ + 4100.0, + 1.6 + ], + [ + 4700.0, + 1.625 + ], + [ + 5250.0, + 1.65 + ], + [ + 6000.0, + 1.675 + ], + [ + 6700.0, + 1.7 + ], + [ + 7500.0, + 1.725 + ], + [ + 8650.0, + 1.75 + ], + [ + 9500.0, + 1.775 + ], + [ + 10750.0, + 1.8 + ], + [ + 14500.0, + 1.85 + ], + [ + 19500.0, + 1.9 + ], + [ + 25000.0, + 1.95 + ], + [ + 33000.0, + 2.0 + ], + [ + 44000.0, + 2.05 + ], + [ + 57000.0, + 2.1 + ], + [ + 74000.0, + 2.15 + ], + [ + 96000.0, + 2.2 + ], + [ + 130000.0, + 2.25 + ], + [ + 170000.0, + 2.3 + ] + ] + }, + "Brm20": 0, + "LossData": { + "__class__": "ImportMatrix", + "is_transpose": false + }, + "ModelBH": { + "Bmax": 2.31, + "Hmax": null, + "__class__": "ModelBH", + "delta": 100 + }, + "Wlam": 0.0005, + "__class__": "MatMagnetics", + "alpha_Br": 0, + "is_BH_extrapolate": false, + "mur_lin": 2500.0 + }, + "name": "M400-50A", + "path": "M400-50A.json", + "struct": { + "Ex": 215000000000.0, + "Ey": 215000000000.0, + "Ez": 80000000000.0, + "Gxy": 0.0, + "Gxz": 2000000000.0, + "Gyz": 2000000000.0, + "__class__": "MatStructural", + "nu_xy": 0.3, + "nu_xz": 0.03, + "nu_yz": 0.03, + "rho": 7650.0 + } + }, + "notch": [], + "skew": null, + "slot": { + "H0": 0.001, + "H1": 0.0015, + "H1_is_rad": false, + "H2": 0.03, + "W0": 0.012, + "W1": 0.014, + "W2": 0.012, + "Zs": 36, + "__class__": "SlotW10", + "is_bore": true, + "wedge_mat": null + }, + "winding": { + "Lewout": 0.1541392, + "Nlayer": 2, + "Npcp": 2, + "Nslot_shift_wind": 0, + "Ntcoil": 7, + "__class__": "Winding", + "coil_pitch": 5, + "conductor": { + "Hwire": 0.002, + "Nwppc_rad": 1, + "Nwppc_tan": 1, + "Wins_coil": 0, + "Wins_wire": 0, + "Wwire": 0.01, + "__class__": "CondType11", + "alpha_ew": 58, + "cond_mat": { + "HT": { + "Cp": 381.0, + "__class__": "MatHT", + "alpha": 1.6e-05, + "lambda_x": 385.0, + "lambda_y": 385.0, + "lambda_z": 385.0 + }, + "__class__": "Material", + "desc": "COPPER WINDING", + "eco": { + "__class__": "MatEconomical", + "cost_unit": 60.0, + "unit_name": "$" + }, + "elec": { + "__class__": "MatElectrical", + "alpha": 0.00393, + "epsr": 1, + "rho": 1.73e-08 + }, + "is_isotropic": true, + "mag": null, + "name": "Copper1", + "path": "Copper1.json", + "struct": { + "Ex": 115000000000.0, + "Ey": 115000000000.0, + "Ez": 115000000000.0, + "Gxy": null, + "Gxz": null, + "Gyz": null, + "__class__": "MatStructural", + "nu_xy": null, + "nu_xz": null, + "nu_yz": null, + "rho": 8900.0 + } + }, + "ins_mat": { + "HT": { + "Cp": 671.0, + "__class__": "MatHT", + "alpha": 0, + "lambda_x": 0.2, + "lambda_y": 0.2, + "lambda_z": 0.2 + }, + "__class__": "Material", + "desc": "INSULATOR1", + "eco": { + "__class__": "MatEconomical", + "cost_unit": null, + "unit_name": "$" + }, + "elec": { + "__class__": "MatElectrical", + "alpha": 0, + "epsr": 1, + "rho": 0 + }, + "is_isotropic": true, + "mag": null, + "name": "Insulator1", + "path": "Insulator1.json", + "struct": { + "Ex": null, + "Ey": null, + "Ez": null, + "Gxy": null, + "Gxz": null, + "Gyz": null, + "__class__": "MatStructural", + "nu_xy": null, + "nu_xz": null, + "nu_yz": null, + "rho": 1200.0 + } + }, + "type_winding_shape": 0 + }, + "end_winding": { + "Lew_enforced": 0, + "__class__": "EndWinding" + }, + "is_aper_a": null, + "is_change_layer": false, + "is_permute_B_C": false, + "is_reverse_layer": false, + "is_reverse_wind": false, + "p": 3, + "per_a": null, + "qs": 3, + "type_connection": 0, + "wind_mat": null + }, + "yoke": null + }, + "type_machine": 1 + }, + "mag": null, + "name": "OptiConstraint_OptiDesignVar_old", + "path_result": null, + "postproc_list": [], + "struct": null, + "var_simu": null + } + }, + "selector": null, + "size_pop": 20, + "toolbox": null, + "xoutput": { + "__class__": "XOutput", + "elec": { + "Arms": null, + "Erms": null, + "Ir": null, + "Is": null, + "Jrms": null, + "OP": null, + "PWM": null, + "P_in": null, + "P_out": null, + "Pem_av": null, + "Pj_losses": null, + "Tem_av": null, + "Us": null, + "__class__": "OutElec", + "axes_dict": null, + "current_dir": null, + "eec": null, + "internal": null, + "logger_name": "pyleecan.Electrical", + "phase_dir": null + }, + "force": { + "AGSF": null, + "Rag": null, + "__class__": "OutForce", + "axes_dict": null, + "logger_name": "Pyleecan.Force", + "meshsolution": null + }, + "geo": { + "Lgap": null, + "Rgap_mec": null, + "Wgap_mag": null, + "Wgap_mec": null, + "__class__": "OutGeo", + "angle_rotor_initial": null, + "axes_dict": null, + "is_antiper_a": null, + "is_antiper_t_R": null, + "is_antiper_t_S": null, + "logger_name": "Pyleecan.OutGeo", + "per_a": null, + "per_t_R": null, + "per_t_S": null, + "rot_dir": null, + "rotor": null, + "stator": null + }, + "logger_name": "Pyleecan.Output", + "loss": { + "Pjoule": null, + "Pmagnet": null, + "Pprox": null, + "Protor": null, + "Pstator": null, + "__class__": "OutLoss", + "axes_dict": null, + "coeff_dict": {}, + "logger_name": "Pyleecan.Loss", + "loss_index": {}, + "loss_list": null, + "meshsol_list": null + }, + "mag": { + "B": null, + "Pem_av": null, + "Phi_wind": null, + "Phi_wind_slice": null, + "Phi_wind_stator": null, + "Rag": null, + "Slice": null, + "Tem": null, + "Tem_av": null, + "Tem_norm": 0.001, + "Tem_rip_norm": null, + "Tem_rip_pp": null, + "Tem_slice": null, + "__class__": "OutMag", + "axes_dict": null, + "emf": null, + "internal": null, + "logger_name": "Pyleecan.Magnetics", + "meshsolution": { + "__class__": "MeshSolution", + "dimension": 2, + "group": null, + "is_same_mesh": true, + "label": "", + "mesh": [], + "path": null, + "solution": [] + } + }, + "nb_simu": 0, + "output_list": [], + "paramexplorer_list": [], + "path_result": "", + "post": { + "__class__": "OutPost", + "legend_name": "", + "line_color": "" + }, + "simu": { + "__class__": "Simulation", + "desc": "", + "index": null, + "input": { + "Na_tot": 2048, + "Nrev": null, + "Nt_tot": 2048, + "OP": null, + "__class__": "Input", + "angle": null, + "t_final": null, + "time": null + }, + "layer": null, + "layer_log_warn": null, + "logger_name": "Pyleecan.Simulation", + "machine": { + "__class__": "Machine", + "desc": "", + "frame": { + "Lfra": 0.35, + "Rext": 0.2, + "Rint": 0.2, + "__class__": "Frame", + "mat_type": { + "HT": { + "Cp": 1, + "__class__": "MatHT", + "alpha": 0, + "lambda_x": 1, + "lambda_y": 1, + "lambda_z": 1 + }, + "__class__": "Material", + "desc": "Material description", + "eco": { + "__class__": "MatEconomical", + "cost_unit": 0.127, + "unit_name": "$" + }, + "elec": { + "__class__": "MatElectrical", + "alpha": 0, + "epsr": 1, + "rho": 0 + }, + "is_isotropic": false, + "mag": { + "BH_curve": { + "__class__": "ImportMatrix", + "is_transpose": false + }, + "Brm20": 0, + "LossData": { + "__class__": "ImportMatrix", + "is_transpose": false + }, + "ModelBH": { + "Bmax": 2.31, + "Hmax": null, + "__class__": "ModelBH", + "delta": 100 + }, + "Wlam": 0, + "__class__": "MatMagnetics", + "alpha_Br": 0, + "is_BH_extrapolate": false, + "mur_lin": 1 + }, + "name": "Material", + "path": "", + "struct": { + "Ex": 215000000000.0, + "Ey": 215000000000.0, + "Ez": 80000000000, + "Gxy": 0, + "Gxz": 2000000000, + "Gyz": 2000000000, + "__class__": "MatStructural", + "nu_xy": 0.3, + "nu_xz": 0.03, + "nu_yz": 0.03, + "rho": 7650 + } + } + }, + "logger_name": "Pyleecan.Machine", + "name": "default_machine", + "shaft": { + "Drsh": 0.045, + "Lshaft": 0.442, + "__class__": "Shaft", + "mat_type": { + "HT": { + "Cp": 1, + "__class__": "MatHT", + "alpha": 0, + "lambda_x": 1, + "lambda_y": 1, + "lambda_z": 1 + }, + "__class__": "Material", + "desc": "Material description", + "eco": { + "__class__": "MatEconomical", + "cost_unit": 0.127, + "unit_name": "$" + }, + "elec": { + "__class__": "MatElectrical", + "alpha": 0, + "epsr": 1, + "rho": 0 + }, + "is_isotropic": false, + "mag": { + "BH_curve": { + "__class__": "ImportMatrix", + "is_transpose": false + }, + "Brm20": 0, + "LossData": { + "__class__": "ImportMatrix", + "is_transpose": false + }, + "ModelBH": { + "Bmax": 2.31, + "Hmax": null, + "__class__": "ModelBH", + "delta": 100 + }, + "Wlam": 0, + "__class__": "MatMagnetics", + "alpha_Br": 0, + "is_BH_extrapolate": false, + "mur_lin": 1 + }, + "name": "Material", + "path": "", + "struct": { + "Ex": 215000000000.0, + "Ey": 215000000000.0, + "Ez": 80000000000, + "Gxy": 0, + "Gxz": 2000000000, + "Gyz": 2000000000, + "__class__": "MatStructural", + "nu_xy": 0.3, + "nu_xz": 0.03, + "nu_yz": 0.03, + "rho": 7650 + } + } + }, + "type_machine": 1 + }, + "name": "", + "path_result": null, + "postproc_list": [], + "var_simu": null + }, + "struct": { + "FEA_dict": null, + "__class__": "OutStruct", + "axes_dict": null, + "logger_name": "Pyleecan.Structural", + "meshsolution": { + "__class__": "MeshSolution", + "dimension": 2, + "group": null, + "is_same_mesh": true, + "label": "", + "mesh": [], + "path": null, + "solution": [] + } + }, + "xoutput_dict": {}, + "xoutput_ref": null, + "xoutput_ref_index": null + } +} \ No newline at end of file diff --git a/Tests/Data/Retrocompatibility/VarParam/VarParam_old.json b/Tests/Data/Retrocompatibility/VarParam/VarParam_old.json new file mode 100644 index 000000000..db5a341a5 --- /dev/null +++ b/Tests/Data/Retrocompatibility/VarParam/VarParam_old.json @@ -0,0 +1,43 @@ +{ + "__class__": "VarParam", + "__save_date__": "2022_12_07 13h49min51s ", + "__version__": "pyleecan_1.4.1", + "datakeeper_list": [ + { + "__class__": "DataKeeper", + "error_keeper": "lambda simu: np.nan", + "keeper": null, + "name": "Dummy result", + "physic": null, + "result": [], + "result_ref": null, + "symbol": "res", + "unit": "-" + } + ], + "desc": "", + "is_keep_all_output": true, + "is_reuse_LUT": false, + "is_reuse_femm_file": false, + "name": "", + "nb_simu": 0, + "paramexplorer_list": [ + { + "__class__": "ParamExplorerSet", + "getter": null, + "name": "Dummy variable", + "setter": null, + "symbol": "X", + "unit": "-", + "value": [ + 0, + 1 + ] + } + ], + "post_keeper_postproc_list": null, + "postproc_list": [], + "pre_keeper_postproc_list": null, + "stop_if_error": true, + "var_simu": null +} \ No newline at end of file diff --git a/Tests/Data/Retrocompatibility/VarParam/VarParam_ref.json b/Tests/Data/Retrocompatibility/VarParam/VarParam_ref.json new file mode 100644 index 000000000..36bd9b5ad --- /dev/null +++ b/Tests/Data/Retrocompatibility/VarParam/VarParam_ref.json @@ -0,0 +1,43 @@ +{ + "__class__": "VarParamSweep", + "__save_date__": "2022_12_07 14h03min33s ", + "__version__": "pyleecan_1.4.1", + "datakeeper_list": [ + { + "__class__": "DataKeeper", + "error_keeper": "lambda simu: np.nan", + "keeper": null, + "name": "Dummy result", + "physic": null, + "result": [], + "result_ref": null, + "symbol": "res", + "unit": "-" + } + ], + "desc": "", + "is_keep_all_output": true, + "is_reuse_LUT": false, + "is_reuse_femm_file": false, + "name": "", + "nb_simu": 0, + "paramexplorer_list": [ + { + "__class__": "ParamExplorerSet", + "getter": null, + "name": "Dummy variable", + "setter": null, + "symbol": "X", + "unit": "-", + "value": [ + 0, + 1 + ] + } + ], + "post_keeper_postproc_list": null, + "postproc_list": [], + "pre_keeper_postproc_list": null, + "stop_if_error": true, + "var_simu": null +} \ No newline at end of file diff --git a/Tests/Functions/test_retrocompatibility.py b/Tests/Functions/test_retrocompatibility.py index 7a07325a9..03628008f 100644 --- a/Tests/Functions/test_retrocompatibility.py +++ b/Tests/Functions/test_retrocompatibility.py @@ -50,6 +50,24 @@ } ) +# VarParam convertion (rename to VarParamSweep) +varparam_list = list() +varparam_list.append( + { + "ref": join(TEST_DATA_DIR, "Retrocompatibility", "VarParam", "VarParam_ref.json"), + "old": join(TEST_DATA_DIR, "Retrocompatibility", "VarParam", "VarParam_old.json"), + } +) + +# OptiConstraint & OptiDesignVar convertion +opti_list = list() +opti_list.append( + { + "ref": join(TEST_DATA_DIR, "Retrocompatibility", "Optimisation", "OptiConstraint_and_OptiDesignVar_ref.json"), + "old": join(TEST_DATA_DIR, "Retrocompatibility", "Optimisation", "OptiConstraint_and_OptiDesignVar_old.json"), + } +) + # 2: Winding convertion (star of slot) wind_list = list() # wind_list.append( # WindingSC + WindingDW2L @@ -165,6 +183,35 @@ def test_save_load_wind_retro(file_dict): ), msg +@pytest.mark.parametrize("file_dict", varparam_list) +def test_load_varparam(file_dict): + """Check that the VarParam into VarParamSweep convertion works""" + ref = load(file_dict["ref"]) + old = load(file_dict["old"]) + + # Check old file is converted to current version + msg = "Error for " + ref.name + ": VarParam is not converted into VarParamSweep" + assert ref.name == old.name, msg + + +@pytest.mark.parametrize("file_dict", opti_list) +def test_load_opti(file_dict): + """Check that the OptiConstraint & OptiDesignVar convertion works""" + ref = load(file_dict["ref"]) + old = load(file_dict["old"]) + + msg = "Error for OptiConstraint, get_variable is not converted into keeper" + for ii in range(len(old.problem.constraint)): + if hasattr(old.problem.constraint[ii], "keeper"): + assert old.problem.constraint[ii]._keeper_str == ref.problem.constraint[ii]._keeper_str + else: + assert False, msg + + msg = "Error for OptiDesignVar, not converted into OptiDesignVarInterval" + for ii, designvar in enumerate(old.problem.design_var): + assert isinstance(designvar, type(ref.problem.design_var[ii])), msg + + def test_before_version(): """Check that we can detect previous version""" assert is_before_version("1.2.3", "1.2.1") diff --git a/Tests/Validation/Optimization/test_opti_varopti.py b/Tests/Validation/Optimization/test_opti_varopti.py index b311ce269..2ecdbc7ac 100644 --- a/Tests/Validation/Optimization/test_opti_varopti.py +++ b/Tests/Validation/Optimization/test_opti_varopti.py @@ -43,8 +43,6 @@ def harm1(output): @pytest.mark.SCIM @pytest.mark.MagFEMM def test_opti_varopti(): - # Defining reference Output - # Definition of the enforced output of the electrical module # Import the machine from a script Toyota_Prius = load(join(DATA_DIR, "Machine", "Toyota_Prius.json")) Toyota_Prius.plot() diff --git a/pyleecan/Functions/Load/retrocompatibility.py b/pyleecan/Functions/Load/retrocompatibility.py index c35d161dd..8c63d3e09 100644 --- a/pyleecan/Functions/Load/retrocompatibility.py +++ b/pyleecan/Functions/Load/retrocompatibility.py @@ -59,6 +59,12 @@ def _search_and_update(obj_dict, parent=None, parent_index=None, update_dict=Non parent[parent_index] = convert_Winding(obj_dict) elif update_dict["Yoke_Notch"] and is_yoke_notch(obj_dict): move_yoke_notch(obj_dict) + elif update_dict["VarParam"] and is_VarParam_dict(obj_dict): + rename_varparam(obj_dict) + elif update_dict["OptiConstraint"] and is_OptiConstraint_dict(obj_dict): + parent[parent_index] = convert_opticonstraint(obj_dict) + elif update_dict["OptiDesignVar"] and is_OptiDesignVar_dict(obj_dict): + parent[parent_index] = convert_optidesignvar(obj_dict) else: # walk through the dict for key, value in obj_dict.items(): @@ -331,6 +337,101 @@ def convert_Winding(wind_dict): return Winding_class(init_dict=wind_dict_new) +###################### +# v 1.4.1 => 1.4.2 +# VarParam is now VarParamSweep +###################### +VARPARAM_VERSION = "1.4.2" + + +def is_VarParam_dict(obj_dict): + """Check if the object need to be updated for Winding""" + return ( + "__class__" in obj_dict.keys() + and obj_dict["__class__"] + in [ + "VarParam", + ] + ) + +def rename_varparam(varparam_dict): + """Update the old VarParam class to VarParamSweep""" + getLogger(GUI_LOG_NAME).info( + "Old machine version detected, Updating the VarParam object" + ) + # Copy dict to keep original version + varparam_dict_new = varparam_dict.copy() + # Instantiate object + VarParamSweep = import_class("pyleecan.Classes", "VarParamSweep") + return VarParamSweep(init_dict=varparam_dict_new) + + +###################### +# v 1.4.1 => 1.4.2 +# VarParam is now VarParamSweep +###################### +OptiConstraint_VERSION = "1.4.2" + + +def is_OptiConstraint_dict(obj_dict): + """Check if the object need to be updated for OptiConstraint""" + return ( + "__class__" in obj_dict.keys() + and obj_dict["__class__"] + in [ + "OptiConstraint", + ] + and "get_variable" in obj_dict.keys() + ) + +def convert_opticonstraint(opticonstraint_dict): + """Update the old OptiConstraint to the new one inherited from DataKeeper without get_variable""" + getLogger(GUI_LOG_NAME).info( + "Old machine version detected, Updating the OptiConstraint object" + ) + # Copy dict to keep original version + opticonstraint_dict_new = opticonstraint_dict.copy() + opticonstraint_dict_new["keeper"] = opticonstraint_dict_new["get_variable"] + del opticonstraint_dict_new["get_variable"] + # Instantiate object + OptiConstraint = import_class("pyleecan.Classes", "OptiConstraint") + return OptiConstraint(init_dict=opticonstraint_dict_new) + + +###################### +# v 1.4.1 => 1.4.2 +# VarParam is now VarParamSweep +###################### +OptiDesignVar_VERSION = "1.4.2" + + +def is_OptiDesignVar_dict(obj_dict): + """Check if the object need to be updated for OptiDesignVar""" + return ( + "__class__" in obj_dict.keys() + and obj_dict["__class__"] + in [ + "OptiDesignVar", + ] + ) + +def convert_optidesignvar(optidesignvar_dict): + """Update the old OptiDesignVar to the new ones OptiDesignVarSet & OptiDesignVarInterval""" + getLogger(GUI_LOG_NAME).info( + "Old machine version detected, Updating the OptiDesignVar object" + ) + # Copy dict to keep original version + optidesignvar_dict_new = optidesignvar_dict.copy() + + if optidesignvar_dict_new["type_var"] == "set": + del optidesignvar_dict_new["type_var"] + OptiDesignVarSet = import_class("pyleecan.Classes", "OptiDesignVarSet") + return OptiDesignVarSet(init_dict=optidesignvar_dict_new) + else: + del optidesignvar_dict_new["type_var"] + OptiDesignVarInterval = import_class("pyleecan.Classes", "OptiDesignVarInterval") + return OptiDesignVarInterval(init_dict=optidesignvar_dict_new) + def is_before_version(ref_version, check_version): """Check if a version str is before another version str @@ -385,10 +486,16 @@ def create_update_dict(file_version): update_dict["OP"] = True update_dict["OP_matrix"] = True update_dict["Yoke_Notch"] = True + update_dict["VarParam"] = True + update_dict["OptiConstraint"] = True + update_dict["OptiDesignVar"] = True else: update_dict["Winding"] = is_before_version(WIND_VERSION, file_version) update_dict["HoleUD"] = is_before_version(HoleUD_VERSION, file_version) update_dict["OP"] = is_before_version(OP_VERSION, file_version) update_dict["OP_matrix"] = is_before_version(OP_MAT_VERSION, file_version) update_dict["Yoke_Notch"] = is_before_version(Yoke_Notch_VERSION, file_version) + update_dict["VarParam"] = is_before_version(VARPARAM_VERSION, file_version) + update_dict["OptiConstraint"] = is_before_version(OptiConstraint_VERSION, file_version) + update_dict["OptiDesignVar"] = is_before_version(OptiDesignVar_VERSION, file_version) return update_dict diff --git a/setup.py b/setup.py index 985cc769d..90d70a0ce 100644 --- a/setup.py +++ b/setup.py @@ -23,7 +23,7 @@ # Release 1.1.0 : 1.1.0 # First post release of the release 1.1.0 : 1.1.0.post1 -PYLEECAN_VERSION = "1.4.1" +PYLEECAN_VERSION = "1.4.2" with open("README.md", "r") as fh: From 85bc9f16305a08407db13bf61602587e91cd5f2d Mon Sep 17 00:00:00 2001 From: BenjaminGabet Date: Fri, 9 Dec 2022 10:33:12 +0100 Subject: [PATCH 06/10] [NF] Modification of tuto --- Tutorials/tuto_MultiSim.ipynb | 16189 +--------------- Tutorials/tuto_Optimization.ipynb | 977 +- ...tuto_Optimization_Bayes_machine_SCIM.ipynb | 21 +- 3 files changed, 63 insertions(+), 17124 deletions(-) diff --git a/Tutorials/tuto_MultiSim.ipynb b/Tutorials/tuto_MultiSim.ipynb index 9e5675860..d6e19ef41 100644 --- a/Tutorials/tuto_MultiSim.ipynb +++ b/Tutorials/tuto_MultiSim.ipynb @@ -40,7 +40,7 @@ "# Classes Glossary\n", "This tutorials mainly uses the following classes:\n", "\n", - "- [VarParam](https://pyleecan.org/pyleecan.Classes.VarParam.html): Class to define a multisimulation by varying parameters\n", + "- [VarParamSweep](https://pyleecan.org/pyleecan.Classes.VarParamSweep.html): Class to define a multisimulation by varying parameters\n", "- [VarLoadCurrent](https://pyleecan.org/pyleecan.Classes.VarLoadCurrent.html): Class to define a multisimulation by varying operating point\n", "- [DataKeeper](https://pyleecan.org/pyleecan.Classes.DataKeeper.html): Class to select some data to keep from a multi-simulation\n", "- [ParamExplorerInterval](https://pyleecan.org/pyleecan.Classes.ParamExplorerInterval.html): Class to define a design variable (for parameter sweep) with value on an interval\n", @@ -54,7 +54,7 @@ "metadata": {}, "source": [ "# How to define a Parameter Sweep of a Variable speed simulation?\n", - "This tutorial explains how to use the objects VarParam and VarLoadCurrent to run Parameter Sweep of a Variable speed simulation by using the multi-simulation tools of pyleecan. This tutorial combines several advanced aspect of pyleecan, please read the following tutorials first:\n", + "This tutorial explains how to use the objects VarParamSweep and VarLoadCurrent to run Parameter Sweep of a Variable speed simulation by using the multi-simulation tools of pyleecan. This tutorial combines several advanced aspect of pyleecan, please read the following tutorials first:\n", "\n", "- \"[How to define a machine](https://pyleecan.org/tuto_Machine.html)\"\n", "- \"[How to define a simulation to call FEMM](https://pyleecan.org/tuto_Simulation_FEMM.html)\".\n", @@ -64,7 +64,7 @@ "The multi-simulation tools of Pyleecan can be combined to create multi-simulation of multi-simulation. This tutorial will build step by step (or layer by layer) a parameter sweep to study the impact of the stator slot opening of the Toyota Prius on the variable speed torque. \n", "\n", "## Machine and Reference Simulation definition\n", - "The first step is to define the reference simulation aka the original machine without any modifications from the VarParam (Parameter sweep object) nor the VarLoadCurrent (Variable speed object). This tutorial uses the usual machine Toyota Prius (2004) and simulation from the previous tutorials:" + "The first step is to define the reference simulation aka the original machine without any modifications from the VarParamSweep (Parameter sweep object) nor the VarLoadCurrent (Variable speed object). This tutorial uses the usual machine Toyota Prius (2004) and simulation from the previous tutorials:" ] }, { @@ -76,955 +76,7 @@ "outputs": [ { "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "/* global mpl */\n", - "window.mpl = {};\n", - "\n", - "mpl.get_websocket_type = function () {\n", - " if (typeof WebSocket !== 'undefined') {\n", - " return WebSocket;\n", - " } else if (typeof MozWebSocket !== 'undefined') {\n", - " return MozWebSocket;\n", - " } else {\n", - " alert(\n", - " 'Your browser does not have WebSocket support. ' +\n", - " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", - " 'Firefox 4 and 5 are also supported but you ' +\n", - " 'have to enable WebSockets in about:config.'\n", - " );\n", - " }\n", - "};\n", - "\n", - "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", - " this.id = figure_id;\n", - "\n", - " this.ws = websocket;\n", - "\n", - " this.supports_binary = this.ws.binaryType !== undefined;\n", - "\n", - " if (!this.supports_binary) {\n", - " var warnings = document.getElementById('mpl-warnings');\n", - " if (warnings) {\n", - " warnings.style.display = 'block';\n", - " warnings.textContent =\n", - " 'This browser does not support binary websocket messages. ' +\n", - " 'Performance may be slow.';\n", - " }\n", - " }\n", - "\n", - " this.imageObj = new Image();\n", - "\n", - " this.context = undefined;\n", - " this.message = undefined;\n", - " this.canvas = undefined;\n", - " this.rubberband_canvas = undefined;\n", - " this.rubberband_context = undefined;\n", - " this.format_dropdown = undefined;\n", - "\n", - " this.image_mode = 'full';\n", - "\n", - " this.root = document.createElement('div');\n", - " this.root.setAttribute('style', 'display: inline-block');\n", - " this._root_extra_style(this.root);\n", - "\n", - " parent_element.appendChild(this.root);\n", - "\n", - " this._init_header(this);\n", - " this._init_canvas(this);\n", - " this._init_toolbar(this);\n", - "\n", - " var fig = this;\n", - "\n", - " this.waiting = false;\n", - "\n", - " this.ws.onopen = function () {\n", - " fig.send_message('supports_binary', { value: fig.supports_binary });\n", - " fig.send_message('send_image_mode', {});\n", - " if (fig.ratio !== 1) {\n", - " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", - " }\n", - " fig.send_message('refresh', {});\n", - " };\n", - "\n", - " this.imageObj.onload = function () {\n", - " if (fig.image_mode === 'full') {\n", - " // Full images could contain transparency (where diff images\n", - " // almost always do), so we need to clear the canvas so that\n", - " // there is no ghosting.\n", - " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", - " }\n", - " fig.context.drawImage(fig.imageObj, 0, 0);\n", - " };\n", - "\n", - " this.imageObj.onunload = function () {\n", - " fig.ws.close();\n", - " };\n", - "\n", - " this.ws.onmessage = this._make_on_message_function(this);\n", - "\n", - " this.ondownload = ondownload;\n", - "};\n", - "\n", - "mpl.figure.prototype._init_header = function () {\n", - " var titlebar = document.createElement('div');\n", - " titlebar.classList =\n", - " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", - " var titletext = document.createElement('div');\n", - " titletext.classList = 'ui-dialog-title';\n", - " titletext.setAttribute(\n", - " 'style',\n", - " 'width: 100%; text-align: center; padding: 3px;'\n", - " );\n", - " titlebar.appendChild(titletext);\n", - " this.root.appendChild(titlebar);\n", - " this.header = titletext;\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._init_canvas = function () {\n", - " var fig = this;\n", - "\n", - " var canvas_div = (this.canvas_div = document.createElement('div'));\n", - " canvas_div.setAttribute(\n", - " 'style',\n", - " 'border: 1px solid #ddd;' +\n", - " 'box-sizing: content-box;' +\n", - " 'clear: both;' +\n", - " 'min-height: 1px;' +\n", - " 'min-width: 1px;' +\n", - " 'outline: 0;' +\n", - " 'overflow: hidden;' +\n", - " 'position: relative;' +\n", - " 'resize: both;'\n", - " );\n", - "\n", - " function on_keyboard_event_closure(name) {\n", - " return function (event) {\n", - " return fig.key_event(event, name);\n", - " };\n", - " }\n", - "\n", - " canvas_div.addEventListener(\n", - " 'keydown',\n", - " on_keyboard_event_closure('key_press')\n", - " );\n", - " canvas_div.addEventListener(\n", - " 'keyup',\n", - " on_keyboard_event_closure('key_release')\n", - " );\n", - "\n", - " this._canvas_extra_style(canvas_div);\n", - " this.root.appendChild(canvas_div);\n", - "\n", - " var canvas = (this.canvas = document.createElement('canvas'));\n", - " canvas.classList.add('mpl-canvas');\n", - " canvas.setAttribute('style', 'box-sizing: content-box;');\n", - "\n", - " this.context = canvas.getContext('2d');\n", - "\n", - " var backingStore =\n", - " this.context.backingStorePixelRatio ||\n", - " this.context.webkitBackingStorePixelRatio ||\n", - " this.context.mozBackingStorePixelRatio ||\n", - " this.context.msBackingStorePixelRatio ||\n", - " this.context.oBackingStorePixelRatio ||\n", - " this.context.backingStorePixelRatio ||\n", - " 1;\n", - "\n", - " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", - "\n", - " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", - " 'canvas'\n", - " ));\n", - " rubberband_canvas.setAttribute(\n", - " 'style',\n", - " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", - " );\n", - "\n", - " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", - " if (this.ResizeObserver === undefined) {\n", - " if (window.ResizeObserver !== undefined) {\n", - " this.ResizeObserver = window.ResizeObserver;\n", - " } else {\n", - " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", - " this.ResizeObserver = obs.ResizeObserver;\n", - " }\n", - " }\n", - "\n", - " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", - " var nentries = entries.length;\n", - " for (var i = 0; i < nentries; i++) {\n", - " var entry = entries[i];\n", - " var width, height;\n", - " if (entry.contentBoxSize) {\n", - " if (entry.contentBoxSize instanceof Array) {\n", - " // Chrome 84 implements new version of spec.\n", - " width = entry.contentBoxSize[0].inlineSize;\n", - " height = entry.contentBoxSize[0].blockSize;\n", - " } else {\n", - " // Firefox implements old version of spec.\n", - " width = entry.contentBoxSize.inlineSize;\n", - " height = entry.contentBoxSize.blockSize;\n", - " }\n", - " } else {\n", - " // Chrome <84 implements even older version of spec.\n", - " width = entry.contentRect.width;\n", - " height = entry.contentRect.height;\n", - " }\n", - "\n", - " // Keep the size of the canvas and rubber band canvas in sync with\n", - " // the canvas container.\n", - " if (entry.devicePixelContentBoxSize) {\n", - " // Chrome 84 implements new version of spec.\n", - " canvas.setAttribute(\n", - " 'width',\n", - " entry.devicePixelContentBoxSize[0].inlineSize\n", - " );\n", - " canvas.setAttribute(\n", - " 'height',\n", - " entry.devicePixelContentBoxSize[0].blockSize\n", - " );\n", - " } else {\n", - " canvas.setAttribute('width', width * fig.ratio);\n", - " canvas.setAttribute('height', height * fig.ratio);\n", - " }\n", - " canvas.setAttribute(\n", - " 'style',\n", - " 'width: ' + width + 'px; height: ' + height + 'px;'\n", - " );\n", - "\n", - " rubberband_canvas.setAttribute('width', width);\n", - " rubberband_canvas.setAttribute('height', height);\n", - "\n", - " // And update the size in Python. We ignore the initial 0/0 size\n", - " // that occurs as the element is placed into the DOM, which should\n", - " // otherwise not happen due to the minimum size styling.\n", - " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", - " fig.request_resize(width, height);\n", - " }\n", - " }\n", - " });\n", - " this.resizeObserverInstance.observe(canvas_div);\n", - "\n", - " function on_mouse_event_closure(name) {\n", - " return function (event) {\n", - " return fig.mouse_event(event, name);\n", - " };\n", - " }\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mousedown',\n", - " on_mouse_event_closure('button_press')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseup',\n", - " on_mouse_event_closure('button_release')\n", - " );\n", - " // Throttle sequential mouse events to 1 every 20ms.\n", - " rubberband_canvas.addEventListener(\n", - " 'mousemove',\n", - " on_mouse_event_closure('motion_notify')\n", - " );\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseenter',\n", - " on_mouse_event_closure('figure_enter')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseleave',\n", - " on_mouse_event_closure('figure_leave')\n", - " );\n", - "\n", - " canvas_div.addEventListener('wheel', function (event) {\n", - " if (event.deltaY < 0) {\n", - " event.step = 1;\n", - " } else {\n", - " event.step = -1;\n", - " }\n", - " on_mouse_event_closure('scroll')(event);\n", - " });\n", - "\n", - " canvas_div.appendChild(canvas);\n", - " canvas_div.appendChild(rubberband_canvas);\n", - "\n", - " this.rubberband_context = rubberband_canvas.getContext('2d');\n", - " this.rubberband_context.strokeStyle = '#000000';\n", - "\n", - " this._resize_canvas = function (width, height, forward) {\n", - " if (forward) {\n", - " canvas_div.style.width = width + 'px';\n", - " canvas_div.style.height = height + 'px';\n", - " }\n", - " };\n", - "\n", - " // Disable right mouse context menu.\n", - " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", - " event.preventDefault();\n", - " return false;\n", - " });\n", - "\n", - " function set_focus() {\n", - " canvas.focus();\n", - " canvas_div.focus();\n", - " }\n", - "\n", - " window.setTimeout(set_focus, 100);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'mpl-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " continue;\n", - " }\n", - "\n", - " var button = (fig.buttons[name] = document.createElement('button'));\n", - " button.classList = 'mpl-widget';\n", - " button.setAttribute('role', 'button');\n", - " button.setAttribute('aria-disabled', 'false');\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - "\n", - " var icon_img = document.createElement('img');\n", - " icon_img.src = '_images/' + image + '.png';\n", - " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", - " icon_img.alt = tooltip;\n", - " button.appendChild(icon_img);\n", - "\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " var fmt_picker = document.createElement('select');\n", - " fmt_picker.classList = 'mpl-widget';\n", - " toolbar.appendChild(fmt_picker);\n", - " this.format_dropdown = fmt_picker;\n", - "\n", - " for (var ind in mpl.extensions) {\n", - " var fmt = mpl.extensions[ind];\n", - " var option = document.createElement('option');\n", - " option.selected = fmt === mpl.default_extension;\n", - " option.innerHTML = fmt;\n", - " fmt_picker.appendChild(option);\n", - " }\n", - "\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "};\n", - "\n", - "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", - " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", - " // which will in turn request a refresh of the image.\n", - " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", - "};\n", - "\n", - "mpl.figure.prototype.send_message = function (type, properties) {\n", - " properties['type'] = type;\n", - " properties['figure_id'] = this.id;\n", - " this.ws.send(JSON.stringify(properties));\n", - "};\n", - "\n", - "mpl.figure.prototype.send_draw_message = function () {\n", - " if (!this.waiting) {\n", - " this.waiting = true;\n", - " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " var format_dropdown = fig.format_dropdown;\n", - " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", - " fig.ondownload(fig, format);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", - " var size = msg['size'];\n", - " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", - " fig._resize_canvas(size[0], size[1], msg['forward']);\n", - " fig.send_message('refresh', {});\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", - " var x0 = msg['x0'] / fig.ratio;\n", - " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", - " var x1 = msg['x1'] / fig.ratio;\n", - " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", - " x0 = Math.floor(x0) + 0.5;\n", - " y0 = Math.floor(y0) + 0.5;\n", - " x1 = Math.floor(x1) + 0.5;\n", - " y1 = Math.floor(y1) + 0.5;\n", - " var min_x = Math.min(x0, x1);\n", - " var min_y = Math.min(y0, y1);\n", - " var width = Math.abs(x1 - x0);\n", - " var height = Math.abs(y1 - y0);\n", - "\n", - " fig.rubberband_context.clearRect(\n", - " 0,\n", - " 0,\n", - " fig.canvas.width / fig.ratio,\n", - " fig.canvas.height / fig.ratio\n", - " );\n", - "\n", - " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", - " // Updates the figure title.\n", - " fig.header.textContent = msg['label'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", - " var cursor = msg['cursor'];\n", - " switch (cursor) {\n", - " case 0:\n", - " cursor = 'pointer';\n", - " break;\n", - " case 1:\n", - " cursor = 'default';\n", - " break;\n", - " case 2:\n", - " cursor = 'crosshair';\n", - " break;\n", - " case 3:\n", - " cursor = 'move';\n", - " break;\n", - " }\n", - " fig.rubberband_canvas.style.cursor = cursor;\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_message = function (fig, msg) {\n", - " fig.message.textContent = msg['message'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", - " // Request the server to send over a new figure.\n", - " fig.send_draw_message();\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", - " fig.image_mode = msg['mode'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", - " for (var key in msg) {\n", - " if (!(key in fig.buttons)) {\n", - " continue;\n", - " }\n", - " fig.buttons[key].disabled = !msg[key];\n", - " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", - " if (msg['mode'] === 'PAN') {\n", - " fig.buttons['Pan'].classList.add('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " } else if (msg['mode'] === 'ZOOM') {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.add('active');\n", - " } else {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Called whenever the canvas gets updated.\n", - " this.send_message('ack', {});\n", - "};\n", - "\n", - "// A function to construct a web socket function for onmessage handling.\n", - "// Called in the figure constructor.\n", - "mpl.figure.prototype._make_on_message_function = function (fig) {\n", - " return function socket_on_message(evt) {\n", - " if (evt.data instanceof Blob) {\n", - " /* FIXME: We get \"Resource interpreted as Image but\n", - " * transferred with MIME type text/plain:\" errors on\n", - " * Chrome. But how to set the MIME type? It doesn't seem\n", - " * to be part of the websocket stream */\n", - " evt.data.type = 'image/png';\n", - "\n", - " /* Free the memory for the previous frames */\n", - " if (fig.imageObj.src) {\n", - " (window.URL || window.webkitURL).revokeObjectURL(\n", - " fig.imageObj.src\n", - " );\n", - " }\n", - "\n", - " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", - " evt.data\n", - " );\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " } else if (\n", - " typeof evt.data === 'string' &&\n", - " evt.data.slice(0, 21) === 'data:image/png;base64'\n", - " ) {\n", - " fig.imageObj.src = evt.data;\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " }\n", - "\n", - " var msg = JSON.parse(evt.data);\n", - " var msg_type = msg['type'];\n", - "\n", - " // Call the \"handle_{type}\" callback, which takes\n", - " // the figure and JSON message as its only arguments.\n", - " try {\n", - " var callback = fig['handle_' + msg_type];\n", - " } catch (e) {\n", - " console.log(\n", - " \"No handler for the '\" + msg_type + \"' message type: \",\n", - " msg\n", - " );\n", - " return;\n", - " }\n", - "\n", - " if (callback) {\n", - " try {\n", - " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", - " callback(fig, msg);\n", - " } catch (e) {\n", - " console.log(\n", - " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", - " e,\n", - " e.stack,\n", - " msg\n", - " );\n", - " }\n", - " }\n", - " };\n", - "};\n", - "\n", - "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", - "mpl.findpos = function (e) {\n", - " //this section is from http://www.quirksmode.org/js/events_properties.html\n", - " var targ;\n", - " if (!e) {\n", - " e = window.event;\n", - " }\n", - " if (e.target) {\n", - " targ = e.target;\n", - " } else if (e.srcElement) {\n", - " targ = e.srcElement;\n", - " }\n", - " if (targ.nodeType === 3) {\n", - " // defeat Safari bug\n", - " targ = targ.parentNode;\n", - " }\n", - "\n", - " // pageX,Y are the mouse positions relative to the document\n", - " var boundingRect = targ.getBoundingClientRect();\n", - " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", - " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", - "\n", - " return { x: x, y: y };\n", - "};\n", - "\n", - "/*\n", - " * return a copy of an object with only non-object keys\n", - " * we need this to avoid circular references\n", - " * http://stackoverflow.com/a/24161582/3208463\n", - " */\n", - "function simpleKeys(original) {\n", - " return Object.keys(original).reduce(function (obj, key) {\n", - " if (typeof original[key] !== 'object') {\n", - " obj[key] = original[key];\n", - " }\n", - " return obj;\n", - " }, {});\n", - "}\n", - "\n", - "mpl.figure.prototype.mouse_event = function (event, name) {\n", - " var canvas_pos = mpl.findpos(event);\n", - "\n", - " if (name === 'button_press') {\n", - " this.canvas.focus();\n", - " this.canvas_div.focus();\n", - " }\n", - "\n", - " var x = canvas_pos.x * this.ratio;\n", - " var y = canvas_pos.y * this.ratio;\n", - "\n", - " this.send_message(name, {\n", - " x: x,\n", - " y: y,\n", - " button: event.button,\n", - " step: event.step,\n", - " guiEvent: simpleKeys(event),\n", - " });\n", - "\n", - " /* This prevents the web browser from automatically changing to\n", - " * the text insertion cursor when the button is pressed. We want\n", - " * to control all of the cursor setting manually through the\n", - " * 'cursor' event from matplotlib */\n", - " event.preventDefault();\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", - " // Handle any extra behaviour associated with a key event\n", - "};\n", - "\n", - "mpl.figure.prototype.key_event = function (event, name) {\n", - " // Prevent repeat events\n", - " if (name === 'key_press') {\n", - " if (event.which === this._key) {\n", - " return;\n", - " } else {\n", - " this._key = event.which;\n", - " }\n", - " }\n", - " if (name === 'key_release') {\n", - " this._key = null;\n", - " }\n", - "\n", - " var value = '';\n", - " if (event.ctrlKey && event.which !== 17) {\n", - " value += 'ctrl+';\n", - " }\n", - " if (event.altKey && event.which !== 18) {\n", - " value += 'alt+';\n", - " }\n", - " if (event.shiftKey && event.which !== 16) {\n", - " value += 'shift+';\n", - " }\n", - "\n", - " value += 'k';\n", - " value += event.which.toString();\n", - "\n", - " this._key_event_extra(event, name);\n", - "\n", - " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", - " if (name === 'download') {\n", - " this.handle_save(this, null);\n", - " } else {\n", - " this.send_message('toolbar_button', { name: name });\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", - " this.message.textContent = tooltip;\n", - "};\n", - "\n", - "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", - "// prettier-ignore\n", - "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", - "\n", - "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", - "\n", - "mpl.default_extension = \"png\";/* global mpl */\n", - "\n", - "var comm_websocket_adapter = function (comm) {\n", - " // Create a \"websocket\"-like object which calls the given IPython comm\n", - " // object with the appropriate methods. Currently this is a non binary\n", - " // socket, so there is still some room for performance tuning.\n", - " var ws = {};\n", - "\n", - " ws.close = function () {\n", - " comm.close();\n", - " };\n", - " ws.send = function (m) {\n", - " //console.log('sending', m);\n", - " comm.send(m);\n", - " };\n", - " // Register the callback with on_msg.\n", - " comm.on_msg(function (msg) {\n", - " //console.log('receiving', msg['content']['data'], msg);\n", - " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", - " ws.onmessage(msg['content']['data']);\n", - " });\n", - " return ws;\n", - "};\n", - "\n", - "mpl.mpl_figure_comm = function (comm, msg) {\n", - " // This is the function which gets called when the mpl process\n", - " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", - "\n", - " var id = msg.content.data.id;\n", - " // Get hold of the div created by the display call when the Comm\n", - " // socket was opened in Python.\n", - " var element = document.getElementById(id);\n", - " var ws_proxy = comm_websocket_adapter(comm);\n", - "\n", - " function ondownload(figure, _format) {\n", - " window.open(figure.canvas.toDataURL());\n", - " }\n", - "\n", - " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", - "\n", - " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", - " // web socket which is closed, not our websocket->open comm proxy.\n", - " ws_proxy.onopen();\n", - "\n", - " fig.parent_element = element;\n", - " fig.cell_info = mpl.find_output_cell(\"
\");\n", - " if (!fig.cell_info) {\n", - " console.error('Failed to find cell for figure', id, fig);\n", - " return;\n", - " }\n", - " fig.cell_info[0].output_area.element.on(\n", - " 'cleared',\n", - " { fig: fig },\n", - " fig._remove_fig_handler\n", - " );\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_close = function (fig, msg) {\n", - " var width = fig.canvas.width / fig.ratio;\n", - " fig.cell_info[0].output_area.element.off(\n", - " 'cleared',\n", - " fig._remove_fig_handler\n", - " );\n", - " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", - "\n", - " // Update the output cell to use the data from the current canvas.\n", - " fig.push_to_output();\n", - " var dataURL = fig.canvas.toDataURL();\n", - " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", - " // the notebook keyboard shortcuts fail.\n", - " IPython.keyboard_manager.enable();\n", - " fig.parent_element.innerHTML =\n", - " '';\n", - " fig.close_ws(fig, msg);\n", - "};\n", - "\n", - "mpl.figure.prototype.close_ws = function (fig, msg) {\n", - " fig.send_message('closing', msg);\n", - " // fig.ws.close()\n", - "};\n", - "\n", - "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", - " // Turn the data on the canvas into data in the output cell.\n", - " var width = this.canvas.width / this.ratio;\n", - " var dataURL = this.canvas.toDataURL();\n", - " this.cell_info[1]['text/html'] =\n", - " '';\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Tell IPython that the notebook contents must change.\n", - " IPython.notebook.set_dirty(true);\n", - " this.send_message('ack', {});\n", - " var fig = this;\n", - " // Wait a second, then push the new image to the DOM so\n", - " // that it is saved nicely (might be nice to debounce this).\n", - " setTimeout(function () {\n", - " fig.push_to_output();\n", - " }, 1000);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'btn-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " var button;\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " continue;\n", - " }\n", - "\n", - " button = fig.buttons[name] = document.createElement('button');\n", - " button.classList = 'btn btn-default';\n", - " button.href = '#';\n", - " button.title = name;\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " // Add the status bar.\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message pull-right';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "\n", - " // Add the close button to the window.\n", - " var buttongrp = document.createElement('div');\n", - " buttongrp.classList = 'btn-group inline pull-right';\n", - " button = document.createElement('button');\n", - " button.classList = 'btn btn-mini btn-primary';\n", - " button.href = '#';\n", - " button.title = 'Stop Interaction';\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', function (_evt) {\n", - " fig.handle_close(fig, {});\n", - " });\n", - " button.addEventListener(\n", - " 'mouseover',\n", - " on_mouseover_closure('Stop Interaction')\n", - " );\n", - " buttongrp.appendChild(button);\n", - " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", - " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", - "};\n", - "\n", - "mpl.figure.prototype._remove_fig_handler = function (event) {\n", - " var fig = event.data.fig;\n", - " if (event.target !== this) {\n", - " // Ignore bubbled events from children.\n", - " return;\n", - " }\n", - " fig.close_ws(fig, {});\n", - "};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (el) {\n", - " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (el) {\n", - " // this is important to make the div 'focusable\n", - " el.setAttribute('tabindex', 0);\n", - " // reach out to IPython and tell the keyboard manager to turn it's self\n", - " // off when our div gets focus\n", - "\n", - " // location in version 3\n", - " if (IPython.notebook.keyboard_manager) {\n", - " IPython.notebook.keyboard_manager.register_events(el);\n", - " } else {\n", - " // location in version 2\n", - " IPython.keyboard_manager.register_events(el);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", - " var manager = IPython.notebook.keyboard_manager;\n", - " if (!manager) {\n", - " manager = IPython.keyboard_manager;\n", - " }\n", - "\n", - " // Check for shift+enter\n", - " if (event.shiftKey && event.which === 13) {\n", - " this.canvas_div.blur();\n", - " // select the cell after this one\n", - " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", - " IPython.notebook.select(index + 1);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " fig.ondownload(fig, null);\n", - "};\n", - "\n", - "mpl.find_output_cell = function (html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i = 0; i < ncells; i++) {\n", - " var cell = cells[i];\n", - " if (cell.cell_type === 'code') {\n", - " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", - " var data = cell.output_area.outputs[j];\n", - " if (data.data) {\n", - " // IPython >= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] === html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "};\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel !== null) {\n", - " IPython.notebook.kernel.comm_manager.register_target(\n", - " 'matplotlib',\n", - " mpl.mpl_figure_comm\n", - " );\n", - "}\n" - ], + "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n if (typeof WebSocket !== 'undefined') {\n return WebSocket;\n } else if (typeof MozWebSocket !== 'undefined') {\n return MozWebSocket;\n } else {\n alert(\n 'Your browser does not have WebSocket support. ' +\n 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n 'Firefox 4 and 5 are also supported but you ' +\n 'have to enable WebSockets in about:config.'\n );\n }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n this.id = figure_id;\n\n this.ws = websocket;\n\n this.supports_binary = this.ws.binaryType !== undefined;\n\n if (!this.supports_binary) {\n var warnings = document.getElementById('mpl-warnings');\n if (warnings) {\n warnings.style.display = 'block';\n warnings.textContent =\n 'This browser does not support binary websocket messages. ' +\n 'Performance may be slow.';\n }\n }\n\n this.imageObj = new Image();\n\n this.context = undefined;\n this.message = undefined;\n this.canvas = undefined;\n this.rubberband_canvas = undefined;\n this.rubberband_context = undefined;\n this.format_dropdown = undefined;\n\n this.image_mode = 'full';\n\n this.root = document.createElement('div');\n this.root.setAttribute('style', 'display: inline-block');\n this._root_extra_style(this.root);\n\n parent_element.appendChild(this.root);\n\n this._init_header(this);\n this._init_canvas(this);\n this._init_toolbar(this);\n\n var fig = this;\n\n this.waiting = false;\n\n this.ws.onopen = function () {\n fig.send_message('supports_binary', { value: fig.supports_binary });\n fig.send_message('send_image_mode', {});\n if (fig.ratio !== 1) {\n fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n }\n fig.send_message('refresh', {});\n };\n\n this.imageObj.onload = function () {\n if (fig.image_mode === 'full') {\n // Full images could contain transparency (where diff images\n // almost always do), so we need to clear the canvas so that\n // there is no ghosting.\n fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n }\n fig.context.drawImage(fig.imageObj, 0, 0);\n };\n\n this.imageObj.onunload = function () {\n fig.ws.close();\n };\n\n this.ws.onmessage = this._make_on_message_function(this);\n\n this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n var titlebar = document.createElement('div');\n titlebar.classList =\n 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n var titletext = document.createElement('div');\n titletext.classList = 'ui-dialog-title';\n titletext.setAttribute(\n 'style',\n 'width: 100%; text-align: center; padding: 3px;'\n );\n titlebar.appendChild(titletext);\n this.root.appendChild(titlebar);\n this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n var fig = this;\n\n var canvas_div = (this.canvas_div = document.createElement('div'));\n canvas_div.setAttribute(\n 'style',\n 'border: 1px solid #ddd;' +\n 'box-sizing: content-box;' +\n 'clear: both;' +\n 'min-height: 1px;' +\n 'min-width: 1px;' +\n 'outline: 0;' +\n 'overflow: hidden;' +\n 'position: relative;' +\n 'resize: both;'\n );\n\n function on_keyboard_event_closure(name) {\n return function (event) {\n return fig.key_event(event, name);\n };\n }\n\n canvas_div.addEventListener(\n 'keydown',\n on_keyboard_event_closure('key_press')\n );\n canvas_div.addEventListener(\n 'keyup',\n on_keyboard_event_closure('key_release')\n );\n\n this._canvas_extra_style(canvas_div);\n this.root.appendChild(canvas_div);\n\n var canvas = (this.canvas = document.createElement('canvas'));\n canvas.classList.add('mpl-canvas');\n canvas.setAttribute('style', 'box-sizing: content-box;');\n\n this.context = canvas.getContext('2d');\n\n var backingStore =\n this.context.backingStorePixelRatio ||\n this.context.webkitBackingStorePixelRatio ||\n this.context.mozBackingStorePixelRatio ||\n this.context.msBackingStorePixelRatio ||\n this.context.oBackingStorePixelRatio ||\n this.context.backingStorePixelRatio ||\n 1;\n\n this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n 'canvas'\n ));\n rubberband_canvas.setAttribute(\n 'style',\n 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n );\n\n // Apply a ponyfill if ResizeObserver is not implemented by browser.\n if (this.ResizeObserver === undefined) {\n if (window.ResizeObserver !== undefined) {\n this.ResizeObserver = window.ResizeObserver;\n } else {\n var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n this.ResizeObserver = obs.ResizeObserver;\n }\n }\n\n this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n var nentries = entries.length;\n for (var i = 0; i < nentries; i++) {\n var entry = entries[i];\n var width, height;\n if (entry.contentBoxSize) {\n if (entry.contentBoxSize instanceof Array) {\n // Chrome 84 implements new version of spec.\n width = entry.contentBoxSize[0].inlineSize;\n height = entry.contentBoxSize[0].blockSize;\n } else {\n // Firefox implements old version of spec.\n width = entry.contentBoxSize.inlineSize;\n height = entry.contentBoxSize.blockSize;\n }\n } else {\n // Chrome <84 implements even older version of spec.\n width = entry.contentRect.width;\n height = entry.contentRect.height;\n }\n\n // Keep the size of the canvas and rubber band canvas in sync with\n // the canvas container.\n if (entry.devicePixelContentBoxSize) {\n // Chrome 84 implements new version of spec.\n canvas.setAttribute(\n 'width',\n entry.devicePixelContentBoxSize[0].inlineSize\n );\n canvas.setAttribute(\n 'height',\n entry.devicePixelContentBoxSize[0].blockSize\n );\n } else {\n canvas.setAttribute('width', width * fig.ratio);\n canvas.setAttribute('height', height * fig.ratio);\n }\n canvas.setAttribute(\n 'style',\n 'width: ' + width + 'px; height: ' + height + 'px;'\n );\n\n rubberband_canvas.setAttribute('width', width);\n rubberband_canvas.setAttribute('height', height);\n\n // And update the size in Python. We ignore the initial 0/0 size\n // that occurs as the element is placed into the DOM, which should\n // otherwise not happen due to the minimum size styling.\n if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n fig.request_resize(width, height);\n }\n }\n });\n this.resizeObserverInstance.observe(canvas_div);\n\n function on_mouse_event_closure(name) {\n return function (event) {\n return fig.mouse_event(event, name);\n };\n }\n\n rubberband_canvas.addEventListener(\n 'mousedown',\n on_mouse_event_closure('button_press')\n );\n rubberband_canvas.addEventListener(\n 'mouseup',\n on_mouse_event_closure('button_release')\n );\n // Throttle sequential mouse events to 1 every 20ms.\n rubberband_canvas.addEventListener(\n 'mousemove',\n on_mouse_event_closure('motion_notify')\n );\n\n rubberband_canvas.addEventListener(\n 'mouseenter',\n on_mouse_event_closure('figure_enter')\n );\n rubberband_canvas.addEventListener(\n 'mouseleave',\n on_mouse_event_closure('figure_leave')\n );\n\n canvas_div.addEventListener('wheel', function (event) {\n if (event.deltaY < 0) {\n event.step = 1;\n } else {\n event.step = -1;\n }\n on_mouse_event_closure('scroll')(event);\n });\n\n canvas_div.appendChild(canvas);\n canvas_div.appendChild(rubberband_canvas);\n\n this.rubberband_context = rubberband_canvas.getContext('2d');\n this.rubberband_context.strokeStyle = '#000000';\n\n this._resize_canvas = function (width, height, forward) {\n if (forward) {\n canvas_div.style.width = width + 'px';\n canvas_div.style.height = height + 'px';\n }\n };\n\n // Disable right mouse context menu.\n this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n event.preventDefault();\n return false;\n });\n\n function set_focus() {\n canvas.focus();\n canvas_div.focus();\n }\n\n window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'mpl-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n continue;\n }\n\n var button = (fig.buttons[name] = document.createElement('button'));\n button.classList = 'mpl-widget';\n button.setAttribute('role', 'button');\n button.setAttribute('aria-disabled', 'false');\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n var icon_img = document.createElement('img');\n icon_img.src = '_images/' + image + '.png';\n icon_img.srcset = '_images/' + image + '_large.png 2x';\n icon_img.alt = tooltip;\n button.appendChild(icon_img);\n\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n var fmt_picker = document.createElement('select');\n fmt_picker.classList = 'mpl-widget';\n toolbar.appendChild(fmt_picker);\n this.format_dropdown = fmt_picker;\n\n for (var ind in mpl.extensions) {\n var fmt = mpl.extensions[ind];\n var option = document.createElement('option');\n option.selected = fmt === mpl.default_extension;\n option.innerHTML = fmt;\n fmt_picker.appendChild(option);\n }\n\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n // which will in turn request a refresh of the image.\n this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n properties['type'] = type;\n properties['figure_id'] = this.id;\n this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n if (!this.waiting) {\n this.waiting = true;\n this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n var format_dropdown = fig.format_dropdown;\n var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n var size = msg['size'];\n if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n fig._resize_canvas(size[0], size[1], msg['forward']);\n fig.send_message('refresh', {});\n }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n var x0 = msg['x0'] / fig.ratio;\n var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n var x1 = msg['x1'] / fig.ratio;\n var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n x0 = Math.floor(x0) + 0.5;\n y0 = Math.floor(y0) + 0.5;\n x1 = Math.floor(x1) + 0.5;\n y1 = Math.floor(y1) + 0.5;\n var min_x = Math.min(x0, x1);\n var min_y = Math.min(y0, y1);\n var width = Math.abs(x1 - x0);\n var height = Math.abs(y1 - y0);\n\n fig.rubberband_context.clearRect(\n 0,\n 0,\n fig.canvas.width / fig.ratio,\n fig.canvas.height / fig.ratio\n );\n\n fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n // Updates the figure title.\n fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n var cursor = msg['cursor'];\n switch (cursor) {\n case 0:\n cursor = 'pointer';\n break;\n case 1:\n cursor = 'default';\n break;\n case 2:\n cursor = 'crosshair';\n break;\n case 3:\n cursor = 'move';\n break;\n }\n fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n // Request the server to send over a new figure.\n fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n for (var key in msg) {\n if (!(key in fig.buttons)) {\n continue;\n }\n fig.buttons[key].disabled = !msg[key];\n fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n if (msg['mode'] === 'PAN') {\n fig.buttons['Pan'].classList.add('active');\n fig.buttons['Zoom'].classList.remove('active');\n } else if (msg['mode'] === 'ZOOM') {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.add('active');\n } else {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.remove('active');\n }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Called whenever the canvas gets updated.\n this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n return function socket_on_message(evt) {\n if (evt.data instanceof Blob) {\n /* FIXME: We get \"Resource interpreted as Image but\n * transferred with MIME type text/plain:\" errors on\n * Chrome. But how to set the MIME type? It doesn't seem\n * to be part of the websocket stream */\n evt.data.type = 'image/png';\n\n /* Free the memory for the previous frames */\n if (fig.imageObj.src) {\n (window.URL || window.webkitURL).revokeObjectURL(\n fig.imageObj.src\n );\n }\n\n fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n evt.data\n );\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n } else if (\n typeof evt.data === 'string' &&\n evt.data.slice(0, 21) === 'data:image/png;base64'\n ) {\n fig.imageObj.src = evt.data;\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n }\n\n var msg = JSON.parse(evt.data);\n var msg_type = msg['type'];\n\n // Call the \"handle_{type}\" callback, which takes\n // the figure and JSON message as its only arguments.\n try {\n var callback = fig['handle_' + msg_type];\n } catch (e) {\n console.log(\n \"No handler for the '\" + msg_type + \"' message type: \",\n msg\n );\n return;\n }\n\n if (callback) {\n try {\n // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n callback(fig, msg);\n } catch (e) {\n console.log(\n \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n e,\n e.stack,\n msg\n );\n }\n }\n };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n //this section is from http://www.quirksmode.org/js/events_properties.html\n var targ;\n if (!e) {\n e = window.event;\n }\n if (e.target) {\n targ = e.target;\n } else if (e.srcElement) {\n targ = e.srcElement;\n }\n if (targ.nodeType === 3) {\n // defeat Safari bug\n targ = targ.parentNode;\n }\n\n // pageX,Y are the mouse positions relative to the document\n var boundingRect = targ.getBoundingClientRect();\n var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n return Object.keys(original).reduce(function (obj, key) {\n if (typeof original[key] !== 'object') {\n obj[key] = original[key];\n }\n return obj;\n }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n var canvas_pos = mpl.findpos(event);\n\n if (name === 'button_press') {\n this.canvas.focus();\n this.canvas_div.focus();\n }\n\n var x = canvas_pos.x * this.ratio;\n var y = canvas_pos.y * this.ratio;\n\n this.send_message(name, {\n x: x,\n y: y,\n button: event.button,\n step: event.step,\n guiEvent: simpleKeys(event),\n });\n\n /* This prevents the web browser from automatically changing to\n * the text insertion cursor when the button is pressed. We want\n * to control all of the cursor setting manually through the\n * 'cursor' event from matplotlib */\n event.preventDefault();\n return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n // Prevent repeat events\n if (name === 'key_press') {\n if (event.which === this._key) {\n return;\n } else {\n this._key = event.which;\n }\n }\n if (name === 'key_release') {\n this._key = null;\n }\n\n var value = '';\n if (event.ctrlKey && event.which !== 17) {\n value += 'ctrl+';\n }\n if (event.altKey && event.which !== 18) {\n value += 'alt+';\n }\n if (event.shiftKey && event.which !== 16) {\n value += 'shift+';\n }\n\n value += 'k';\n value += event.which.toString();\n\n this._key_event_extra(event, name);\n\n this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n if (name === 'download') {\n this.handle_save(this, null);\n } else {\n this.send_message('toolbar_button', { name: name });\n }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\nmpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n\nmpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n // Create a \"websocket\"-like object which calls the given IPython comm\n // object with the appropriate methods. Currently this is a non binary\n // socket, so there is still some room for performance tuning.\n var ws = {};\n\n ws.close = function () {\n comm.close();\n };\n ws.send = function (m) {\n //console.log('sending', m);\n comm.send(m);\n };\n // Register the callback with on_msg.\n comm.on_msg(function (msg) {\n //console.log('receiving', msg['content']['data'], msg);\n // Pass the mpl event to the overridden (by mpl) onmessage function.\n ws.onmessage(msg['content']['data']);\n });\n return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n // This is the function which gets called when the mpl process\n // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n var id = msg.content.data.id;\n // Get hold of the div created by the display call when the Comm\n // socket was opened in Python.\n var element = document.getElementById(id);\n var ws_proxy = comm_websocket_adapter(comm);\n\n function ondownload(figure, _format) {\n window.open(figure.canvas.toDataURL());\n }\n\n var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n // web socket which is closed, not our websocket->open comm proxy.\n ws_proxy.onopen();\n\n fig.parent_element = element;\n fig.cell_info = mpl.find_output_cell(\"
\");\n if (!fig.cell_info) {\n console.error('Failed to find cell for figure', id, fig);\n return;\n }\n fig.cell_info[0].output_area.element.on(\n 'cleared',\n { fig: fig },\n fig._remove_fig_handler\n );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n var width = fig.canvas.width / fig.ratio;\n fig.cell_info[0].output_area.element.off(\n 'cleared',\n fig._remove_fig_handler\n );\n fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n // Update the output cell to use the data from the current canvas.\n fig.push_to_output();\n var dataURL = fig.canvas.toDataURL();\n // Re-enable the keyboard manager in IPython - without this line, in FF,\n // the notebook keyboard shortcuts fail.\n IPython.keyboard_manager.enable();\n fig.parent_element.innerHTML =\n '';\n fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n fig.send_message('closing', msg);\n // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n // Turn the data on the canvas into data in the output cell.\n var width = this.canvas.width / this.ratio;\n var dataURL = this.canvas.toDataURL();\n this.cell_info[1]['text/html'] =\n '';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Tell IPython that the notebook contents must change.\n IPython.notebook.set_dirty(true);\n this.send_message('ack', {});\n var fig = this;\n // Wait a second, then push the new image to the DOM so\n // that it is saved nicely (might be nice to debounce this).\n setTimeout(function () {\n fig.push_to_output();\n }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'btn-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n var button;\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n continue;\n }\n\n button = fig.buttons[name] = document.createElement('button');\n button.classList = 'btn btn-default';\n button.href = '#';\n button.title = name;\n button.innerHTML = '';\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n // Add the status bar.\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message pull-right';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n\n // Add the close button to the window.\n var buttongrp = document.createElement('div');\n buttongrp.classList = 'btn-group inline pull-right';\n button = document.createElement('button');\n button.classList = 'btn btn-mini btn-primary';\n button.href = '#';\n button.title = 'Stop Interaction';\n button.innerHTML = '';\n button.addEventListener('click', function (_evt) {\n fig.handle_close(fig, {});\n });\n button.addEventListener(\n 'mouseover',\n on_mouseover_closure('Stop Interaction')\n );\n buttongrp.appendChild(button);\n var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n var fig = event.data.fig;\n if (event.target !== this) {\n // Ignore bubbled events from children.\n return;\n }\n fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n // this is important to make the div 'focusable\n el.setAttribute('tabindex', 0);\n // reach out to IPython and tell the keyboard manager to turn it's self\n // off when our div gets focus\n\n // location in version 3\n if (IPython.notebook.keyboard_manager) {\n IPython.notebook.keyboard_manager.register_events(el);\n } else {\n // location in version 2\n IPython.keyboard_manager.register_events(el);\n }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n var manager = IPython.notebook.keyboard_manager;\n if (!manager) {\n manager = IPython.keyboard_manager;\n }\n\n // Check for shift+enter\n if (event.shiftKey && event.which === 13) {\n this.canvas_div.blur();\n // select the cell after this one\n var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n IPython.notebook.select(index + 1);\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n // Return the cell and output element which can be found *uniquely* in the notebook.\n // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n // IPython event is triggered only after the cells have been serialised, which for\n // our purposes (turning an active figure into a static one), is too late.\n var cells = IPython.notebook.get_cells();\n var ncells = cells.length;\n for (var i = 0; i < ncells; i++) {\n var cell = cells[i];\n if (cell.cell_type === 'code') {\n for (var j = 0; j < cell.output_area.outputs.length; j++) {\n var data = cell.output_area.outputs[j];\n if (data.data) {\n // IPython >= 3 moved mimebundle to data attribute of output\n data = data.data;\n }\n if (data['text/html'] === html_output) {\n return [cell, data, j];\n }\n }\n }\n }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n IPython.notebook.kernel.comm_manager.register_target(\n 'matplotlib',\n mpl.mpl_figure_comm\n );\n}\n", "text/plain": [ "" ] @@ -1153,955 +205,7 @@ "outputs": [ { "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "/* global mpl */\n", - "window.mpl = {};\n", - "\n", - "mpl.get_websocket_type = function () {\n", - " if (typeof WebSocket !== 'undefined') {\n", - " return WebSocket;\n", - " } else if (typeof MozWebSocket !== 'undefined') {\n", - " return MozWebSocket;\n", - " } else {\n", - " alert(\n", - " 'Your browser does not have WebSocket support. ' +\n", - " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", - " 'Firefox 4 and 5 are also supported but you ' +\n", - " 'have to enable WebSockets in about:config.'\n", - " );\n", - " }\n", - "};\n", - "\n", - "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", - " this.id = figure_id;\n", - "\n", - " this.ws = websocket;\n", - "\n", - " this.supports_binary = this.ws.binaryType !== undefined;\n", - "\n", - " if (!this.supports_binary) {\n", - " var warnings = document.getElementById('mpl-warnings');\n", - " if (warnings) {\n", - " warnings.style.display = 'block';\n", - " warnings.textContent =\n", - " 'This browser does not support binary websocket messages. ' +\n", - " 'Performance may be slow.';\n", - " }\n", - " }\n", - "\n", - " this.imageObj = new Image();\n", - "\n", - " this.context = undefined;\n", - " this.message = undefined;\n", - " this.canvas = undefined;\n", - " this.rubberband_canvas = undefined;\n", - " this.rubberband_context = undefined;\n", - " this.format_dropdown = undefined;\n", - "\n", - " this.image_mode = 'full';\n", - "\n", - " this.root = document.createElement('div');\n", - " this.root.setAttribute('style', 'display: inline-block');\n", - " this._root_extra_style(this.root);\n", - "\n", - " parent_element.appendChild(this.root);\n", - "\n", - " this._init_header(this);\n", - " this._init_canvas(this);\n", - " this._init_toolbar(this);\n", - "\n", - " var fig = this;\n", - "\n", - " this.waiting = false;\n", - "\n", - " this.ws.onopen = function () {\n", - " fig.send_message('supports_binary', { value: fig.supports_binary });\n", - " fig.send_message('send_image_mode', {});\n", - " if (fig.ratio !== 1) {\n", - " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", - " }\n", - " fig.send_message('refresh', {});\n", - " };\n", - "\n", - " this.imageObj.onload = function () {\n", - " if (fig.image_mode === 'full') {\n", - " // Full images could contain transparency (where diff images\n", - " // almost always do), so we need to clear the canvas so that\n", - " // there is no ghosting.\n", - " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", - " }\n", - " fig.context.drawImage(fig.imageObj, 0, 0);\n", - " };\n", - "\n", - " this.imageObj.onunload = function () {\n", - " fig.ws.close();\n", - " };\n", - "\n", - " this.ws.onmessage = this._make_on_message_function(this);\n", - "\n", - " this.ondownload = ondownload;\n", - "};\n", - "\n", - "mpl.figure.prototype._init_header = function () {\n", - " var titlebar = document.createElement('div');\n", - " titlebar.classList =\n", - " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", - " var titletext = document.createElement('div');\n", - " titletext.classList = 'ui-dialog-title';\n", - " titletext.setAttribute(\n", - " 'style',\n", - " 'width: 100%; text-align: center; padding: 3px;'\n", - " );\n", - " titlebar.appendChild(titletext);\n", - " this.root.appendChild(titlebar);\n", - " this.header = titletext;\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._init_canvas = function () {\n", - " var fig = this;\n", - "\n", - " var canvas_div = (this.canvas_div = document.createElement('div'));\n", - " canvas_div.setAttribute(\n", - " 'style',\n", - " 'border: 1px solid #ddd;' +\n", - " 'box-sizing: content-box;' +\n", - " 'clear: both;' +\n", - " 'min-height: 1px;' +\n", - " 'min-width: 1px;' +\n", - " 'outline: 0;' +\n", - " 'overflow: hidden;' +\n", - " 'position: relative;' +\n", - " 'resize: both;'\n", - " );\n", - "\n", - " function on_keyboard_event_closure(name) {\n", - " return function (event) {\n", - " return fig.key_event(event, name);\n", - " };\n", - " }\n", - "\n", - " canvas_div.addEventListener(\n", - " 'keydown',\n", - " on_keyboard_event_closure('key_press')\n", - " );\n", - " canvas_div.addEventListener(\n", - " 'keyup',\n", - " on_keyboard_event_closure('key_release')\n", - " );\n", - "\n", - " this._canvas_extra_style(canvas_div);\n", - " this.root.appendChild(canvas_div);\n", - "\n", - " var canvas = (this.canvas = document.createElement('canvas'));\n", - " canvas.classList.add('mpl-canvas');\n", - " canvas.setAttribute('style', 'box-sizing: content-box;');\n", - "\n", - " this.context = canvas.getContext('2d');\n", - "\n", - " var backingStore =\n", - " this.context.backingStorePixelRatio ||\n", - " this.context.webkitBackingStorePixelRatio ||\n", - " this.context.mozBackingStorePixelRatio ||\n", - " this.context.msBackingStorePixelRatio ||\n", - " this.context.oBackingStorePixelRatio ||\n", - " this.context.backingStorePixelRatio ||\n", - " 1;\n", - "\n", - " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", - "\n", - " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", - " 'canvas'\n", - " ));\n", - " rubberband_canvas.setAttribute(\n", - " 'style',\n", - " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", - " );\n", - "\n", - " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", - " if (this.ResizeObserver === undefined) {\n", - " if (window.ResizeObserver !== undefined) {\n", - " this.ResizeObserver = window.ResizeObserver;\n", - " } else {\n", - " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", - " this.ResizeObserver = obs.ResizeObserver;\n", - " }\n", - " }\n", - "\n", - " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", - " var nentries = entries.length;\n", - " for (var i = 0; i < nentries; i++) {\n", - " var entry = entries[i];\n", - " var width, height;\n", - " if (entry.contentBoxSize) {\n", - " if (entry.contentBoxSize instanceof Array) {\n", - " // Chrome 84 implements new version of spec.\n", - " width = entry.contentBoxSize[0].inlineSize;\n", - " height = entry.contentBoxSize[0].blockSize;\n", - " } else {\n", - " // Firefox implements old version of spec.\n", - " width = entry.contentBoxSize.inlineSize;\n", - " height = entry.contentBoxSize.blockSize;\n", - " }\n", - " } else {\n", - " // Chrome <84 implements even older version of spec.\n", - " width = entry.contentRect.width;\n", - " height = entry.contentRect.height;\n", - " }\n", - "\n", - " // Keep the size of the canvas and rubber band canvas in sync with\n", - " // the canvas container.\n", - " if (entry.devicePixelContentBoxSize) {\n", - " // Chrome 84 implements new version of spec.\n", - " canvas.setAttribute(\n", - " 'width',\n", - " entry.devicePixelContentBoxSize[0].inlineSize\n", - " );\n", - " canvas.setAttribute(\n", - " 'height',\n", - " entry.devicePixelContentBoxSize[0].blockSize\n", - " );\n", - " } else {\n", - " canvas.setAttribute('width', width * fig.ratio);\n", - " canvas.setAttribute('height', height * fig.ratio);\n", - " }\n", - " canvas.setAttribute(\n", - " 'style',\n", - " 'width: ' + width + 'px; height: ' + height + 'px;'\n", - " );\n", - "\n", - " rubberband_canvas.setAttribute('width', width);\n", - " rubberband_canvas.setAttribute('height', height);\n", - "\n", - " // And update the size in Python. We ignore the initial 0/0 size\n", - " // that occurs as the element is placed into the DOM, which should\n", - " // otherwise not happen due to the minimum size styling.\n", - " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", - " fig.request_resize(width, height);\n", - " }\n", - " }\n", - " });\n", - " this.resizeObserverInstance.observe(canvas_div);\n", - "\n", - " function on_mouse_event_closure(name) {\n", - " return function (event) {\n", - " return fig.mouse_event(event, name);\n", - " };\n", - " }\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mousedown',\n", - " on_mouse_event_closure('button_press')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseup',\n", - " on_mouse_event_closure('button_release')\n", - " );\n", - " // Throttle sequential mouse events to 1 every 20ms.\n", - " rubberband_canvas.addEventListener(\n", - " 'mousemove',\n", - " on_mouse_event_closure('motion_notify')\n", - " );\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseenter',\n", - " on_mouse_event_closure('figure_enter')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseleave',\n", - " on_mouse_event_closure('figure_leave')\n", - " );\n", - "\n", - " canvas_div.addEventListener('wheel', function (event) {\n", - " if (event.deltaY < 0) {\n", - " event.step = 1;\n", - " } else {\n", - " event.step = -1;\n", - " }\n", - " on_mouse_event_closure('scroll')(event);\n", - " });\n", - "\n", - " canvas_div.appendChild(canvas);\n", - " canvas_div.appendChild(rubberband_canvas);\n", - "\n", - " this.rubberband_context = rubberband_canvas.getContext('2d');\n", - " this.rubberband_context.strokeStyle = '#000000';\n", - "\n", - " this._resize_canvas = function (width, height, forward) {\n", - " if (forward) {\n", - " canvas_div.style.width = width + 'px';\n", - " canvas_div.style.height = height + 'px';\n", - " }\n", - " };\n", - "\n", - " // Disable right mouse context menu.\n", - " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", - " event.preventDefault();\n", - " return false;\n", - " });\n", - "\n", - " function set_focus() {\n", - " canvas.focus();\n", - " canvas_div.focus();\n", - " }\n", - "\n", - " window.setTimeout(set_focus, 100);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'mpl-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " continue;\n", - " }\n", - "\n", - " var button = (fig.buttons[name] = document.createElement('button'));\n", - " button.classList = 'mpl-widget';\n", - " button.setAttribute('role', 'button');\n", - " button.setAttribute('aria-disabled', 'false');\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - "\n", - " var icon_img = document.createElement('img');\n", - " icon_img.src = '_images/' + image + '.png';\n", - " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", - " icon_img.alt = tooltip;\n", - " button.appendChild(icon_img);\n", - "\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " var fmt_picker = document.createElement('select');\n", - " fmt_picker.classList = 'mpl-widget';\n", - " toolbar.appendChild(fmt_picker);\n", - " this.format_dropdown = fmt_picker;\n", - "\n", - " for (var ind in mpl.extensions) {\n", - " var fmt = mpl.extensions[ind];\n", - " var option = document.createElement('option');\n", - " option.selected = fmt === mpl.default_extension;\n", - " option.innerHTML = fmt;\n", - " fmt_picker.appendChild(option);\n", - " }\n", - "\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "};\n", - "\n", - "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", - " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", - " // which will in turn request a refresh of the image.\n", - " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", - "};\n", - "\n", - "mpl.figure.prototype.send_message = function (type, properties) {\n", - " properties['type'] = type;\n", - " properties['figure_id'] = this.id;\n", - " this.ws.send(JSON.stringify(properties));\n", - "};\n", - "\n", - "mpl.figure.prototype.send_draw_message = function () {\n", - " if (!this.waiting) {\n", - " this.waiting = true;\n", - " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " var format_dropdown = fig.format_dropdown;\n", - " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", - " fig.ondownload(fig, format);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", - " var size = msg['size'];\n", - " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", - " fig._resize_canvas(size[0], size[1], msg['forward']);\n", - " fig.send_message('refresh', {});\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", - " var x0 = msg['x0'] / fig.ratio;\n", - " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", - " var x1 = msg['x1'] / fig.ratio;\n", - " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", - " x0 = Math.floor(x0) + 0.5;\n", - " y0 = Math.floor(y0) + 0.5;\n", - " x1 = Math.floor(x1) + 0.5;\n", - " y1 = Math.floor(y1) + 0.5;\n", - " var min_x = Math.min(x0, x1);\n", - " var min_y = Math.min(y0, y1);\n", - " var width = Math.abs(x1 - x0);\n", - " var height = Math.abs(y1 - y0);\n", - "\n", - " fig.rubberband_context.clearRect(\n", - " 0,\n", - " 0,\n", - " fig.canvas.width / fig.ratio,\n", - " fig.canvas.height / fig.ratio\n", - " );\n", - "\n", - " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", - " // Updates the figure title.\n", - " fig.header.textContent = msg['label'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", - " var cursor = msg['cursor'];\n", - " switch (cursor) {\n", - " case 0:\n", - " cursor = 'pointer';\n", - " break;\n", - " case 1:\n", - " cursor = 'default';\n", - " break;\n", - " case 2:\n", - " cursor = 'crosshair';\n", - " break;\n", - " case 3:\n", - " cursor = 'move';\n", - " break;\n", - " }\n", - " fig.rubberband_canvas.style.cursor = cursor;\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_message = function (fig, msg) {\n", - " fig.message.textContent = msg['message'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", - " // Request the server to send over a new figure.\n", - " fig.send_draw_message();\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", - " fig.image_mode = msg['mode'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", - " for (var key in msg) {\n", - " if (!(key in fig.buttons)) {\n", - " continue;\n", - " }\n", - " fig.buttons[key].disabled = !msg[key];\n", - " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", - " if (msg['mode'] === 'PAN') {\n", - " fig.buttons['Pan'].classList.add('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " } else if (msg['mode'] === 'ZOOM') {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.add('active');\n", - " } else {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Called whenever the canvas gets updated.\n", - " this.send_message('ack', {});\n", - "};\n", - "\n", - "// A function to construct a web socket function for onmessage handling.\n", - "// Called in the figure constructor.\n", - "mpl.figure.prototype._make_on_message_function = function (fig) {\n", - " return function socket_on_message(evt) {\n", - " if (evt.data instanceof Blob) {\n", - " /* FIXME: We get \"Resource interpreted as Image but\n", - " * transferred with MIME type text/plain:\" errors on\n", - " * Chrome. But how to set the MIME type? It doesn't seem\n", - " * to be part of the websocket stream */\n", - " evt.data.type = 'image/png';\n", - "\n", - " /* Free the memory for the previous frames */\n", - " if (fig.imageObj.src) {\n", - " (window.URL || window.webkitURL).revokeObjectURL(\n", - " fig.imageObj.src\n", - " );\n", - " }\n", - "\n", - " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", - " evt.data\n", - " );\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " } else if (\n", - " typeof evt.data === 'string' &&\n", - " evt.data.slice(0, 21) === 'data:image/png;base64'\n", - " ) {\n", - " fig.imageObj.src = evt.data;\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " }\n", - "\n", - " var msg = JSON.parse(evt.data);\n", - " var msg_type = msg['type'];\n", - "\n", - " // Call the \"handle_{type}\" callback, which takes\n", - " // the figure and JSON message as its only arguments.\n", - " try {\n", - " var callback = fig['handle_' + msg_type];\n", - " } catch (e) {\n", - " console.log(\n", - " \"No handler for the '\" + msg_type + \"' message type: \",\n", - " msg\n", - " );\n", - " return;\n", - " }\n", - "\n", - " if (callback) {\n", - " try {\n", - " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", - " callback(fig, msg);\n", - " } catch (e) {\n", - " console.log(\n", - " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", - " e,\n", - " e.stack,\n", - " msg\n", - " );\n", - " }\n", - " }\n", - " };\n", - "};\n", - "\n", - "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", - "mpl.findpos = function (e) {\n", - " //this section is from http://www.quirksmode.org/js/events_properties.html\n", - " var targ;\n", - " if (!e) {\n", - " e = window.event;\n", - " }\n", - " if (e.target) {\n", - " targ = e.target;\n", - " } else if (e.srcElement) {\n", - " targ = e.srcElement;\n", - " }\n", - " if (targ.nodeType === 3) {\n", - " // defeat Safari bug\n", - " targ = targ.parentNode;\n", - " }\n", - "\n", - " // pageX,Y are the mouse positions relative to the document\n", - " var boundingRect = targ.getBoundingClientRect();\n", - " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", - " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", - "\n", - " return { x: x, y: y };\n", - "};\n", - "\n", - "/*\n", - " * return a copy of an object with only non-object keys\n", - " * we need this to avoid circular references\n", - " * http://stackoverflow.com/a/24161582/3208463\n", - " */\n", - "function simpleKeys(original) {\n", - " return Object.keys(original).reduce(function (obj, key) {\n", - " if (typeof original[key] !== 'object') {\n", - " obj[key] = original[key];\n", - " }\n", - " return obj;\n", - " }, {});\n", - "}\n", - "\n", - "mpl.figure.prototype.mouse_event = function (event, name) {\n", - " var canvas_pos = mpl.findpos(event);\n", - "\n", - " if (name === 'button_press') {\n", - " this.canvas.focus();\n", - " this.canvas_div.focus();\n", - " }\n", - "\n", - " var x = canvas_pos.x * this.ratio;\n", - " var y = canvas_pos.y * this.ratio;\n", - "\n", - " this.send_message(name, {\n", - " x: x,\n", - " y: y,\n", - " button: event.button,\n", - " step: event.step,\n", - " guiEvent: simpleKeys(event),\n", - " });\n", - "\n", - " /* This prevents the web browser from automatically changing to\n", - " * the text insertion cursor when the button is pressed. We want\n", - " * to control all of the cursor setting manually through the\n", - " * 'cursor' event from matplotlib */\n", - " event.preventDefault();\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", - " // Handle any extra behaviour associated with a key event\n", - "};\n", - "\n", - "mpl.figure.prototype.key_event = function (event, name) {\n", - " // Prevent repeat events\n", - " if (name === 'key_press') {\n", - " if (event.which === this._key) {\n", - " return;\n", - " } else {\n", - " this._key = event.which;\n", - " }\n", - " }\n", - " if (name === 'key_release') {\n", - " this._key = null;\n", - " }\n", - "\n", - " var value = '';\n", - " if (event.ctrlKey && event.which !== 17) {\n", - " value += 'ctrl+';\n", - " }\n", - " if (event.altKey && event.which !== 18) {\n", - " value += 'alt+';\n", - " }\n", - " if (event.shiftKey && event.which !== 16) {\n", - " value += 'shift+';\n", - " }\n", - "\n", - " value += 'k';\n", - " value += event.which.toString();\n", - "\n", - " this._key_event_extra(event, name);\n", - "\n", - " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", - " if (name === 'download') {\n", - " this.handle_save(this, null);\n", - " } else {\n", - " this.send_message('toolbar_button', { name: name });\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", - " this.message.textContent = tooltip;\n", - "};\n", - "\n", - "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", - "// prettier-ignore\n", - "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", - "\n", - "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", - "\n", - "mpl.default_extension = \"png\";/* global mpl */\n", - "\n", - "var comm_websocket_adapter = function (comm) {\n", - " // Create a \"websocket\"-like object which calls the given IPython comm\n", - " // object with the appropriate methods. Currently this is a non binary\n", - " // socket, so there is still some room for performance tuning.\n", - " var ws = {};\n", - "\n", - " ws.close = function () {\n", - " comm.close();\n", - " };\n", - " ws.send = function (m) {\n", - " //console.log('sending', m);\n", - " comm.send(m);\n", - " };\n", - " // Register the callback with on_msg.\n", - " comm.on_msg(function (msg) {\n", - " //console.log('receiving', msg['content']['data'], msg);\n", - " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", - " ws.onmessage(msg['content']['data']);\n", - " });\n", - " return ws;\n", - "};\n", - "\n", - "mpl.mpl_figure_comm = function (comm, msg) {\n", - " // This is the function which gets called when the mpl process\n", - " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", - "\n", - " var id = msg.content.data.id;\n", - " // Get hold of the div created by the display call when the Comm\n", - " // socket was opened in Python.\n", - " var element = document.getElementById(id);\n", - " var ws_proxy = comm_websocket_adapter(comm);\n", - "\n", - " function ondownload(figure, _format) {\n", - " window.open(figure.canvas.toDataURL());\n", - " }\n", - "\n", - " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", - "\n", - " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", - " // web socket which is closed, not our websocket->open comm proxy.\n", - " ws_proxy.onopen();\n", - "\n", - " fig.parent_element = element;\n", - " fig.cell_info = mpl.find_output_cell(\"
\");\n", - " if (!fig.cell_info) {\n", - " console.error('Failed to find cell for figure', id, fig);\n", - " return;\n", - " }\n", - " fig.cell_info[0].output_area.element.on(\n", - " 'cleared',\n", - " { fig: fig },\n", - " fig._remove_fig_handler\n", - " );\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_close = function (fig, msg) {\n", - " var width = fig.canvas.width / fig.ratio;\n", - " fig.cell_info[0].output_area.element.off(\n", - " 'cleared',\n", - " fig._remove_fig_handler\n", - " );\n", - " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", - "\n", - " // Update the output cell to use the data from the current canvas.\n", - " fig.push_to_output();\n", - " var dataURL = fig.canvas.toDataURL();\n", - " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", - " // the notebook keyboard shortcuts fail.\n", - " IPython.keyboard_manager.enable();\n", - " fig.parent_element.innerHTML =\n", - " '';\n", - " fig.close_ws(fig, msg);\n", - "};\n", - "\n", - "mpl.figure.prototype.close_ws = function (fig, msg) {\n", - " fig.send_message('closing', msg);\n", - " // fig.ws.close()\n", - "};\n", - "\n", - "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", - " // Turn the data on the canvas into data in the output cell.\n", - " var width = this.canvas.width / this.ratio;\n", - " var dataURL = this.canvas.toDataURL();\n", - " this.cell_info[1]['text/html'] =\n", - " '';\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Tell IPython that the notebook contents must change.\n", - " IPython.notebook.set_dirty(true);\n", - " this.send_message('ack', {});\n", - " var fig = this;\n", - " // Wait a second, then push the new image to the DOM so\n", - " // that it is saved nicely (might be nice to debounce this).\n", - " setTimeout(function () {\n", - " fig.push_to_output();\n", - " }, 1000);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'btn-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " var button;\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " continue;\n", - " }\n", - "\n", - " button = fig.buttons[name] = document.createElement('button');\n", - " button.classList = 'btn btn-default';\n", - " button.href = '#';\n", - " button.title = name;\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " // Add the status bar.\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message pull-right';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "\n", - " // Add the close button to the window.\n", - " var buttongrp = document.createElement('div');\n", - " buttongrp.classList = 'btn-group inline pull-right';\n", - " button = document.createElement('button');\n", - " button.classList = 'btn btn-mini btn-primary';\n", - " button.href = '#';\n", - " button.title = 'Stop Interaction';\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', function (_evt) {\n", - " fig.handle_close(fig, {});\n", - " });\n", - " button.addEventListener(\n", - " 'mouseover',\n", - " on_mouseover_closure('Stop Interaction')\n", - " );\n", - " buttongrp.appendChild(button);\n", - " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", - " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", - "};\n", - "\n", - "mpl.figure.prototype._remove_fig_handler = function (event) {\n", - " var fig = event.data.fig;\n", - " if (event.target !== this) {\n", - " // Ignore bubbled events from children.\n", - " return;\n", - " }\n", - " fig.close_ws(fig, {});\n", - "};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (el) {\n", - " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (el) {\n", - " // this is important to make the div 'focusable\n", - " el.setAttribute('tabindex', 0);\n", - " // reach out to IPython and tell the keyboard manager to turn it's self\n", - " // off when our div gets focus\n", - "\n", - " // location in version 3\n", - " if (IPython.notebook.keyboard_manager) {\n", - " IPython.notebook.keyboard_manager.register_events(el);\n", - " } else {\n", - " // location in version 2\n", - " IPython.keyboard_manager.register_events(el);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", - " var manager = IPython.notebook.keyboard_manager;\n", - " if (!manager) {\n", - " manager = IPython.keyboard_manager;\n", - " }\n", - "\n", - " // Check for shift+enter\n", - " if (event.shiftKey && event.which === 13) {\n", - " this.canvas_div.blur();\n", - " // select the cell after this one\n", - " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", - " IPython.notebook.select(index + 1);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " fig.ondownload(fig, null);\n", - "};\n", - "\n", - "mpl.find_output_cell = function (html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i = 0; i < ncells; i++) {\n", - " var cell = cells[i];\n", - " if (cell.cell_type === 'code') {\n", - " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", - " var data = cell.output_area.outputs[j];\n", - " if (data.data) {\n", - " // IPython >= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] === html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "};\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel !== null) {\n", - " IPython.notebook.kernel.comm_manager.register_target(\n", - " 'matplotlib',\n", - " mpl.mpl_figure_comm\n", - " );\n", - "}\n" - ], + "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n if (typeof WebSocket !== 'undefined') {\n return WebSocket;\n } else if (typeof MozWebSocket !== 'undefined') {\n return MozWebSocket;\n } else {\n alert(\n 'Your browser does not have WebSocket support. ' +\n 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n 'Firefox 4 and 5 are also supported but you ' +\n 'have to enable WebSockets in about:config.'\n );\n }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n this.id = figure_id;\n\n this.ws = websocket;\n\n this.supports_binary = this.ws.binaryType !== undefined;\n\n if (!this.supports_binary) {\n var warnings = document.getElementById('mpl-warnings');\n if (warnings) {\n warnings.style.display = 'block';\n warnings.textContent =\n 'This browser does not support binary websocket messages. ' +\n 'Performance may be slow.';\n }\n }\n\n this.imageObj = new Image();\n\n this.context = undefined;\n this.message = undefined;\n this.canvas = undefined;\n this.rubberband_canvas = undefined;\n this.rubberband_context = undefined;\n this.format_dropdown = undefined;\n\n this.image_mode = 'full';\n\n this.root = document.createElement('div');\n this.root.setAttribute('style', 'display: inline-block');\n this._root_extra_style(this.root);\n\n parent_element.appendChild(this.root);\n\n this._init_header(this);\n this._init_canvas(this);\n this._init_toolbar(this);\n\n var fig = this;\n\n this.waiting = false;\n\n this.ws.onopen = function () {\n fig.send_message('supports_binary', { value: fig.supports_binary });\n fig.send_message('send_image_mode', {});\n if (fig.ratio !== 1) {\n fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n }\n fig.send_message('refresh', {});\n };\n\n this.imageObj.onload = function () {\n if (fig.image_mode === 'full') {\n // Full images could contain transparency (where diff images\n // almost always do), so we need to clear the canvas so that\n // there is no ghosting.\n fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n }\n fig.context.drawImage(fig.imageObj, 0, 0);\n };\n\n this.imageObj.onunload = function () {\n fig.ws.close();\n };\n\n this.ws.onmessage = this._make_on_message_function(this);\n\n this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n var titlebar = document.createElement('div');\n titlebar.classList =\n 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n var titletext = document.createElement('div');\n titletext.classList = 'ui-dialog-title';\n titletext.setAttribute(\n 'style',\n 'width: 100%; text-align: center; padding: 3px;'\n );\n titlebar.appendChild(titletext);\n this.root.appendChild(titlebar);\n this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n var fig = this;\n\n var canvas_div = (this.canvas_div = document.createElement('div'));\n canvas_div.setAttribute(\n 'style',\n 'border: 1px solid #ddd;' +\n 'box-sizing: content-box;' +\n 'clear: both;' +\n 'min-height: 1px;' +\n 'min-width: 1px;' +\n 'outline: 0;' +\n 'overflow: hidden;' +\n 'position: relative;' +\n 'resize: both;'\n );\n\n function on_keyboard_event_closure(name) {\n return function (event) {\n return fig.key_event(event, name);\n };\n }\n\n canvas_div.addEventListener(\n 'keydown',\n on_keyboard_event_closure('key_press')\n );\n canvas_div.addEventListener(\n 'keyup',\n on_keyboard_event_closure('key_release')\n );\n\n this._canvas_extra_style(canvas_div);\n this.root.appendChild(canvas_div);\n\n var canvas = (this.canvas = document.createElement('canvas'));\n canvas.classList.add('mpl-canvas');\n canvas.setAttribute('style', 'box-sizing: content-box;');\n\n this.context = canvas.getContext('2d');\n\n var backingStore =\n this.context.backingStorePixelRatio ||\n this.context.webkitBackingStorePixelRatio ||\n this.context.mozBackingStorePixelRatio ||\n this.context.msBackingStorePixelRatio ||\n this.context.oBackingStorePixelRatio ||\n this.context.backingStorePixelRatio ||\n 1;\n\n this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n 'canvas'\n ));\n rubberband_canvas.setAttribute(\n 'style',\n 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n );\n\n // Apply a ponyfill if ResizeObserver is not implemented by browser.\n if (this.ResizeObserver === undefined) {\n if (window.ResizeObserver !== undefined) {\n this.ResizeObserver = window.ResizeObserver;\n } else {\n var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n this.ResizeObserver = obs.ResizeObserver;\n }\n }\n\n this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n var nentries = entries.length;\n for (var i = 0; i < nentries; i++) {\n var entry = entries[i];\n var width, height;\n if (entry.contentBoxSize) {\n if (entry.contentBoxSize instanceof Array) {\n // Chrome 84 implements new version of spec.\n width = entry.contentBoxSize[0].inlineSize;\n height = entry.contentBoxSize[0].blockSize;\n } else {\n // Firefox implements old version of spec.\n width = entry.contentBoxSize.inlineSize;\n height = entry.contentBoxSize.blockSize;\n }\n } else {\n // Chrome <84 implements even older version of spec.\n width = entry.contentRect.width;\n height = entry.contentRect.height;\n }\n\n // Keep the size of the canvas and rubber band canvas in sync with\n // the canvas container.\n if (entry.devicePixelContentBoxSize) {\n // Chrome 84 implements new version of spec.\n canvas.setAttribute(\n 'width',\n entry.devicePixelContentBoxSize[0].inlineSize\n );\n canvas.setAttribute(\n 'height',\n entry.devicePixelContentBoxSize[0].blockSize\n );\n } else {\n canvas.setAttribute('width', width * fig.ratio);\n canvas.setAttribute('height', height * fig.ratio);\n }\n canvas.setAttribute(\n 'style',\n 'width: ' + width + 'px; height: ' + height + 'px;'\n );\n\n rubberband_canvas.setAttribute('width', width);\n rubberband_canvas.setAttribute('height', height);\n\n // And update the size in Python. We ignore the initial 0/0 size\n // that occurs as the element is placed into the DOM, which should\n // otherwise not happen due to the minimum size styling.\n if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n fig.request_resize(width, height);\n }\n }\n });\n this.resizeObserverInstance.observe(canvas_div);\n\n function on_mouse_event_closure(name) {\n return function (event) {\n return fig.mouse_event(event, name);\n };\n }\n\n rubberband_canvas.addEventListener(\n 'mousedown',\n on_mouse_event_closure('button_press')\n );\n rubberband_canvas.addEventListener(\n 'mouseup',\n on_mouse_event_closure('button_release')\n );\n // Throttle sequential mouse events to 1 every 20ms.\n rubberband_canvas.addEventListener(\n 'mousemove',\n on_mouse_event_closure('motion_notify')\n );\n\n rubberband_canvas.addEventListener(\n 'mouseenter',\n on_mouse_event_closure('figure_enter')\n );\n rubberband_canvas.addEventListener(\n 'mouseleave',\n on_mouse_event_closure('figure_leave')\n );\n\n canvas_div.addEventListener('wheel', function (event) {\n if (event.deltaY < 0) {\n event.step = 1;\n } else {\n event.step = -1;\n }\n on_mouse_event_closure('scroll')(event);\n });\n\n canvas_div.appendChild(canvas);\n canvas_div.appendChild(rubberband_canvas);\n\n this.rubberband_context = rubberband_canvas.getContext('2d');\n this.rubberband_context.strokeStyle = '#000000';\n\n this._resize_canvas = function (width, height, forward) {\n if (forward) {\n canvas_div.style.width = width + 'px';\n canvas_div.style.height = height + 'px';\n }\n };\n\n // Disable right mouse context menu.\n this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n event.preventDefault();\n return false;\n });\n\n function set_focus() {\n canvas.focus();\n canvas_div.focus();\n }\n\n window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'mpl-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n continue;\n }\n\n var button = (fig.buttons[name] = document.createElement('button'));\n button.classList = 'mpl-widget';\n button.setAttribute('role', 'button');\n button.setAttribute('aria-disabled', 'false');\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n var icon_img = document.createElement('img');\n icon_img.src = '_images/' + image + '.png';\n icon_img.srcset = '_images/' + image + '_large.png 2x';\n icon_img.alt = tooltip;\n button.appendChild(icon_img);\n\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n var fmt_picker = document.createElement('select');\n fmt_picker.classList = 'mpl-widget';\n toolbar.appendChild(fmt_picker);\n this.format_dropdown = fmt_picker;\n\n for (var ind in mpl.extensions) {\n var fmt = mpl.extensions[ind];\n var option = document.createElement('option');\n option.selected = fmt === mpl.default_extension;\n option.innerHTML = fmt;\n fmt_picker.appendChild(option);\n }\n\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n // which will in turn request a refresh of the image.\n this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n properties['type'] = type;\n properties['figure_id'] = this.id;\n this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n if (!this.waiting) {\n this.waiting = true;\n this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n var format_dropdown = fig.format_dropdown;\n var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n var size = msg['size'];\n if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n fig._resize_canvas(size[0], size[1], msg['forward']);\n fig.send_message('refresh', {});\n }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n var x0 = msg['x0'] / fig.ratio;\n var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n var x1 = msg['x1'] / fig.ratio;\n var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n x0 = Math.floor(x0) + 0.5;\n y0 = Math.floor(y0) + 0.5;\n x1 = Math.floor(x1) + 0.5;\n y1 = Math.floor(y1) + 0.5;\n var min_x = Math.min(x0, x1);\n var min_y = Math.min(y0, y1);\n var width = Math.abs(x1 - x0);\n var height = Math.abs(y1 - y0);\n\n fig.rubberband_context.clearRect(\n 0,\n 0,\n fig.canvas.width / fig.ratio,\n fig.canvas.height / fig.ratio\n );\n\n fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n // Updates the figure title.\n fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n var cursor = msg['cursor'];\n switch (cursor) {\n case 0:\n cursor = 'pointer';\n break;\n case 1:\n cursor = 'default';\n break;\n case 2:\n cursor = 'crosshair';\n break;\n case 3:\n cursor = 'move';\n break;\n }\n fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n // Request the server to send over a new figure.\n fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n for (var key in msg) {\n if (!(key in fig.buttons)) {\n continue;\n }\n fig.buttons[key].disabled = !msg[key];\n fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n if (msg['mode'] === 'PAN') {\n fig.buttons['Pan'].classList.add('active');\n fig.buttons['Zoom'].classList.remove('active');\n } else if (msg['mode'] === 'ZOOM') {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.add('active');\n } else {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.remove('active');\n }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Called whenever the canvas gets updated.\n this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n return function socket_on_message(evt) {\n if (evt.data instanceof Blob) {\n /* FIXME: We get \"Resource interpreted as Image but\n * transferred with MIME type text/plain:\" errors on\n * Chrome. But how to set the MIME type? It doesn't seem\n * to be part of the websocket stream */\n evt.data.type = 'image/png';\n\n /* Free the memory for the previous frames */\n if (fig.imageObj.src) {\n (window.URL || window.webkitURL).revokeObjectURL(\n fig.imageObj.src\n );\n }\n\n fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n evt.data\n );\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n } else if (\n typeof evt.data === 'string' &&\n evt.data.slice(0, 21) === 'data:image/png;base64'\n ) {\n fig.imageObj.src = evt.data;\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n }\n\n var msg = JSON.parse(evt.data);\n var msg_type = msg['type'];\n\n // Call the \"handle_{type}\" callback, which takes\n // the figure and JSON message as its only arguments.\n try {\n var callback = fig['handle_' + msg_type];\n } catch (e) {\n console.log(\n \"No handler for the '\" + msg_type + \"' message type: \",\n msg\n );\n return;\n }\n\n if (callback) {\n try {\n // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n callback(fig, msg);\n } catch (e) {\n console.log(\n \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n e,\n e.stack,\n msg\n );\n }\n }\n };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n //this section is from http://www.quirksmode.org/js/events_properties.html\n var targ;\n if (!e) {\n e = window.event;\n }\n if (e.target) {\n targ = e.target;\n } else if (e.srcElement) {\n targ = e.srcElement;\n }\n if (targ.nodeType === 3) {\n // defeat Safari bug\n targ = targ.parentNode;\n }\n\n // pageX,Y are the mouse positions relative to the document\n var boundingRect = targ.getBoundingClientRect();\n var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n return Object.keys(original).reduce(function (obj, key) {\n if (typeof original[key] !== 'object') {\n obj[key] = original[key];\n }\n return obj;\n }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n var canvas_pos = mpl.findpos(event);\n\n if (name === 'button_press') {\n this.canvas.focus();\n this.canvas_div.focus();\n }\n\n var x = canvas_pos.x * this.ratio;\n var y = canvas_pos.y * this.ratio;\n\n this.send_message(name, {\n x: x,\n y: y,\n button: event.button,\n step: event.step,\n guiEvent: simpleKeys(event),\n });\n\n /* This prevents the web browser from automatically changing to\n * the text insertion cursor when the button is pressed. We want\n * to control all of the cursor setting manually through the\n * 'cursor' event from matplotlib */\n event.preventDefault();\n return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n // Prevent repeat events\n if (name === 'key_press') {\n if (event.which === this._key) {\n return;\n } else {\n this._key = event.which;\n }\n }\n if (name === 'key_release') {\n this._key = null;\n }\n\n var value = '';\n if (event.ctrlKey && event.which !== 17) {\n value += 'ctrl+';\n }\n if (event.altKey && event.which !== 18) {\n value += 'alt+';\n }\n if (event.shiftKey && event.which !== 16) {\n value += 'shift+';\n }\n\n value += 'k';\n value += event.which.toString();\n\n this._key_event_extra(event, name);\n\n this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n if (name === 'download') {\n this.handle_save(this, null);\n } else {\n this.send_message('toolbar_button', { name: name });\n }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\nmpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n\nmpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n // Create a \"websocket\"-like object which calls the given IPython comm\n // object with the appropriate methods. Currently this is a non binary\n // socket, so there is still some room for performance tuning.\n var ws = {};\n\n ws.close = function () {\n comm.close();\n };\n ws.send = function (m) {\n //console.log('sending', m);\n comm.send(m);\n };\n // Register the callback with on_msg.\n comm.on_msg(function (msg) {\n //console.log('receiving', msg['content']['data'], msg);\n // Pass the mpl event to the overridden (by mpl) onmessage function.\n ws.onmessage(msg['content']['data']);\n });\n return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n // This is the function which gets called when the mpl process\n // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n var id = msg.content.data.id;\n // Get hold of the div created by the display call when the Comm\n // socket was opened in Python.\n var element = document.getElementById(id);\n var ws_proxy = comm_websocket_adapter(comm);\n\n function ondownload(figure, _format) {\n window.open(figure.canvas.toDataURL());\n }\n\n var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n // web socket which is closed, not our websocket->open comm proxy.\n ws_proxy.onopen();\n\n fig.parent_element = element;\n fig.cell_info = mpl.find_output_cell(\"
\");\n if (!fig.cell_info) {\n console.error('Failed to find cell for figure', id, fig);\n return;\n }\n fig.cell_info[0].output_area.element.on(\n 'cleared',\n { fig: fig },\n fig._remove_fig_handler\n );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n var width = fig.canvas.width / fig.ratio;\n fig.cell_info[0].output_area.element.off(\n 'cleared',\n fig._remove_fig_handler\n );\n fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n // Update the output cell to use the data from the current canvas.\n fig.push_to_output();\n var dataURL = fig.canvas.toDataURL();\n // Re-enable the keyboard manager in IPython - without this line, in FF,\n // the notebook keyboard shortcuts fail.\n IPython.keyboard_manager.enable();\n fig.parent_element.innerHTML =\n '';\n fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n fig.send_message('closing', msg);\n // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n // Turn the data on the canvas into data in the output cell.\n var width = this.canvas.width / this.ratio;\n var dataURL = this.canvas.toDataURL();\n this.cell_info[1]['text/html'] =\n '';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Tell IPython that the notebook contents must change.\n IPython.notebook.set_dirty(true);\n this.send_message('ack', {});\n var fig = this;\n // Wait a second, then push the new image to the DOM so\n // that it is saved nicely (might be nice to debounce this).\n setTimeout(function () {\n fig.push_to_output();\n }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'btn-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n var button;\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n continue;\n }\n\n button = fig.buttons[name] = document.createElement('button');\n button.classList = 'btn btn-default';\n button.href = '#';\n button.title = name;\n button.innerHTML = '';\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n // Add the status bar.\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message pull-right';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n\n // Add the close button to the window.\n var buttongrp = document.createElement('div');\n buttongrp.classList = 'btn-group inline pull-right';\n button = document.createElement('button');\n button.classList = 'btn btn-mini btn-primary';\n button.href = '#';\n button.title = 'Stop Interaction';\n button.innerHTML = '';\n button.addEventListener('click', function (_evt) {\n fig.handle_close(fig, {});\n });\n button.addEventListener(\n 'mouseover',\n on_mouseover_closure('Stop Interaction')\n );\n buttongrp.appendChild(button);\n var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n var fig = event.data.fig;\n if (event.target !== this) {\n // Ignore bubbled events from children.\n return;\n }\n fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n // this is important to make the div 'focusable\n el.setAttribute('tabindex', 0);\n // reach out to IPython and tell the keyboard manager to turn it's self\n // off when our div gets focus\n\n // location in version 3\n if (IPython.notebook.keyboard_manager) {\n IPython.notebook.keyboard_manager.register_events(el);\n } else {\n // location in version 2\n IPython.keyboard_manager.register_events(el);\n }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n var manager = IPython.notebook.keyboard_manager;\n if (!manager) {\n manager = IPython.keyboard_manager;\n }\n\n // Check for shift+enter\n if (event.shiftKey && event.which === 13) {\n this.canvas_div.blur();\n // select the cell after this one\n var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n IPython.notebook.select(index + 1);\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n // Return the cell and output element which can be found *uniquely* in the notebook.\n // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n // IPython event is triggered only after the cells have been serialised, which for\n // our purposes (turning an active figure into a static one), is too late.\n var cells = IPython.notebook.get_cells();\n var ncells = cells.length;\n for (var i = 0; i < ncells; i++) {\n var cell = cells[i];\n if (cell.cell_type === 'code') {\n for (var j = 0; j < cell.output_area.outputs.length; j++) {\n var data = cell.output_area.outputs[j];\n if (data.data) {\n // IPython >= 3 moved mimebundle to data attribute of output\n data = data.data;\n }\n if (data['text/html'] === html_output) {\n return [cell, data, j];\n }\n }\n }\n }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n IPython.notebook.kernel.comm_manager.register_target(\n 'matplotlib',\n mpl.mpl_figure_comm\n );\n}\n", "text/plain": [ "" ] @@ -2123,955 +227,7 @@ }, { "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "/* global mpl */\n", - "window.mpl = {};\n", - "\n", - "mpl.get_websocket_type = function () {\n", - " if (typeof WebSocket !== 'undefined') {\n", - " return WebSocket;\n", - " } else if (typeof MozWebSocket !== 'undefined') {\n", - " return MozWebSocket;\n", - " } else {\n", - " alert(\n", - " 'Your browser does not have WebSocket support. ' +\n", - " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", - " 'Firefox 4 and 5 are also supported but you ' +\n", - " 'have to enable WebSockets in about:config.'\n", - " );\n", - " }\n", - "};\n", - "\n", - "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", - " this.id = figure_id;\n", - "\n", - " this.ws = websocket;\n", - "\n", - " this.supports_binary = this.ws.binaryType !== undefined;\n", - "\n", - " if (!this.supports_binary) {\n", - " var warnings = document.getElementById('mpl-warnings');\n", - " if (warnings) {\n", - " warnings.style.display = 'block';\n", - " warnings.textContent =\n", - " 'This browser does not support binary websocket messages. ' +\n", - " 'Performance may be slow.';\n", - " }\n", - " }\n", - "\n", - " this.imageObj = new Image();\n", - "\n", - " this.context = undefined;\n", - " this.message = undefined;\n", - " this.canvas = undefined;\n", - " this.rubberband_canvas = undefined;\n", - " this.rubberband_context = undefined;\n", - " this.format_dropdown = undefined;\n", - "\n", - " this.image_mode = 'full';\n", - "\n", - " this.root = document.createElement('div');\n", - " this.root.setAttribute('style', 'display: inline-block');\n", - " this._root_extra_style(this.root);\n", - "\n", - " parent_element.appendChild(this.root);\n", - "\n", - " this._init_header(this);\n", - " this._init_canvas(this);\n", - " this._init_toolbar(this);\n", - "\n", - " var fig = this;\n", - "\n", - " this.waiting = false;\n", - "\n", - " this.ws.onopen = function () {\n", - " fig.send_message('supports_binary', { value: fig.supports_binary });\n", - " fig.send_message('send_image_mode', {});\n", - " if (fig.ratio !== 1) {\n", - " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", - " }\n", - " fig.send_message('refresh', {});\n", - " };\n", - "\n", - " this.imageObj.onload = function () {\n", - " if (fig.image_mode === 'full') {\n", - " // Full images could contain transparency (where diff images\n", - " // almost always do), so we need to clear the canvas so that\n", - " // there is no ghosting.\n", - " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", - " }\n", - " fig.context.drawImage(fig.imageObj, 0, 0);\n", - " };\n", - "\n", - " this.imageObj.onunload = function () {\n", - " fig.ws.close();\n", - " };\n", - "\n", - " this.ws.onmessage = this._make_on_message_function(this);\n", - "\n", - " this.ondownload = ondownload;\n", - "};\n", - "\n", - "mpl.figure.prototype._init_header = function () {\n", - " var titlebar = document.createElement('div');\n", - " titlebar.classList =\n", - " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", - " var titletext = document.createElement('div');\n", - " titletext.classList = 'ui-dialog-title';\n", - " titletext.setAttribute(\n", - " 'style',\n", - " 'width: 100%; text-align: center; padding: 3px;'\n", - " );\n", - " titlebar.appendChild(titletext);\n", - " this.root.appendChild(titlebar);\n", - " this.header = titletext;\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._init_canvas = function () {\n", - " var fig = this;\n", - "\n", - " var canvas_div = (this.canvas_div = document.createElement('div'));\n", - " canvas_div.setAttribute(\n", - " 'style',\n", - " 'border: 1px solid #ddd;' +\n", - " 'box-sizing: content-box;' +\n", - " 'clear: both;' +\n", - " 'min-height: 1px;' +\n", - " 'min-width: 1px;' +\n", - " 'outline: 0;' +\n", - " 'overflow: hidden;' +\n", - " 'position: relative;' +\n", - " 'resize: both;'\n", - " );\n", - "\n", - " function on_keyboard_event_closure(name) {\n", - " return function (event) {\n", - " return fig.key_event(event, name);\n", - " };\n", - " }\n", - "\n", - " canvas_div.addEventListener(\n", - " 'keydown',\n", - " on_keyboard_event_closure('key_press')\n", - " );\n", - " canvas_div.addEventListener(\n", - " 'keyup',\n", - " on_keyboard_event_closure('key_release')\n", - " );\n", - "\n", - " this._canvas_extra_style(canvas_div);\n", - " this.root.appendChild(canvas_div);\n", - "\n", - " var canvas = (this.canvas = document.createElement('canvas'));\n", - " canvas.classList.add('mpl-canvas');\n", - " canvas.setAttribute('style', 'box-sizing: content-box;');\n", - "\n", - " this.context = canvas.getContext('2d');\n", - "\n", - " var backingStore =\n", - " this.context.backingStorePixelRatio ||\n", - " this.context.webkitBackingStorePixelRatio ||\n", - " this.context.mozBackingStorePixelRatio ||\n", - " this.context.msBackingStorePixelRatio ||\n", - " this.context.oBackingStorePixelRatio ||\n", - " this.context.backingStorePixelRatio ||\n", - " 1;\n", - "\n", - " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", - "\n", - " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", - " 'canvas'\n", - " ));\n", - " rubberband_canvas.setAttribute(\n", - " 'style',\n", - " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", - " );\n", - "\n", - " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", - " if (this.ResizeObserver === undefined) {\n", - " if (window.ResizeObserver !== undefined) {\n", - " this.ResizeObserver = window.ResizeObserver;\n", - " } else {\n", - " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", - " this.ResizeObserver = obs.ResizeObserver;\n", - " }\n", - " }\n", - "\n", - " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", - " var nentries = entries.length;\n", - " for (var i = 0; i < nentries; i++) {\n", - " var entry = entries[i];\n", - " var width, height;\n", - " if (entry.contentBoxSize) {\n", - " if (entry.contentBoxSize instanceof Array) {\n", - " // Chrome 84 implements new version of spec.\n", - " width = entry.contentBoxSize[0].inlineSize;\n", - " height = entry.contentBoxSize[0].blockSize;\n", - " } else {\n", - " // Firefox implements old version of spec.\n", - " width = entry.contentBoxSize.inlineSize;\n", - " height = entry.contentBoxSize.blockSize;\n", - " }\n", - " } else {\n", - " // Chrome <84 implements even older version of spec.\n", - " width = entry.contentRect.width;\n", - " height = entry.contentRect.height;\n", - " }\n", - "\n", - " // Keep the size of the canvas and rubber band canvas in sync with\n", - " // the canvas container.\n", - " if (entry.devicePixelContentBoxSize) {\n", - " // Chrome 84 implements new version of spec.\n", - " canvas.setAttribute(\n", - " 'width',\n", - " entry.devicePixelContentBoxSize[0].inlineSize\n", - " );\n", - " canvas.setAttribute(\n", - " 'height',\n", - " entry.devicePixelContentBoxSize[0].blockSize\n", - " );\n", - " } else {\n", - " canvas.setAttribute('width', width * fig.ratio);\n", - " canvas.setAttribute('height', height * fig.ratio);\n", - " }\n", - " canvas.setAttribute(\n", - " 'style',\n", - " 'width: ' + width + 'px; height: ' + height + 'px;'\n", - " );\n", - "\n", - " rubberband_canvas.setAttribute('width', width);\n", - " rubberband_canvas.setAttribute('height', height);\n", - "\n", - " // And update the size in Python. We ignore the initial 0/0 size\n", - " // that occurs as the element is placed into the DOM, which should\n", - " // otherwise not happen due to the minimum size styling.\n", - " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", - " fig.request_resize(width, height);\n", - " }\n", - " }\n", - " });\n", - " this.resizeObserverInstance.observe(canvas_div);\n", - "\n", - " function on_mouse_event_closure(name) {\n", - " return function (event) {\n", - " return fig.mouse_event(event, name);\n", - " };\n", - " }\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mousedown',\n", - " on_mouse_event_closure('button_press')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseup',\n", - " on_mouse_event_closure('button_release')\n", - " );\n", - " // Throttle sequential mouse events to 1 every 20ms.\n", - " rubberband_canvas.addEventListener(\n", - " 'mousemove',\n", - " on_mouse_event_closure('motion_notify')\n", - " );\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseenter',\n", - " on_mouse_event_closure('figure_enter')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseleave',\n", - " on_mouse_event_closure('figure_leave')\n", - " );\n", - "\n", - " canvas_div.addEventListener('wheel', function (event) {\n", - " if (event.deltaY < 0) {\n", - " event.step = 1;\n", - " } else {\n", - " event.step = -1;\n", - " }\n", - " on_mouse_event_closure('scroll')(event);\n", - " });\n", - "\n", - " canvas_div.appendChild(canvas);\n", - " canvas_div.appendChild(rubberband_canvas);\n", - "\n", - " this.rubberband_context = rubberband_canvas.getContext('2d');\n", - " this.rubberband_context.strokeStyle = '#000000';\n", - "\n", - " this._resize_canvas = function (width, height, forward) {\n", - " if (forward) {\n", - " canvas_div.style.width = width + 'px';\n", - " canvas_div.style.height = height + 'px';\n", - " }\n", - " };\n", - "\n", - " // Disable right mouse context menu.\n", - " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", - " event.preventDefault();\n", - " return false;\n", - " });\n", - "\n", - " function set_focus() {\n", - " canvas.focus();\n", - " canvas_div.focus();\n", - " }\n", - "\n", - " window.setTimeout(set_focus, 100);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'mpl-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " continue;\n", - " }\n", - "\n", - " var button = (fig.buttons[name] = document.createElement('button'));\n", - " button.classList = 'mpl-widget';\n", - " button.setAttribute('role', 'button');\n", - " button.setAttribute('aria-disabled', 'false');\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - "\n", - " var icon_img = document.createElement('img');\n", - " icon_img.src = '_images/' + image + '.png';\n", - " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", - " icon_img.alt = tooltip;\n", - " button.appendChild(icon_img);\n", - "\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " var fmt_picker = document.createElement('select');\n", - " fmt_picker.classList = 'mpl-widget';\n", - " toolbar.appendChild(fmt_picker);\n", - " this.format_dropdown = fmt_picker;\n", - "\n", - " for (var ind in mpl.extensions) {\n", - " var fmt = mpl.extensions[ind];\n", - " var option = document.createElement('option');\n", - " option.selected = fmt === mpl.default_extension;\n", - " option.innerHTML = fmt;\n", - " fmt_picker.appendChild(option);\n", - " }\n", - "\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "};\n", - "\n", - "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", - " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", - " // which will in turn request a refresh of the image.\n", - " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", - "};\n", - "\n", - "mpl.figure.prototype.send_message = function (type, properties) {\n", - " properties['type'] = type;\n", - " properties['figure_id'] = this.id;\n", - " this.ws.send(JSON.stringify(properties));\n", - "};\n", - "\n", - "mpl.figure.prototype.send_draw_message = function () {\n", - " if (!this.waiting) {\n", - " this.waiting = true;\n", - " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " var format_dropdown = fig.format_dropdown;\n", - " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", - " fig.ondownload(fig, format);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", - " var size = msg['size'];\n", - " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", - " fig._resize_canvas(size[0], size[1], msg['forward']);\n", - " fig.send_message('refresh', {});\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", - " var x0 = msg['x0'] / fig.ratio;\n", - " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", - " var x1 = msg['x1'] / fig.ratio;\n", - " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", - " x0 = Math.floor(x0) + 0.5;\n", - " y0 = Math.floor(y0) + 0.5;\n", - " x1 = Math.floor(x1) + 0.5;\n", - " y1 = Math.floor(y1) + 0.5;\n", - " var min_x = Math.min(x0, x1);\n", - " var min_y = Math.min(y0, y1);\n", - " var width = Math.abs(x1 - x0);\n", - " var height = Math.abs(y1 - y0);\n", - "\n", - " fig.rubberband_context.clearRect(\n", - " 0,\n", - " 0,\n", - " fig.canvas.width / fig.ratio,\n", - " fig.canvas.height / fig.ratio\n", - " );\n", - "\n", - " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", - " // Updates the figure title.\n", - " fig.header.textContent = msg['label'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", - " var cursor = msg['cursor'];\n", - " switch (cursor) {\n", - " case 0:\n", - " cursor = 'pointer';\n", - " break;\n", - " case 1:\n", - " cursor = 'default';\n", - " break;\n", - " case 2:\n", - " cursor = 'crosshair';\n", - " break;\n", - " case 3:\n", - " cursor = 'move';\n", - " break;\n", - " }\n", - " fig.rubberband_canvas.style.cursor = cursor;\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_message = function (fig, msg) {\n", - " fig.message.textContent = msg['message'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", - " // Request the server to send over a new figure.\n", - " fig.send_draw_message();\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", - " fig.image_mode = msg['mode'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", - " for (var key in msg) {\n", - " if (!(key in fig.buttons)) {\n", - " continue;\n", - " }\n", - " fig.buttons[key].disabled = !msg[key];\n", - " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", - " if (msg['mode'] === 'PAN') {\n", - " fig.buttons['Pan'].classList.add('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " } else if (msg['mode'] === 'ZOOM') {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.add('active');\n", - " } else {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Called whenever the canvas gets updated.\n", - " this.send_message('ack', {});\n", - "};\n", - "\n", - "// A function to construct a web socket function for onmessage handling.\n", - "// Called in the figure constructor.\n", - "mpl.figure.prototype._make_on_message_function = function (fig) {\n", - " return function socket_on_message(evt) {\n", - " if (evt.data instanceof Blob) {\n", - " /* FIXME: We get \"Resource interpreted as Image but\n", - " * transferred with MIME type text/plain:\" errors on\n", - " * Chrome. But how to set the MIME type? It doesn't seem\n", - " * to be part of the websocket stream */\n", - " evt.data.type = 'image/png';\n", - "\n", - " /* Free the memory for the previous frames */\n", - " if (fig.imageObj.src) {\n", - " (window.URL || window.webkitURL).revokeObjectURL(\n", - " fig.imageObj.src\n", - " );\n", - " }\n", - "\n", - " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", - " evt.data\n", - " );\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " } else if (\n", - " typeof evt.data === 'string' &&\n", - " evt.data.slice(0, 21) === 'data:image/png;base64'\n", - " ) {\n", - " fig.imageObj.src = evt.data;\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " }\n", - "\n", - " var msg = JSON.parse(evt.data);\n", - " var msg_type = msg['type'];\n", - "\n", - " // Call the \"handle_{type}\" callback, which takes\n", - " // the figure and JSON message as its only arguments.\n", - " try {\n", - " var callback = fig['handle_' + msg_type];\n", - " } catch (e) {\n", - " console.log(\n", - " \"No handler for the '\" + msg_type + \"' message type: \",\n", - " msg\n", - " );\n", - " return;\n", - " }\n", - "\n", - " if (callback) {\n", - " try {\n", - " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", - " callback(fig, msg);\n", - " } catch (e) {\n", - " console.log(\n", - " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", - " e,\n", - " e.stack,\n", - " msg\n", - " );\n", - " }\n", - " }\n", - " };\n", - "};\n", - "\n", - "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", - "mpl.findpos = function (e) {\n", - " //this section is from http://www.quirksmode.org/js/events_properties.html\n", - " var targ;\n", - " if (!e) {\n", - " e = window.event;\n", - " }\n", - " if (e.target) {\n", - " targ = e.target;\n", - " } else if (e.srcElement) {\n", - " targ = e.srcElement;\n", - " }\n", - " if (targ.nodeType === 3) {\n", - " // defeat Safari bug\n", - " targ = targ.parentNode;\n", - " }\n", - "\n", - " // pageX,Y are the mouse positions relative to the document\n", - " var boundingRect = targ.getBoundingClientRect();\n", - " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", - " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", - "\n", - " return { x: x, y: y };\n", - "};\n", - "\n", - "/*\n", - " * return a copy of an object with only non-object keys\n", - " * we need this to avoid circular references\n", - " * http://stackoverflow.com/a/24161582/3208463\n", - " */\n", - "function simpleKeys(original) {\n", - " return Object.keys(original).reduce(function (obj, key) {\n", - " if (typeof original[key] !== 'object') {\n", - " obj[key] = original[key];\n", - " }\n", - " return obj;\n", - " }, {});\n", - "}\n", - "\n", - "mpl.figure.prototype.mouse_event = function (event, name) {\n", - " var canvas_pos = mpl.findpos(event);\n", - "\n", - " if (name === 'button_press') {\n", - " this.canvas.focus();\n", - " this.canvas_div.focus();\n", - " }\n", - "\n", - " var x = canvas_pos.x * this.ratio;\n", - " var y = canvas_pos.y * this.ratio;\n", - "\n", - " this.send_message(name, {\n", - " x: x,\n", - " y: y,\n", - " button: event.button,\n", - " step: event.step,\n", - " guiEvent: simpleKeys(event),\n", - " });\n", - "\n", - " /* This prevents the web browser from automatically changing to\n", - " * the text insertion cursor when the button is pressed. We want\n", - " * to control all of the cursor setting manually through the\n", - " * 'cursor' event from matplotlib */\n", - " event.preventDefault();\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", - " // Handle any extra behaviour associated with a key event\n", - "};\n", - "\n", - "mpl.figure.prototype.key_event = function (event, name) {\n", - " // Prevent repeat events\n", - " if (name === 'key_press') {\n", - " if (event.which === this._key) {\n", - " return;\n", - " } else {\n", - " this._key = event.which;\n", - " }\n", - " }\n", - " if (name === 'key_release') {\n", - " this._key = null;\n", - " }\n", - "\n", - " var value = '';\n", - " if (event.ctrlKey && event.which !== 17) {\n", - " value += 'ctrl+';\n", - " }\n", - " if (event.altKey && event.which !== 18) {\n", - " value += 'alt+';\n", - " }\n", - " if (event.shiftKey && event.which !== 16) {\n", - " value += 'shift+';\n", - " }\n", - "\n", - " value += 'k';\n", - " value += event.which.toString();\n", - "\n", - " this._key_event_extra(event, name);\n", - "\n", - " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", - " if (name === 'download') {\n", - " this.handle_save(this, null);\n", - " } else {\n", - " this.send_message('toolbar_button', { name: name });\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", - " this.message.textContent = tooltip;\n", - "};\n", - "\n", - "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", - "// prettier-ignore\n", - "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", - "\n", - "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", - "\n", - "mpl.default_extension = \"png\";/* global mpl */\n", - "\n", - "var comm_websocket_adapter = function (comm) {\n", - " // Create a \"websocket\"-like object which calls the given IPython comm\n", - " // object with the appropriate methods. Currently this is a non binary\n", - " // socket, so there is still some room for performance tuning.\n", - " var ws = {};\n", - "\n", - " ws.close = function () {\n", - " comm.close();\n", - " };\n", - " ws.send = function (m) {\n", - " //console.log('sending', m);\n", - " comm.send(m);\n", - " };\n", - " // Register the callback with on_msg.\n", - " comm.on_msg(function (msg) {\n", - " //console.log('receiving', msg['content']['data'], msg);\n", - " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", - " ws.onmessage(msg['content']['data']);\n", - " });\n", - " return ws;\n", - "};\n", - "\n", - "mpl.mpl_figure_comm = function (comm, msg) {\n", - " // This is the function which gets called when the mpl process\n", - " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", - "\n", - " var id = msg.content.data.id;\n", - " // Get hold of the div created by the display call when the Comm\n", - " // socket was opened in Python.\n", - " var element = document.getElementById(id);\n", - " var ws_proxy = comm_websocket_adapter(comm);\n", - "\n", - " function ondownload(figure, _format) {\n", - " window.open(figure.canvas.toDataURL());\n", - " }\n", - "\n", - " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", - "\n", - " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", - " // web socket which is closed, not our websocket->open comm proxy.\n", - " ws_proxy.onopen();\n", - "\n", - " fig.parent_element = element;\n", - " fig.cell_info = mpl.find_output_cell(\"
\");\n", - " if (!fig.cell_info) {\n", - " console.error('Failed to find cell for figure', id, fig);\n", - " return;\n", - " }\n", - " fig.cell_info[0].output_area.element.on(\n", - " 'cleared',\n", - " { fig: fig },\n", - " fig._remove_fig_handler\n", - " );\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_close = function (fig, msg) {\n", - " var width = fig.canvas.width / fig.ratio;\n", - " fig.cell_info[0].output_area.element.off(\n", - " 'cleared',\n", - " fig._remove_fig_handler\n", - " );\n", - " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", - "\n", - " // Update the output cell to use the data from the current canvas.\n", - " fig.push_to_output();\n", - " var dataURL = fig.canvas.toDataURL();\n", - " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", - " // the notebook keyboard shortcuts fail.\n", - " IPython.keyboard_manager.enable();\n", - " fig.parent_element.innerHTML =\n", - " '';\n", - " fig.close_ws(fig, msg);\n", - "};\n", - "\n", - "mpl.figure.prototype.close_ws = function (fig, msg) {\n", - " fig.send_message('closing', msg);\n", - " // fig.ws.close()\n", - "};\n", - "\n", - "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", - " // Turn the data on the canvas into data in the output cell.\n", - " var width = this.canvas.width / this.ratio;\n", - " var dataURL = this.canvas.toDataURL();\n", - " this.cell_info[1]['text/html'] =\n", - " '';\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Tell IPython that the notebook contents must change.\n", - " IPython.notebook.set_dirty(true);\n", - " this.send_message('ack', {});\n", - " var fig = this;\n", - " // Wait a second, then push the new image to the DOM so\n", - " // that it is saved nicely (might be nice to debounce this).\n", - " setTimeout(function () {\n", - " fig.push_to_output();\n", - " }, 1000);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'btn-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " var button;\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " continue;\n", - " }\n", - "\n", - " button = fig.buttons[name] = document.createElement('button');\n", - " button.classList = 'btn btn-default';\n", - " button.href = '#';\n", - " button.title = name;\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " // Add the status bar.\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message pull-right';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "\n", - " // Add the close button to the window.\n", - " var buttongrp = document.createElement('div');\n", - " buttongrp.classList = 'btn-group inline pull-right';\n", - " button = document.createElement('button');\n", - " button.classList = 'btn btn-mini btn-primary';\n", - " button.href = '#';\n", - " button.title = 'Stop Interaction';\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', function (_evt) {\n", - " fig.handle_close(fig, {});\n", - " });\n", - " button.addEventListener(\n", - " 'mouseover',\n", - " on_mouseover_closure('Stop Interaction')\n", - " );\n", - " buttongrp.appendChild(button);\n", - " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", - " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", - "};\n", - "\n", - "mpl.figure.prototype._remove_fig_handler = function (event) {\n", - " var fig = event.data.fig;\n", - " if (event.target !== this) {\n", - " // Ignore bubbled events from children.\n", - " return;\n", - " }\n", - " fig.close_ws(fig, {});\n", - "};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (el) {\n", - " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (el) {\n", - " // this is important to make the div 'focusable\n", - " el.setAttribute('tabindex', 0);\n", - " // reach out to IPython and tell the keyboard manager to turn it's self\n", - " // off when our div gets focus\n", - "\n", - " // location in version 3\n", - " if (IPython.notebook.keyboard_manager) {\n", - " IPython.notebook.keyboard_manager.register_events(el);\n", - " } else {\n", - " // location in version 2\n", - " IPython.keyboard_manager.register_events(el);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", - " var manager = IPython.notebook.keyboard_manager;\n", - " if (!manager) {\n", - " manager = IPython.keyboard_manager;\n", - " }\n", - "\n", - " // Check for shift+enter\n", - " if (event.shiftKey && event.which === 13) {\n", - " this.canvas_div.blur();\n", - " // select the cell after this one\n", - " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", - " IPython.notebook.select(index + 1);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " fig.ondownload(fig, null);\n", - "};\n", - "\n", - "mpl.find_output_cell = function (html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i = 0; i < ncells; i++) {\n", - " var cell = cells[i];\n", - " if (cell.cell_type === 'code') {\n", - " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", - " var data = cell.output_area.outputs[j];\n", - " if (data.data) {\n", - " // IPython >= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] === html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "};\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel !== null) {\n", - " IPython.notebook.kernel.comm_manager.register_target(\n", - " 'matplotlib',\n", - " mpl.mpl_figure_comm\n", - " );\n", - "}\n" - ], + "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n if (typeof WebSocket !== 'undefined') {\n return WebSocket;\n } else if (typeof MozWebSocket !== 'undefined') {\n return MozWebSocket;\n } else {\n alert(\n 'Your browser does not have WebSocket support. ' +\n 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n 'Firefox 4 and 5 are also supported but you ' +\n 'have to enable WebSockets in about:config.'\n );\n }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n this.id = figure_id;\n\n this.ws = websocket;\n\n this.supports_binary = this.ws.binaryType !== undefined;\n\n if (!this.supports_binary) {\n var warnings = document.getElementById('mpl-warnings');\n if (warnings) {\n warnings.style.display = 'block';\n warnings.textContent =\n 'This browser does not support binary websocket messages. ' +\n 'Performance may be slow.';\n }\n }\n\n this.imageObj = new Image();\n\n this.context = undefined;\n this.message = undefined;\n this.canvas = undefined;\n this.rubberband_canvas = undefined;\n this.rubberband_context = undefined;\n this.format_dropdown = undefined;\n\n this.image_mode = 'full';\n\n this.root = document.createElement('div');\n this.root.setAttribute('style', 'display: inline-block');\n this._root_extra_style(this.root);\n\n parent_element.appendChild(this.root);\n\n this._init_header(this);\n this._init_canvas(this);\n this._init_toolbar(this);\n\n var fig = this;\n\n this.waiting = false;\n\n this.ws.onopen = function () {\n fig.send_message('supports_binary', { value: fig.supports_binary });\n fig.send_message('send_image_mode', {});\n if (fig.ratio !== 1) {\n fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n }\n fig.send_message('refresh', {});\n };\n\n this.imageObj.onload = function () {\n if (fig.image_mode === 'full') {\n // Full images could contain transparency (where diff images\n // almost always do), so we need to clear the canvas so that\n // there is no ghosting.\n fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n }\n fig.context.drawImage(fig.imageObj, 0, 0);\n };\n\n this.imageObj.onunload = function () {\n fig.ws.close();\n };\n\n this.ws.onmessage = this._make_on_message_function(this);\n\n this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n var titlebar = document.createElement('div');\n titlebar.classList =\n 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n var titletext = document.createElement('div');\n titletext.classList = 'ui-dialog-title';\n titletext.setAttribute(\n 'style',\n 'width: 100%; text-align: center; padding: 3px;'\n );\n titlebar.appendChild(titletext);\n this.root.appendChild(titlebar);\n this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n var fig = this;\n\n var canvas_div = (this.canvas_div = document.createElement('div'));\n canvas_div.setAttribute(\n 'style',\n 'border: 1px solid #ddd;' +\n 'box-sizing: content-box;' +\n 'clear: both;' +\n 'min-height: 1px;' +\n 'min-width: 1px;' +\n 'outline: 0;' +\n 'overflow: hidden;' +\n 'position: relative;' +\n 'resize: both;'\n );\n\n function on_keyboard_event_closure(name) {\n return function (event) {\n return fig.key_event(event, name);\n };\n }\n\n canvas_div.addEventListener(\n 'keydown',\n on_keyboard_event_closure('key_press')\n );\n canvas_div.addEventListener(\n 'keyup',\n on_keyboard_event_closure('key_release')\n );\n\n this._canvas_extra_style(canvas_div);\n this.root.appendChild(canvas_div);\n\n var canvas = (this.canvas = document.createElement('canvas'));\n canvas.classList.add('mpl-canvas');\n canvas.setAttribute('style', 'box-sizing: content-box;');\n\n this.context = canvas.getContext('2d');\n\n var backingStore =\n this.context.backingStorePixelRatio ||\n this.context.webkitBackingStorePixelRatio ||\n this.context.mozBackingStorePixelRatio ||\n this.context.msBackingStorePixelRatio ||\n this.context.oBackingStorePixelRatio ||\n this.context.backingStorePixelRatio ||\n 1;\n\n this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n 'canvas'\n ));\n rubberband_canvas.setAttribute(\n 'style',\n 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n );\n\n // Apply a ponyfill if ResizeObserver is not implemented by browser.\n if (this.ResizeObserver === undefined) {\n if (window.ResizeObserver !== undefined) {\n this.ResizeObserver = window.ResizeObserver;\n } else {\n var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n this.ResizeObserver = obs.ResizeObserver;\n }\n }\n\n this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n var nentries = entries.length;\n for (var i = 0; i < nentries; i++) {\n var entry = entries[i];\n var width, height;\n if (entry.contentBoxSize) {\n if (entry.contentBoxSize instanceof Array) {\n // Chrome 84 implements new version of spec.\n width = entry.contentBoxSize[0].inlineSize;\n height = entry.contentBoxSize[0].blockSize;\n } else {\n // Firefox implements old version of spec.\n width = entry.contentBoxSize.inlineSize;\n height = entry.contentBoxSize.blockSize;\n }\n } else {\n // Chrome <84 implements even older version of spec.\n width = entry.contentRect.width;\n height = entry.contentRect.height;\n }\n\n // Keep the size of the canvas and rubber band canvas in sync with\n // the canvas container.\n if (entry.devicePixelContentBoxSize) {\n // Chrome 84 implements new version of spec.\n canvas.setAttribute(\n 'width',\n entry.devicePixelContentBoxSize[0].inlineSize\n );\n canvas.setAttribute(\n 'height',\n entry.devicePixelContentBoxSize[0].blockSize\n );\n } else {\n canvas.setAttribute('width', width * fig.ratio);\n canvas.setAttribute('height', height * fig.ratio);\n }\n canvas.setAttribute(\n 'style',\n 'width: ' + width + 'px; height: ' + height + 'px;'\n );\n\n rubberband_canvas.setAttribute('width', width);\n rubberband_canvas.setAttribute('height', height);\n\n // And update the size in Python. We ignore the initial 0/0 size\n // that occurs as the element is placed into the DOM, which should\n // otherwise not happen due to the minimum size styling.\n if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n fig.request_resize(width, height);\n }\n }\n });\n this.resizeObserverInstance.observe(canvas_div);\n\n function on_mouse_event_closure(name) {\n return function (event) {\n return fig.mouse_event(event, name);\n };\n }\n\n rubberband_canvas.addEventListener(\n 'mousedown',\n on_mouse_event_closure('button_press')\n );\n rubberband_canvas.addEventListener(\n 'mouseup',\n on_mouse_event_closure('button_release')\n );\n // Throttle sequential mouse events to 1 every 20ms.\n rubberband_canvas.addEventListener(\n 'mousemove',\n on_mouse_event_closure('motion_notify')\n );\n\n rubberband_canvas.addEventListener(\n 'mouseenter',\n on_mouse_event_closure('figure_enter')\n );\n rubberband_canvas.addEventListener(\n 'mouseleave',\n on_mouse_event_closure('figure_leave')\n );\n\n canvas_div.addEventListener('wheel', function (event) {\n if (event.deltaY < 0) {\n event.step = 1;\n } else {\n event.step = -1;\n }\n on_mouse_event_closure('scroll')(event);\n });\n\n canvas_div.appendChild(canvas);\n canvas_div.appendChild(rubberband_canvas);\n\n this.rubberband_context = rubberband_canvas.getContext('2d');\n this.rubberband_context.strokeStyle = '#000000';\n\n this._resize_canvas = function (width, height, forward) {\n if (forward) {\n canvas_div.style.width = width + 'px';\n canvas_div.style.height = height + 'px';\n }\n };\n\n // Disable right mouse context menu.\n this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n event.preventDefault();\n return false;\n });\n\n function set_focus() {\n canvas.focus();\n canvas_div.focus();\n }\n\n window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'mpl-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n continue;\n }\n\n var button = (fig.buttons[name] = document.createElement('button'));\n button.classList = 'mpl-widget';\n button.setAttribute('role', 'button');\n button.setAttribute('aria-disabled', 'false');\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n var icon_img = document.createElement('img');\n icon_img.src = '_images/' + image + '.png';\n icon_img.srcset = '_images/' + image + '_large.png 2x';\n icon_img.alt = tooltip;\n button.appendChild(icon_img);\n\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n var fmt_picker = document.createElement('select');\n fmt_picker.classList = 'mpl-widget';\n toolbar.appendChild(fmt_picker);\n this.format_dropdown = fmt_picker;\n\n for (var ind in mpl.extensions) {\n var fmt = mpl.extensions[ind];\n var option = document.createElement('option');\n option.selected = fmt === mpl.default_extension;\n option.innerHTML = fmt;\n fmt_picker.appendChild(option);\n }\n\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n // which will in turn request a refresh of the image.\n this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n properties['type'] = type;\n properties['figure_id'] = this.id;\n this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n if (!this.waiting) {\n this.waiting = true;\n this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n var format_dropdown = fig.format_dropdown;\n var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n var size = msg['size'];\n if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n fig._resize_canvas(size[0], size[1], msg['forward']);\n fig.send_message('refresh', {});\n }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n var x0 = msg['x0'] / fig.ratio;\n var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n var x1 = msg['x1'] / fig.ratio;\n var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n x0 = Math.floor(x0) + 0.5;\n y0 = Math.floor(y0) + 0.5;\n x1 = Math.floor(x1) + 0.5;\n y1 = Math.floor(y1) + 0.5;\n var min_x = Math.min(x0, x1);\n var min_y = Math.min(y0, y1);\n var width = Math.abs(x1 - x0);\n var height = Math.abs(y1 - y0);\n\n fig.rubberband_context.clearRect(\n 0,\n 0,\n fig.canvas.width / fig.ratio,\n fig.canvas.height / fig.ratio\n );\n\n fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n // Updates the figure title.\n fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n var cursor = msg['cursor'];\n switch (cursor) {\n case 0:\n cursor = 'pointer';\n break;\n case 1:\n cursor = 'default';\n break;\n case 2:\n cursor = 'crosshair';\n break;\n case 3:\n cursor = 'move';\n break;\n }\n fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n // Request the server to send over a new figure.\n fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n for (var key in msg) {\n if (!(key in fig.buttons)) {\n continue;\n }\n fig.buttons[key].disabled = !msg[key];\n fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n if (msg['mode'] === 'PAN') {\n fig.buttons['Pan'].classList.add('active');\n fig.buttons['Zoom'].classList.remove('active');\n } else if (msg['mode'] === 'ZOOM') {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.add('active');\n } else {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.remove('active');\n }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Called whenever the canvas gets updated.\n this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n return function socket_on_message(evt) {\n if (evt.data instanceof Blob) {\n /* FIXME: We get \"Resource interpreted as Image but\n * transferred with MIME type text/plain:\" errors on\n * Chrome. But how to set the MIME type? It doesn't seem\n * to be part of the websocket stream */\n evt.data.type = 'image/png';\n\n /* Free the memory for the previous frames */\n if (fig.imageObj.src) {\n (window.URL || window.webkitURL).revokeObjectURL(\n fig.imageObj.src\n );\n }\n\n fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n evt.data\n );\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n } else if (\n typeof evt.data === 'string' &&\n evt.data.slice(0, 21) === 'data:image/png;base64'\n ) {\n fig.imageObj.src = evt.data;\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n }\n\n var msg = JSON.parse(evt.data);\n var msg_type = msg['type'];\n\n // Call the \"handle_{type}\" callback, which takes\n // the figure and JSON message as its only arguments.\n try {\n var callback = fig['handle_' + msg_type];\n } catch (e) {\n console.log(\n \"No handler for the '\" + msg_type + \"' message type: \",\n msg\n );\n return;\n }\n\n if (callback) {\n try {\n // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n callback(fig, msg);\n } catch (e) {\n console.log(\n \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n e,\n e.stack,\n msg\n );\n }\n }\n };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n //this section is from http://www.quirksmode.org/js/events_properties.html\n var targ;\n if (!e) {\n e = window.event;\n }\n if (e.target) {\n targ = e.target;\n } else if (e.srcElement) {\n targ = e.srcElement;\n }\n if (targ.nodeType === 3) {\n // defeat Safari bug\n targ = targ.parentNode;\n }\n\n // pageX,Y are the mouse positions relative to the document\n var boundingRect = targ.getBoundingClientRect();\n var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n return Object.keys(original).reduce(function (obj, key) {\n if (typeof original[key] !== 'object') {\n obj[key] = original[key];\n }\n return obj;\n }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n var canvas_pos = mpl.findpos(event);\n\n if (name === 'button_press') {\n this.canvas.focus();\n this.canvas_div.focus();\n }\n\n var x = canvas_pos.x * this.ratio;\n var y = canvas_pos.y * this.ratio;\n\n this.send_message(name, {\n x: x,\n y: y,\n button: event.button,\n step: event.step,\n guiEvent: simpleKeys(event),\n });\n\n /* This prevents the web browser from automatically changing to\n * the text insertion cursor when the button is pressed. We want\n * to control all of the cursor setting manually through the\n * 'cursor' event from matplotlib */\n event.preventDefault();\n return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n // Prevent repeat events\n if (name === 'key_press') {\n if (event.which === this._key) {\n return;\n } else {\n this._key = event.which;\n }\n }\n if (name === 'key_release') {\n this._key = null;\n }\n\n var value = '';\n if (event.ctrlKey && event.which !== 17) {\n value += 'ctrl+';\n }\n if (event.altKey && event.which !== 18) {\n value += 'alt+';\n }\n if (event.shiftKey && event.which !== 16) {\n value += 'shift+';\n }\n\n value += 'k';\n value += event.which.toString();\n\n this._key_event_extra(event, name);\n\n this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n if (name === 'download') {\n this.handle_save(this, null);\n } else {\n this.send_message('toolbar_button', { name: name });\n }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\nmpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n\nmpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n // Create a \"websocket\"-like object which calls the given IPython comm\n // object with the appropriate methods. Currently this is a non binary\n // socket, so there is still some room for performance tuning.\n var ws = {};\n\n ws.close = function () {\n comm.close();\n };\n ws.send = function (m) {\n //console.log('sending', m);\n comm.send(m);\n };\n // Register the callback with on_msg.\n comm.on_msg(function (msg) {\n //console.log('receiving', msg['content']['data'], msg);\n // Pass the mpl event to the overridden (by mpl) onmessage function.\n ws.onmessage(msg['content']['data']);\n });\n return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n // This is the function which gets called when the mpl process\n // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n var id = msg.content.data.id;\n // Get hold of the div created by the display call when the Comm\n // socket was opened in Python.\n var element = document.getElementById(id);\n var ws_proxy = comm_websocket_adapter(comm);\n\n function ondownload(figure, _format) {\n window.open(figure.canvas.toDataURL());\n }\n\n var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n // web socket which is closed, not our websocket->open comm proxy.\n ws_proxy.onopen();\n\n fig.parent_element = element;\n fig.cell_info = mpl.find_output_cell(\"
\");\n if (!fig.cell_info) {\n console.error('Failed to find cell for figure', id, fig);\n return;\n }\n fig.cell_info[0].output_area.element.on(\n 'cleared',\n { fig: fig },\n fig._remove_fig_handler\n );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n var width = fig.canvas.width / fig.ratio;\n fig.cell_info[0].output_area.element.off(\n 'cleared',\n fig._remove_fig_handler\n );\n fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n // Update the output cell to use the data from the current canvas.\n fig.push_to_output();\n var dataURL = fig.canvas.toDataURL();\n // Re-enable the keyboard manager in IPython - without this line, in FF,\n // the notebook keyboard shortcuts fail.\n IPython.keyboard_manager.enable();\n fig.parent_element.innerHTML =\n '';\n fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n fig.send_message('closing', msg);\n // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n // Turn the data on the canvas into data in the output cell.\n var width = this.canvas.width / this.ratio;\n var dataURL = this.canvas.toDataURL();\n this.cell_info[1]['text/html'] =\n '';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Tell IPython that the notebook contents must change.\n IPython.notebook.set_dirty(true);\n this.send_message('ack', {});\n var fig = this;\n // Wait a second, then push the new image to the DOM so\n // that it is saved nicely (might be nice to debounce this).\n setTimeout(function () {\n fig.push_to_output();\n }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'btn-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n var button;\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n continue;\n }\n\n button = fig.buttons[name] = document.createElement('button');\n button.classList = 'btn btn-default';\n button.href = '#';\n button.title = name;\n button.innerHTML = '';\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n // Add the status bar.\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message pull-right';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n\n // Add the close button to the window.\n var buttongrp = document.createElement('div');\n buttongrp.classList = 'btn-group inline pull-right';\n button = document.createElement('button');\n button.classList = 'btn btn-mini btn-primary';\n button.href = '#';\n button.title = 'Stop Interaction';\n button.innerHTML = '';\n button.addEventListener('click', function (_evt) {\n fig.handle_close(fig, {});\n });\n button.addEventListener(\n 'mouseover',\n on_mouseover_closure('Stop Interaction')\n );\n buttongrp.appendChild(button);\n var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n var fig = event.data.fig;\n if (event.target !== this) {\n // Ignore bubbled events from children.\n return;\n }\n fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n // this is important to make the div 'focusable\n el.setAttribute('tabindex', 0);\n // reach out to IPython and tell the keyboard manager to turn it's self\n // off when our div gets focus\n\n // location in version 3\n if (IPython.notebook.keyboard_manager) {\n IPython.notebook.keyboard_manager.register_events(el);\n } else {\n // location in version 2\n IPython.keyboard_manager.register_events(el);\n }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n var manager = IPython.notebook.keyboard_manager;\n if (!manager) {\n manager = IPython.keyboard_manager;\n }\n\n // Check for shift+enter\n if (event.shiftKey && event.which === 13) {\n this.canvas_div.blur();\n // select the cell after this one\n var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n IPython.notebook.select(index + 1);\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n // Return the cell and output element which can be found *uniquely* in the notebook.\n // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n // IPython event is triggered only after the cells have been serialised, which for\n // our purposes (turning an active figure into a static one), is too late.\n var cells = IPython.notebook.get_cells();\n var ncells = cells.length;\n for (var i = 0; i < ncells; i++) {\n var cell = cells[i];\n if (cell.cell_type === 'code') {\n for (var j = 0; j < cell.output_area.outputs.length; j++) {\n var data = cell.output_area.outputs[j];\n if (data.data) {\n // IPython >= 3 moved mimebundle to data attribute of output\n data = data.data;\n }\n if (data['text/html'] === html_output) {\n return [cell, data, j];\n }\n }\n }\n }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n IPython.notebook.kernel.comm_manager.register_target(\n 'matplotlib',\n mpl.mpl_figure_comm\n );\n}\n", "text/plain": [ "" ] @@ -3461,955 +617,7 @@ }, { "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "/* global mpl */\n", - "window.mpl = {};\n", - "\n", - "mpl.get_websocket_type = function () {\n", - " if (typeof WebSocket !== 'undefined') {\n", - " return WebSocket;\n", - " } else if (typeof MozWebSocket !== 'undefined') {\n", - " return MozWebSocket;\n", - " } else {\n", - " alert(\n", - " 'Your browser does not have WebSocket support. ' +\n", - " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", - " 'Firefox 4 and 5 are also supported but you ' +\n", - " 'have to enable WebSockets in about:config.'\n", - " );\n", - " }\n", - "};\n", - "\n", - "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", - " this.id = figure_id;\n", - "\n", - " this.ws = websocket;\n", - "\n", - " this.supports_binary = this.ws.binaryType !== undefined;\n", - "\n", - " if (!this.supports_binary) {\n", - " var warnings = document.getElementById('mpl-warnings');\n", - " if (warnings) {\n", - " warnings.style.display = 'block';\n", - " warnings.textContent =\n", - " 'This browser does not support binary websocket messages. ' +\n", - " 'Performance may be slow.';\n", - " }\n", - " }\n", - "\n", - " this.imageObj = new Image();\n", - "\n", - " this.context = undefined;\n", - " this.message = undefined;\n", - " this.canvas = undefined;\n", - " this.rubberband_canvas = undefined;\n", - " this.rubberband_context = undefined;\n", - " this.format_dropdown = undefined;\n", - "\n", - " this.image_mode = 'full';\n", - "\n", - " this.root = document.createElement('div');\n", - " this.root.setAttribute('style', 'display: inline-block');\n", - " this._root_extra_style(this.root);\n", - "\n", - " parent_element.appendChild(this.root);\n", - "\n", - " this._init_header(this);\n", - " this._init_canvas(this);\n", - " this._init_toolbar(this);\n", - "\n", - " var fig = this;\n", - "\n", - " this.waiting = false;\n", - "\n", - " this.ws.onopen = function () {\n", - " fig.send_message('supports_binary', { value: fig.supports_binary });\n", - " fig.send_message('send_image_mode', {});\n", - " if (fig.ratio !== 1) {\n", - " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", - " }\n", - " fig.send_message('refresh', {});\n", - " };\n", - "\n", - " this.imageObj.onload = function () {\n", - " if (fig.image_mode === 'full') {\n", - " // Full images could contain transparency (where diff images\n", - " // almost always do), so we need to clear the canvas so that\n", - " // there is no ghosting.\n", - " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", - " }\n", - " fig.context.drawImage(fig.imageObj, 0, 0);\n", - " };\n", - "\n", - " this.imageObj.onunload = function () {\n", - " fig.ws.close();\n", - " };\n", - "\n", - " this.ws.onmessage = this._make_on_message_function(this);\n", - "\n", - " this.ondownload = ondownload;\n", - "};\n", - "\n", - "mpl.figure.prototype._init_header = function () {\n", - " var titlebar = document.createElement('div');\n", - " titlebar.classList =\n", - " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", - " var titletext = document.createElement('div');\n", - " titletext.classList = 'ui-dialog-title';\n", - " titletext.setAttribute(\n", - " 'style',\n", - " 'width: 100%; text-align: center; padding: 3px;'\n", - " );\n", - " titlebar.appendChild(titletext);\n", - " this.root.appendChild(titlebar);\n", - " this.header = titletext;\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._init_canvas = function () {\n", - " var fig = this;\n", - "\n", - " var canvas_div = (this.canvas_div = document.createElement('div'));\n", - " canvas_div.setAttribute(\n", - " 'style',\n", - " 'border: 1px solid #ddd;' +\n", - " 'box-sizing: content-box;' +\n", - " 'clear: both;' +\n", - " 'min-height: 1px;' +\n", - " 'min-width: 1px;' +\n", - " 'outline: 0;' +\n", - " 'overflow: hidden;' +\n", - " 'position: relative;' +\n", - " 'resize: both;'\n", - " );\n", - "\n", - " function on_keyboard_event_closure(name) {\n", - " return function (event) {\n", - " return fig.key_event(event, name);\n", - " };\n", - " }\n", - "\n", - " canvas_div.addEventListener(\n", - " 'keydown',\n", - " on_keyboard_event_closure('key_press')\n", - " );\n", - " canvas_div.addEventListener(\n", - " 'keyup',\n", - " on_keyboard_event_closure('key_release')\n", - " );\n", - "\n", - " this._canvas_extra_style(canvas_div);\n", - " this.root.appendChild(canvas_div);\n", - "\n", - " var canvas = (this.canvas = document.createElement('canvas'));\n", - " canvas.classList.add('mpl-canvas');\n", - " canvas.setAttribute('style', 'box-sizing: content-box;');\n", - "\n", - " this.context = canvas.getContext('2d');\n", - "\n", - " var backingStore =\n", - " this.context.backingStorePixelRatio ||\n", - " this.context.webkitBackingStorePixelRatio ||\n", - " this.context.mozBackingStorePixelRatio ||\n", - " this.context.msBackingStorePixelRatio ||\n", - " this.context.oBackingStorePixelRatio ||\n", - " this.context.backingStorePixelRatio ||\n", - " 1;\n", - "\n", - " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", - "\n", - " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", - " 'canvas'\n", - " ));\n", - " rubberband_canvas.setAttribute(\n", - " 'style',\n", - " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", - " );\n", - "\n", - " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", - " if (this.ResizeObserver === undefined) {\n", - " if (window.ResizeObserver !== undefined) {\n", - " this.ResizeObserver = window.ResizeObserver;\n", - " } else {\n", - " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", - " this.ResizeObserver = obs.ResizeObserver;\n", - " }\n", - " }\n", - "\n", - " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", - " var nentries = entries.length;\n", - " for (var i = 0; i < nentries; i++) {\n", - " var entry = entries[i];\n", - " var width, height;\n", - " if (entry.contentBoxSize) {\n", - " if (entry.contentBoxSize instanceof Array) {\n", - " // Chrome 84 implements new version of spec.\n", - " width = entry.contentBoxSize[0].inlineSize;\n", - " height = entry.contentBoxSize[0].blockSize;\n", - " } else {\n", - " // Firefox implements old version of spec.\n", - " width = entry.contentBoxSize.inlineSize;\n", - " height = entry.contentBoxSize.blockSize;\n", - " }\n", - " } else {\n", - " // Chrome <84 implements even older version of spec.\n", - " width = entry.contentRect.width;\n", - " height = entry.contentRect.height;\n", - " }\n", - "\n", - " // Keep the size of the canvas and rubber band canvas in sync with\n", - " // the canvas container.\n", - " if (entry.devicePixelContentBoxSize) {\n", - " // Chrome 84 implements new version of spec.\n", - " canvas.setAttribute(\n", - " 'width',\n", - " entry.devicePixelContentBoxSize[0].inlineSize\n", - " );\n", - " canvas.setAttribute(\n", - " 'height',\n", - " entry.devicePixelContentBoxSize[0].blockSize\n", - " );\n", - " } else {\n", - " canvas.setAttribute('width', width * fig.ratio);\n", - " canvas.setAttribute('height', height * fig.ratio);\n", - " }\n", - " canvas.setAttribute(\n", - " 'style',\n", - " 'width: ' + width + 'px; height: ' + height + 'px;'\n", - " );\n", - "\n", - " rubberband_canvas.setAttribute('width', width);\n", - " rubberband_canvas.setAttribute('height', height);\n", - "\n", - " // And update the size in Python. We ignore the initial 0/0 size\n", - " // that occurs as the element is placed into the DOM, which should\n", - " // otherwise not happen due to the minimum size styling.\n", - " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", - " fig.request_resize(width, height);\n", - " }\n", - " }\n", - " });\n", - " this.resizeObserverInstance.observe(canvas_div);\n", - "\n", - " function on_mouse_event_closure(name) {\n", - " return function (event) {\n", - " return fig.mouse_event(event, name);\n", - " };\n", - " }\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mousedown',\n", - " on_mouse_event_closure('button_press')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseup',\n", - " on_mouse_event_closure('button_release')\n", - " );\n", - " // Throttle sequential mouse events to 1 every 20ms.\n", - " rubberband_canvas.addEventListener(\n", - " 'mousemove',\n", - " on_mouse_event_closure('motion_notify')\n", - " );\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseenter',\n", - " on_mouse_event_closure('figure_enter')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseleave',\n", - " on_mouse_event_closure('figure_leave')\n", - " );\n", - "\n", - " canvas_div.addEventListener('wheel', function (event) {\n", - " if (event.deltaY < 0) {\n", - " event.step = 1;\n", - " } else {\n", - " event.step = -1;\n", - " }\n", - " on_mouse_event_closure('scroll')(event);\n", - " });\n", - "\n", - " canvas_div.appendChild(canvas);\n", - " canvas_div.appendChild(rubberband_canvas);\n", - "\n", - " this.rubberband_context = rubberband_canvas.getContext('2d');\n", - " this.rubberband_context.strokeStyle = '#000000';\n", - "\n", - " this._resize_canvas = function (width, height, forward) {\n", - " if (forward) {\n", - " canvas_div.style.width = width + 'px';\n", - " canvas_div.style.height = height + 'px';\n", - " }\n", - " };\n", - "\n", - " // Disable right mouse context menu.\n", - " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", - " event.preventDefault();\n", - " return false;\n", - " });\n", - "\n", - " function set_focus() {\n", - " canvas.focus();\n", - " canvas_div.focus();\n", - " }\n", - "\n", - " window.setTimeout(set_focus, 100);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'mpl-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " continue;\n", - " }\n", - "\n", - " var button = (fig.buttons[name] = document.createElement('button'));\n", - " button.classList = 'mpl-widget';\n", - " button.setAttribute('role', 'button');\n", - " button.setAttribute('aria-disabled', 'false');\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - "\n", - " var icon_img = document.createElement('img');\n", - " icon_img.src = '_images/' + image + '.png';\n", - " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", - " icon_img.alt = tooltip;\n", - " button.appendChild(icon_img);\n", - "\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " var fmt_picker = document.createElement('select');\n", - " fmt_picker.classList = 'mpl-widget';\n", - " toolbar.appendChild(fmt_picker);\n", - " this.format_dropdown = fmt_picker;\n", - "\n", - " for (var ind in mpl.extensions) {\n", - " var fmt = mpl.extensions[ind];\n", - " var option = document.createElement('option');\n", - " option.selected = fmt === mpl.default_extension;\n", - " option.innerHTML = fmt;\n", - " fmt_picker.appendChild(option);\n", - " }\n", - "\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "};\n", - "\n", - "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", - " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", - " // which will in turn request a refresh of the image.\n", - " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", - "};\n", - "\n", - "mpl.figure.prototype.send_message = function (type, properties) {\n", - " properties['type'] = type;\n", - " properties['figure_id'] = this.id;\n", - " this.ws.send(JSON.stringify(properties));\n", - "};\n", - "\n", - "mpl.figure.prototype.send_draw_message = function () {\n", - " if (!this.waiting) {\n", - " this.waiting = true;\n", - " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " var format_dropdown = fig.format_dropdown;\n", - " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", - " fig.ondownload(fig, format);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", - " var size = msg['size'];\n", - " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", - " fig._resize_canvas(size[0], size[1], msg['forward']);\n", - " fig.send_message('refresh', {});\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", - " var x0 = msg['x0'] / fig.ratio;\n", - " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", - " var x1 = msg['x1'] / fig.ratio;\n", - " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", - " x0 = Math.floor(x0) + 0.5;\n", - " y0 = Math.floor(y0) + 0.5;\n", - " x1 = Math.floor(x1) + 0.5;\n", - " y1 = Math.floor(y1) + 0.5;\n", - " var min_x = Math.min(x0, x1);\n", - " var min_y = Math.min(y0, y1);\n", - " var width = Math.abs(x1 - x0);\n", - " var height = Math.abs(y1 - y0);\n", - "\n", - " fig.rubberband_context.clearRect(\n", - " 0,\n", - " 0,\n", - " fig.canvas.width / fig.ratio,\n", - " fig.canvas.height / fig.ratio\n", - " );\n", - "\n", - " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", - " // Updates the figure title.\n", - " fig.header.textContent = msg['label'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", - " var cursor = msg['cursor'];\n", - " switch (cursor) {\n", - " case 0:\n", - " cursor = 'pointer';\n", - " break;\n", - " case 1:\n", - " cursor = 'default';\n", - " break;\n", - " case 2:\n", - " cursor = 'crosshair';\n", - " break;\n", - " case 3:\n", - " cursor = 'move';\n", - " break;\n", - " }\n", - " fig.rubberband_canvas.style.cursor = cursor;\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_message = function (fig, msg) {\n", - " fig.message.textContent = msg['message'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", - " // Request the server to send over a new figure.\n", - " fig.send_draw_message();\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", - " fig.image_mode = msg['mode'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", - " for (var key in msg) {\n", - " if (!(key in fig.buttons)) {\n", - " continue;\n", - " }\n", - " fig.buttons[key].disabled = !msg[key];\n", - " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", - " if (msg['mode'] === 'PAN') {\n", - " fig.buttons['Pan'].classList.add('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " } else if (msg['mode'] === 'ZOOM') {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.add('active');\n", - " } else {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Called whenever the canvas gets updated.\n", - " this.send_message('ack', {});\n", - "};\n", - "\n", - "// A function to construct a web socket function for onmessage handling.\n", - "// Called in the figure constructor.\n", - "mpl.figure.prototype._make_on_message_function = function (fig) {\n", - " return function socket_on_message(evt) {\n", - " if (evt.data instanceof Blob) {\n", - " /* FIXME: We get \"Resource interpreted as Image but\n", - " * transferred with MIME type text/plain:\" errors on\n", - " * Chrome. But how to set the MIME type? It doesn't seem\n", - " * to be part of the websocket stream */\n", - " evt.data.type = 'image/png';\n", - "\n", - " /* Free the memory for the previous frames */\n", - " if (fig.imageObj.src) {\n", - " (window.URL || window.webkitURL).revokeObjectURL(\n", - " fig.imageObj.src\n", - " );\n", - " }\n", - "\n", - " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", - " evt.data\n", - " );\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " } else if (\n", - " typeof evt.data === 'string' &&\n", - " evt.data.slice(0, 21) === 'data:image/png;base64'\n", - " ) {\n", - " fig.imageObj.src = evt.data;\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " }\n", - "\n", - " var msg = JSON.parse(evt.data);\n", - " var msg_type = msg['type'];\n", - "\n", - " // Call the \"handle_{type}\" callback, which takes\n", - " // the figure and JSON message as its only arguments.\n", - " try {\n", - " var callback = fig['handle_' + msg_type];\n", - " } catch (e) {\n", - " console.log(\n", - " \"No handler for the '\" + msg_type + \"' message type: \",\n", - " msg\n", - " );\n", - " return;\n", - " }\n", - "\n", - " if (callback) {\n", - " try {\n", - " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", - " callback(fig, msg);\n", - " } catch (e) {\n", - " console.log(\n", - " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", - " e,\n", - " e.stack,\n", - " msg\n", - " );\n", - " }\n", - " }\n", - " };\n", - "};\n", - "\n", - "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", - "mpl.findpos = function (e) {\n", - " //this section is from http://www.quirksmode.org/js/events_properties.html\n", - " var targ;\n", - " if (!e) {\n", - " e = window.event;\n", - " }\n", - " if (e.target) {\n", - " targ = e.target;\n", - " } else if (e.srcElement) {\n", - " targ = e.srcElement;\n", - " }\n", - " if (targ.nodeType === 3) {\n", - " // defeat Safari bug\n", - " targ = targ.parentNode;\n", - " }\n", - "\n", - " // pageX,Y are the mouse positions relative to the document\n", - " var boundingRect = targ.getBoundingClientRect();\n", - " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", - " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", - "\n", - " return { x: x, y: y };\n", - "};\n", - "\n", - "/*\n", - " * return a copy of an object with only non-object keys\n", - " * we need this to avoid circular references\n", - " * http://stackoverflow.com/a/24161582/3208463\n", - " */\n", - "function simpleKeys(original) {\n", - " return Object.keys(original).reduce(function (obj, key) {\n", - " if (typeof original[key] !== 'object') {\n", - " obj[key] = original[key];\n", - " }\n", - " return obj;\n", - " }, {});\n", - "}\n", - "\n", - "mpl.figure.prototype.mouse_event = function (event, name) {\n", - " var canvas_pos = mpl.findpos(event);\n", - "\n", - " if (name === 'button_press') {\n", - " this.canvas.focus();\n", - " this.canvas_div.focus();\n", - " }\n", - "\n", - " var x = canvas_pos.x * this.ratio;\n", - " var y = canvas_pos.y * this.ratio;\n", - "\n", - " this.send_message(name, {\n", - " x: x,\n", - " y: y,\n", - " button: event.button,\n", - " step: event.step,\n", - " guiEvent: simpleKeys(event),\n", - " });\n", - "\n", - " /* This prevents the web browser from automatically changing to\n", - " * the text insertion cursor when the button is pressed. We want\n", - " * to control all of the cursor setting manually through the\n", - " * 'cursor' event from matplotlib */\n", - " event.preventDefault();\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", - " // Handle any extra behaviour associated with a key event\n", - "};\n", - "\n", - "mpl.figure.prototype.key_event = function (event, name) {\n", - " // Prevent repeat events\n", - " if (name === 'key_press') {\n", - " if (event.which === this._key) {\n", - " return;\n", - " } else {\n", - " this._key = event.which;\n", - " }\n", - " }\n", - " if (name === 'key_release') {\n", - " this._key = null;\n", - " }\n", - "\n", - " var value = '';\n", - " if (event.ctrlKey && event.which !== 17) {\n", - " value += 'ctrl+';\n", - " }\n", - " if (event.altKey && event.which !== 18) {\n", - " value += 'alt+';\n", - " }\n", - " if (event.shiftKey && event.which !== 16) {\n", - " value += 'shift+';\n", - " }\n", - "\n", - " value += 'k';\n", - " value += event.which.toString();\n", - "\n", - " this._key_event_extra(event, name);\n", - "\n", - " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", - " if (name === 'download') {\n", - " this.handle_save(this, null);\n", - " } else {\n", - " this.send_message('toolbar_button', { name: name });\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", - " this.message.textContent = tooltip;\n", - "};\n", - "\n", - "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", - "// prettier-ignore\n", - "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", - "\n", - "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", - "\n", - "mpl.default_extension = \"png\";/* global mpl */\n", - "\n", - "var comm_websocket_adapter = function (comm) {\n", - " // Create a \"websocket\"-like object which calls the given IPython comm\n", - " // object with the appropriate methods. Currently this is a non binary\n", - " // socket, so there is still some room for performance tuning.\n", - " var ws = {};\n", - "\n", - " ws.close = function () {\n", - " comm.close();\n", - " };\n", - " ws.send = function (m) {\n", - " //console.log('sending', m);\n", - " comm.send(m);\n", - " };\n", - " // Register the callback with on_msg.\n", - " comm.on_msg(function (msg) {\n", - " //console.log('receiving', msg['content']['data'], msg);\n", - " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", - " ws.onmessage(msg['content']['data']);\n", - " });\n", - " return ws;\n", - "};\n", - "\n", - "mpl.mpl_figure_comm = function (comm, msg) {\n", - " // This is the function which gets called when the mpl process\n", - " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", - "\n", - " var id = msg.content.data.id;\n", - " // Get hold of the div created by the display call when the Comm\n", - " // socket was opened in Python.\n", - " var element = document.getElementById(id);\n", - " var ws_proxy = comm_websocket_adapter(comm);\n", - "\n", - " function ondownload(figure, _format) {\n", - " window.open(figure.canvas.toDataURL());\n", - " }\n", - "\n", - " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", - "\n", - " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", - " // web socket which is closed, not our websocket->open comm proxy.\n", - " ws_proxy.onopen();\n", - "\n", - " fig.parent_element = element;\n", - " fig.cell_info = mpl.find_output_cell(\"
\");\n", - " if (!fig.cell_info) {\n", - " console.error('Failed to find cell for figure', id, fig);\n", - " return;\n", - " }\n", - " fig.cell_info[0].output_area.element.on(\n", - " 'cleared',\n", - " { fig: fig },\n", - " fig._remove_fig_handler\n", - " );\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_close = function (fig, msg) {\n", - " var width = fig.canvas.width / fig.ratio;\n", - " fig.cell_info[0].output_area.element.off(\n", - " 'cleared',\n", - " fig._remove_fig_handler\n", - " );\n", - " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", - "\n", - " // Update the output cell to use the data from the current canvas.\n", - " fig.push_to_output();\n", - " var dataURL = fig.canvas.toDataURL();\n", - " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", - " // the notebook keyboard shortcuts fail.\n", - " IPython.keyboard_manager.enable();\n", - " fig.parent_element.innerHTML =\n", - " '';\n", - " fig.close_ws(fig, msg);\n", - "};\n", - "\n", - "mpl.figure.prototype.close_ws = function (fig, msg) {\n", - " fig.send_message('closing', msg);\n", - " // fig.ws.close()\n", - "};\n", - "\n", - "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", - " // Turn the data on the canvas into data in the output cell.\n", - " var width = this.canvas.width / this.ratio;\n", - " var dataURL = this.canvas.toDataURL();\n", - " this.cell_info[1]['text/html'] =\n", - " '';\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Tell IPython that the notebook contents must change.\n", - " IPython.notebook.set_dirty(true);\n", - " this.send_message('ack', {});\n", - " var fig = this;\n", - " // Wait a second, then push the new image to the DOM so\n", - " // that it is saved nicely (might be nice to debounce this).\n", - " setTimeout(function () {\n", - " fig.push_to_output();\n", - " }, 1000);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'btn-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " var button;\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " continue;\n", - " }\n", - "\n", - " button = fig.buttons[name] = document.createElement('button');\n", - " button.classList = 'btn btn-default';\n", - " button.href = '#';\n", - " button.title = name;\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " // Add the status bar.\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message pull-right';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "\n", - " // Add the close button to the window.\n", - " var buttongrp = document.createElement('div');\n", - " buttongrp.classList = 'btn-group inline pull-right';\n", - " button = document.createElement('button');\n", - " button.classList = 'btn btn-mini btn-primary';\n", - " button.href = '#';\n", - " button.title = 'Stop Interaction';\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', function (_evt) {\n", - " fig.handle_close(fig, {});\n", - " });\n", - " button.addEventListener(\n", - " 'mouseover',\n", - " on_mouseover_closure('Stop Interaction')\n", - " );\n", - " buttongrp.appendChild(button);\n", - " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", - " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", - "};\n", - "\n", - "mpl.figure.prototype._remove_fig_handler = function (event) {\n", - " var fig = event.data.fig;\n", - " if (event.target !== this) {\n", - " // Ignore bubbled events from children.\n", - " return;\n", - " }\n", - " fig.close_ws(fig, {});\n", - "};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (el) {\n", - " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (el) {\n", - " // this is important to make the div 'focusable\n", - " el.setAttribute('tabindex', 0);\n", - " // reach out to IPython and tell the keyboard manager to turn it's self\n", - " // off when our div gets focus\n", - "\n", - " // location in version 3\n", - " if (IPython.notebook.keyboard_manager) {\n", - " IPython.notebook.keyboard_manager.register_events(el);\n", - " } else {\n", - " // location in version 2\n", - " IPython.keyboard_manager.register_events(el);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", - " var manager = IPython.notebook.keyboard_manager;\n", - " if (!manager) {\n", - " manager = IPython.keyboard_manager;\n", - " }\n", - "\n", - " // Check for shift+enter\n", - " if (event.shiftKey && event.which === 13) {\n", - " this.canvas_div.blur();\n", - " // select the cell after this one\n", - " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", - " IPython.notebook.select(index + 1);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " fig.ondownload(fig, null);\n", - "};\n", - "\n", - "mpl.find_output_cell = function (html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i = 0; i < ncells; i++) {\n", - " var cell = cells[i];\n", - " if (cell.cell_type === 'code') {\n", - " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", - " var data = cell.output_area.outputs[j];\n", - " if (data.data) {\n", - " // IPython >= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] === html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "};\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel !== null) {\n", - " IPython.notebook.kernel.comm_manager.register_target(\n", - " 'matplotlib',\n", - " mpl.mpl_figure_comm\n", - " );\n", - "}\n" - ], + "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n if (typeof WebSocket !== 'undefined') {\n return WebSocket;\n } else if (typeof MozWebSocket !== 'undefined') {\n return MozWebSocket;\n } else {\n alert(\n 'Your browser does not have WebSocket support. ' +\n 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n 'Firefox 4 and 5 are also supported but you ' +\n 'have to enable WebSockets in about:config.'\n );\n }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n this.id = figure_id;\n\n this.ws = websocket;\n\n this.supports_binary = this.ws.binaryType !== undefined;\n\n if (!this.supports_binary) {\n var warnings = document.getElementById('mpl-warnings');\n if (warnings) {\n warnings.style.display = 'block';\n warnings.textContent =\n 'This browser does not support binary websocket messages. ' +\n 'Performance may be slow.';\n }\n }\n\n this.imageObj = new Image();\n\n this.context = undefined;\n this.message = undefined;\n this.canvas = undefined;\n this.rubberband_canvas = undefined;\n this.rubberband_context = undefined;\n this.format_dropdown = undefined;\n\n this.image_mode = 'full';\n\n this.root = document.createElement('div');\n this.root.setAttribute('style', 'display: inline-block');\n this._root_extra_style(this.root);\n\n parent_element.appendChild(this.root);\n\n this._init_header(this);\n this._init_canvas(this);\n this._init_toolbar(this);\n\n var fig = this;\n\n this.waiting = false;\n\n this.ws.onopen = function () {\n fig.send_message('supports_binary', { value: fig.supports_binary });\n fig.send_message('send_image_mode', {});\n if (fig.ratio !== 1) {\n fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n }\n fig.send_message('refresh', {});\n };\n\n this.imageObj.onload = function () {\n if (fig.image_mode === 'full') {\n // Full images could contain transparency (where diff images\n // almost always do), so we need to clear the canvas so that\n // there is no ghosting.\n fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n }\n fig.context.drawImage(fig.imageObj, 0, 0);\n };\n\n this.imageObj.onunload = function () {\n fig.ws.close();\n };\n\n this.ws.onmessage = this._make_on_message_function(this);\n\n this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n var titlebar = document.createElement('div');\n titlebar.classList =\n 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n var titletext = document.createElement('div');\n titletext.classList = 'ui-dialog-title';\n titletext.setAttribute(\n 'style',\n 'width: 100%; text-align: center; padding: 3px;'\n );\n titlebar.appendChild(titletext);\n this.root.appendChild(titlebar);\n this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n var fig = this;\n\n var canvas_div = (this.canvas_div = document.createElement('div'));\n canvas_div.setAttribute(\n 'style',\n 'border: 1px solid #ddd;' +\n 'box-sizing: content-box;' +\n 'clear: both;' +\n 'min-height: 1px;' +\n 'min-width: 1px;' +\n 'outline: 0;' +\n 'overflow: hidden;' +\n 'position: relative;' +\n 'resize: both;'\n );\n\n function on_keyboard_event_closure(name) {\n return function (event) {\n return fig.key_event(event, name);\n };\n }\n\n canvas_div.addEventListener(\n 'keydown',\n on_keyboard_event_closure('key_press')\n );\n canvas_div.addEventListener(\n 'keyup',\n on_keyboard_event_closure('key_release')\n );\n\n this._canvas_extra_style(canvas_div);\n this.root.appendChild(canvas_div);\n\n var canvas = (this.canvas = document.createElement('canvas'));\n canvas.classList.add('mpl-canvas');\n canvas.setAttribute('style', 'box-sizing: content-box;');\n\n this.context = canvas.getContext('2d');\n\n var backingStore =\n this.context.backingStorePixelRatio ||\n this.context.webkitBackingStorePixelRatio ||\n this.context.mozBackingStorePixelRatio ||\n this.context.msBackingStorePixelRatio ||\n this.context.oBackingStorePixelRatio ||\n this.context.backingStorePixelRatio ||\n 1;\n\n this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n 'canvas'\n ));\n rubberband_canvas.setAttribute(\n 'style',\n 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n );\n\n // Apply a ponyfill if ResizeObserver is not implemented by browser.\n if (this.ResizeObserver === undefined) {\n if (window.ResizeObserver !== undefined) {\n this.ResizeObserver = window.ResizeObserver;\n } else {\n var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n this.ResizeObserver = obs.ResizeObserver;\n }\n }\n\n this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n var nentries = entries.length;\n for (var i = 0; i < nentries; i++) {\n var entry = entries[i];\n var width, height;\n if (entry.contentBoxSize) {\n if (entry.contentBoxSize instanceof Array) {\n // Chrome 84 implements new version of spec.\n width = entry.contentBoxSize[0].inlineSize;\n height = entry.contentBoxSize[0].blockSize;\n } else {\n // Firefox implements old version of spec.\n width = entry.contentBoxSize.inlineSize;\n height = entry.contentBoxSize.blockSize;\n }\n } else {\n // Chrome <84 implements even older version of spec.\n width = entry.contentRect.width;\n height = entry.contentRect.height;\n }\n\n // Keep the size of the canvas and rubber band canvas in sync with\n // the canvas container.\n if (entry.devicePixelContentBoxSize) {\n // Chrome 84 implements new version of spec.\n canvas.setAttribute(\n 'width',\n entry.devicePixelContentBoxSize[0].inlineSize\n );\n canvas.setAttribute(\n 'height',\n entry.devicePixelContentBoxSize[0].blockSize\n );\n } else {\n canvas.setAttribute('width', width * fig.ratio);\n canvas.setAttribute('height', height * fig.ratio);\n }\n canvas.setAttribute(\n 'style',\n 'width: ' + width + 'px; height: ' + height + 'px;'\n );\n\n rubberband_canvas.setAttribute('width', width);\n rubberband_canvas.setAttribute('height', height);\n\n // And update the size in Python. We ignore the initial 0/0 size\n // that occurs as the element is placed into the DOM, which should\n // otherwise not happen due to the minimum size styling.\n if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n fig.request_resize(width, height);\n }\n }\n });\n this.resizeObserverInstance.observe(canvas_div);\n\n function on_mouse_event_closure(name) {\n return function (event) {\n return fig.mouse_event(event, name);\n };\n }\n\n rubberband_canvas.addEventListener(\n 'mousedown',\n on_mouse_event_closure('button_press')\n );\n rubberband_canvas.addEventListener(\n 'mouseup',\n on_mouse_event_closure('button_release')\n );\n // Throttle sequential mouse events to 1 every 20ms.\n rubberband_canvas.addEventListener(\n 'mousemove',\n on_mouse_event_closure('motion_notify')\n );\n\n rubberband_canvas.addEventListener(\n 'mouseenter',\n on_mouse_event_closure('figure_enter')\n );\n rubberband_canvas.addEventListener(\n 'mouseleave',\n on_mouse_event_closure('figure_leave')\n );\n\n canvas_div.addEventListener('wheel', function (event) {\n if (event.deltaY < 0) {\n event.step = 1;\n } else {\n event.step = -1;\n }\n on_mouse_event_closure('scroll')(event);\n });\n\n canvas_div.appendChild(canvas);\n canvas_div.appendChild(rubberband_canvas);\n\n this.rubberband_context = rubberband_canvas.getContext('2d');\n this.rubberband_context.strokeStyle = '#000000';\n\n this._resize_canvas = function (width, height, forward) {\n if (forward) {\n canvas_div.style.width = width + 'px';\n canvas_div.style.height = height + 'px';\n }\n };\n\n // Disable right mouse context menu.\n this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n event.preventDefault();\n return false;\n });\n\n function set_focus() {\n canvas.focus();\n canvas_div.focus();\n }\n\n window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'mpl-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n continue;\n }\n\n var button = (fig.buttons[name] = document.createElement('button'));\n button.classList = 'mpl-widget';\n button.setAttribute('role', 'button');\n button.setAttribute('aria-disabled', 'false');\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n var icon_img = document.createElement('img');\n icon_img.src = '_images/' + image + '.png';\n icon_img.srcset = '_images/' + image + '_large.png 2x';\n icon_img.alt = tooltip;\n button.appendChild(icon_img);\n\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n var fmt_picker = document.createElement('select');\n fmt_picker.classList = 'mpl-widget';\n toolbar.appendChild(fmt_picker);\n this.format_dropdown = fmt_picker;\n\n for (var ind in mpl.extensions) {\n var fmt = mpl.extensions[ind];\n var option = document.createElement('option');\n option.selected = fmt === mpl.default_extension;\n option.innerHTML = fmt;\n fmt_picker.appendChild(option);\n }\n\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n // which will in turn request a refresh of the image.\n this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n properties['type'] = type;\n properties['figure_id'] = this.id;\n this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n if (!this.waiting) {\n this.waiting = true;\n this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n var format_dropdown = fig.format_dropdown;\n var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n var size = msg['size'];\n if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n fig._resize_canvas(size[0], size[1], msg['forward']);\n fig.send_message('refresh', {});\n }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n var x0 = msg['x0'] / fig.ratio;\n var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n var x1 = msg['x1'] / fig.ratio;\n var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n x0 = Math.floor(x0) + 0.5;\n y0 = Math.floor(y0) + 0.5;\n x1 = Math.floor(x1) + 0.5;\n y1 = Math.floor(y1) + 0.5;\n var min_x = Math.min(x0, x1);\n var min_y = Math.min(y0, y1);\n var width = Math.abs(x1 - x0);\n var height = Math.abs(y1 - y0);\n\n fig.rubberband_context.clearRect(\n 0,\n 0,\n fig.canvas.width / fig.ratio,\n fig.canvas.height / fig.ratio\n );\n\n fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n // Updates the figure title.\n fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n var cursor = msg['cursor'];\n switch (cursor) {\n case 0:\n cursor = 'pointer';\n break;\n case 1:\n cursor = 'default';\n break;\n case 2:\n cursor = 'crosshair';\n break;\n case 3:\n cursor = 'move';\n break;\n }\n fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n // Request the server to send over a new figure.\n fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n for (var key in msg) {\n if (!(key in fig.buttons)) {\n continue;\n }\n fig.buttons[key].disabled = !msg[key];\n fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n if (msg['mode'] === 'PAN') {\n fig.buttons['Pan'].classList.add('active');\n fig.buttons['Zoom'].classList.remove('active');\n } else if (msg['mode'] === 'ZOOM') {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.add('active');\n } else {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.remove('active');\n }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Called whenever the canvas gets updated.\n this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n return function socket_on_message(evt) {\n if (evt.data instanceof Blob) {\n /* FIXME: We get \"Resource interpreted as Image but\n * transferred with MIME type text/plain:\" errors on\n * Chrome. But how to set the MIME type? It doesn't seem\n * to be part of the websocket stream */\n evt.data.type = 'image/png';\n\n /* Free the memory for the previous frames */\n if (fig.imageObj.src) {\n (window.URL || window.webkitURL).revokeObjectURL(\n fig.imageObj.src\n );\n }\n\n fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n evt.data\n );\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n } else if (\n typeof evt.data === 'string' &&\n evt.data.slice(0, 21) === 'data:image/png;base64'\n ) {\n fig.imageObj.src = evt.data;\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n }\n\n var msg = JSON.parse(evt.data);\n var msg_type = msg['type'];\n\n // Call the \"handle_{type}\" callback, which takes\n // the figure and JSON message as its only arguments.\n try {\n var callback = fig['handle_' + msg_type];\n } catch (e) {\n console.log(\n \"No handler for the '\" + msg_type + \"' message type: \",\n msg\n );\n return;\n }\n\n if (callback) {\n try {\n // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n callback(fig, msg);\n } catch (e) {\n console.log(\n \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n e,\n e.stack,\n msg\n );\n }\n }\n };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n //this section is from http://www.quirksmode.org/js/events_properties.html\n var targ;\n if (!e) {\n e = window.event;\n }\n if (e.target) {\n targ = e.target;\n } else if (e.srcElement) {\n targ = e.srcElement;\n }\n if (targ.nodeType === 3) {\n // defeat Safari bug\n targ = targ.parentNode;\n }\n\n // pageX,Y are the mouse positions relative to the document\n var boundingRect = targ.getBoundingClientRect();\n var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n return Object.keys(original).reduce(function (obj, key) {\n if (typeof original[key] !== 'object') {\n obj[key] = original[key];\n }\n return obj;\n }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n var canvas_pos = mpl.findpos(event);\n\n if (name === 'button_press') {\n this.canvas.focus();\n this.canvas_div.focus();\n }\n\n var x = canvas_pos.x * this.ratio;\n var y = canvas_pos.y * this.ratio;\n\n this.send_message(name, {\n x: x,\n y: y,\n button: event.button,\n step: event.step,\n guiEvent: simpleKeys(event),\n });\n\n /* This prevents the web browser from automatically changing to\n * the text insertion cursor when the button is pressed. We want\n * to control all of the cursor setting manually through the\n * 'cursor' event from matplotlib */\n event.preventDefault();\n return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n // Prevent repeat events\n if (name === 'key_press') {\n if (event.which === this._key) {\n return;\n } else {\n this._key = event.which;\n }\n }\n if (name === 'key_release') {\n this._key = null;\n }\n\n var value = '';\n if (event.ctrlKey && event.which !== 17) {\n value += 'ctrl+';\n }\n if (event.altKey && event.which !== 18) {\n value += 'alt+';\n }\n if (event.shiftKey && event.which !== 16) {\n value += 'shift+';\n }\n\n value += 'k';\n value += event.which.toString();\n\n this._key_event_extra(event, name);\n\n this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n if (name === 'download') {\n this.handle_save(this, null);\n } else {\n this.send_message('toolbar_button', { name: name });\n }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\nmpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n\nmpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n // Create a \"websocket\"-like object which calls the given IPython comm\n // object with the appropriate methods. Currently this is a non binary\n // socket, so there is still some room for performance tuning.\n var ws = {};\n\n ws.close = function () {\n comm.close();\n };\n ws.send = function (m) {\n //console.log('sending', m);\n comm.send(m);\n };\n // Register the callback with on_msg.\n comm.on_msg(function (msg) {\n //console.log('receiving', msg['content']['data'], msg);\n // Pass the mpl event to the overridden (by mpl) onmessage function.\n ws.onmessage(msg['content']['data']);\n });\n return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n // This is the function which gets called when the mpl process\n // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n var id = msg.content.data.id;\n // Get hold of the div created by the display call when the Comm\n // socket was opened in Python.\n var element = document.getElementById(id);\n var ws_proxy = comm_websocket_adapter(comm);\n\n function ondownload(figure, _format) {\n window.open(figure.canvas.toDataURL());\n }\n\n var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n // web socket which is closed, not our websocket->open comm proxy.\n ws_proxy.onopen();\n\n fig.parent_element = element;\n fig.cell_info = mpl.find_output_cell(\"
\");\n if (!fig.cell_info) {\n console.error('Failed to find cell for figure', id, fig);\n return;\n }\n fig.cell_info[0].output_area.element.on(\n 'cleared',\n { fig: fig },\n fig._remove_fig_handler\n );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n var width = fig.canvas.width / fig.ratio;\n fig.cell_info[0].output_area.element.off(\n 'cleared',\n fig._remove_fig_handler\n );\n fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n // Update the output cell to use the data from the current canvas.\n fig.push_to_output();\n var dataURL = fig.canvas.toDataURL();\n // Re-enable the keyboard manager in IPython - without this line, in FF,\n // the notebook keyboard shortcuts fail.\n IPython.keyboard_manager.enable();\n fig.parent_element.innerHTML =\n '';\n fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n fig.send_message('closing', msg);\n // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n // Turn the data on the canvas into data in the output cell.\n var width = this.canvas.width / this.ratio;\n var dataURL = this.canvas.toDataURL();\n this.cell_info[1]['text/html'] =\n '';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Tell IPython that the notebook contents must change.\n IPython.notebook.set_dirty(true);\n this.send_message('ack', {});\n var fig = this;\n // Wait a second, then push the new image to the DOM so\n // that it is saved nicely (might be nice to debounce this).\n setTimeout(function () {\n fig.push_to_output();\n }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'btn-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n var button;\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n continue;\n }\n\n button = fig.buttons[name] = document.createElement('button');\n button.classList = 'btn btn-default';\n button.href = '#';\n button.title = name;\n button.innerHTML = '';\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n // Add the status bar.\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message pull-right';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n\n // Add the close button to the window.\n var buttongrp = document.createElement('div');\n buttongrp.classList = 'btn-group inline pull-right';\n button = document.createElement('button');\n button.classList = 'btn btn-mini btn-primary';\n button.href = '#';\n button.title = 'Stop Interaction';\n button.innerHTML = '';\n button.addEventListener('click', function (_evt) {\n fig.handle_close(fig, {});\n });\n button.addEventListener(\n 'mouseover',\n on_mouseover_closure('Stop Interaction')\n );\n buttongrp.appendChild(button);\n var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n var fig = event.data.fig;\n if (event.target !== this) {\n // Ignore bubbled events from children.\n return;\n }\n fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n // this is important to make the div 'focusable\n el.setAttribute('tabindex', 0);\n // reach out to IPython and tell the keyboard manager to turn it's self\n // off when our div gets focus\n\n // location in version 3\n if (IPython.notebook.keyboard_manager) {\n IPython.notebook.keyboard_manager.register_events(el);\n } else {\n // location in version 2\n IPython.keyboard_manager.register_events(el);\n }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n var manager = IPython.notebook.keyboard_manager;\n if (!manager) {\n manager = IPython.keyboard_manager;\n }\n\n // Check for shift+enter\n if (event.shiftKey && event.which === 13) {\n this.canvas_div.blur();\n // select the cell after this one\n var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n IPython.notebook.select(index + 1);\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n // Return the cell and output element which can be found *uniquely* in the notebook.\n // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n // IPython event is triggered only after the cells have been serialised, which for\n // our purposes (turning an active figure into a static one), is too late.\n var cells = IPython.notebook.get_cells();\n var ncells = cells.length;\n for (var i = 0; i < ncells; i++) {\n var cell = cells[i];\n if (cell.cell_type === 'code') {\n for (var j = 0; j < cell.output_area.outputs.length; j++) {\n var data = cell.output_area.outputs[j];\n if (data.data) {\n // IPython >= 3 moved mimebundle to data attribute of output\n data = data.data;\n }\n if (data['text/html'] === html_output) {\n return [cell, data, j];\n }\n }\n }\n }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n IPython.notebook.kernel.comm_manager.register_target(\n 'matplotlib',\n mpl.mpl_figure_comm\n );\n}\n", "text/plain": [ "" ] @@ -4431,955 +639,7 @@ }, { "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "/* global mpl */\n", - "window.mpl = {};\n", - "\n", - "mpl.get_websocket_type = function () {\n", - " if (typeof WebSocket !== 'undefined') {\n", - " return WebSocket;\n", - " } else if (typeof MozWebSocket !== 'undefined') {\n", - " return MozWebSocket;\n", - " } else {\n", - " alert(\n", - " 'Your browser does not have WebSocket support. ' +\n", - " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", - " 'Firefox 4 and 5 are also supported but you ' +\n", - " 'have to enable WebSockets in about:config.'\n", - " );\n", - " }\n", - "};\n", - "\n", - "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", - " this.id = figure_id;\n", - "\n", - " this.ws = websocket;\n", - "\n", - " this.supports_binary = this.ws.binaryType !== undefined;\n", - "\n", - " if (!this.supports_binary) {\n", - " var warnings = document.getElementById('mpl-warnings');\n", - " if (warnings) {\n", - " warnings.style.display = 'block';\n", - " warnings.textContent =\n", - " 'This browser does not support binary websocket messages. ' +\n", - " 'Performance may be slow.';\n", - " }\n", - " }\n", - "\n", - " this.imageObj = new Image();\n", - "\n", - " this.context = undefined;\n", - " this.message = undefined;\n", - " this.canvas = undefined;\n", - " this.rubberband_canvas = undefined;\n", - " this.rubberband_context = undefined;\n", - " this.format_dropdown = undefined;\n", - "\n", - " this.image_mode = 'full';\n", - "\n", - " this.root = document.createElement('div');\n", - " this.root.setAttribute('style', 'display: inline-block');\n", - " this._root_extra_style(this.root);\n", - "\n", - " parent_element.appendChild(this.root);\n", - "\n", - " this._init_header(this);\n", - " this._init_canvas(this);\n", - " this._init_toolbar(this);\n", - "\n", - " var fig = this;\n", - "\n", - " this.waiting = false;\n", - "\n", - " this.ws.onopen = function () {\n", - " fig.send_message('supports_binary', { value: fig.supports_binary });\n", - " fig.send_message('send_image_mode', {});\n", - " if (fig.ratio !== 1) {\n", - " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", - " }\n", - " fig.send_message('refresh', {});\n", - " };\n", - "\n", - " this.imageObj.onload = function () {\n", - " if (fig.image_mode === 'full') {\n", - " // Full images could contain transparency (where diff images\n", - " // almost always do), so we need to clear the canvas so that\n", - " // there is no ghosting.\n", - " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", - " }\n", - " fig.context.drawImage(fig.imageObj, 0, 0);\n", - " };\n", - "\n", - " this.imageObj.onunload = function () {\n", - " fig.ws.close();\n", - " };\n", - "\n", - " this.ws.onmessage = this._make_on_message_function(this);\n", - "\n", - " this.ondownload = ondownload;\n", - "};\n", - "\n", - "mpl.figure.prototype._init_header = function () {\n", - " var titlebar = document.createElement('div');\n", - " titlebar.classList =\n", - " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", - " var titletext = document.createElement('div');\n", - " titletext.classList = 'ui-dialog-title';\n", - " titletext.setAttribute(\n", - " 'style',\n", - " 'width: 100%; text-align: center; padding: 3px;'\n", - " );\n", - " titlebar.appendChild(titletext);\n", - " this.root.appendChild(titlebar);\n", - " this.header = titletext;\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._init_canvas = function () {\n", - " var fig = this;\n", - "\n", - " var canvas_div = (this.canvas_div = document.createElement('div'));\n", - " canvas_div.setAttribute(\n", - " 'style',\n", - " 'border: 1px solid #ddd;' +\n", - " 'box-sizing: content-box;' +\n", - " 'clear: both;' +\n", - " 'min-height: 1px;' +\n", - " 'min-width: 1px;' +\n", - " 'outline: 0;' +\n", - " 'overflow: hidden;' +\n", - " 'position: relative;' +\n", - " 'resize: both;'\n", - " );\n", - "\n", - " function on_keyboard_event_closure(name) {\n", - " return function (event) {\n", - " return fig.key_event(event, name);\n", - " };\n", - " }\n", - "\n", - " canvas_div.addEventListener(\n", - " 'keydown',\n", - " on_keyboard_event_closure('key_press')\n", - " );\n", - " canvas_div.addEventListener(\n", - " 'keyup',\n", - " on_keyboard_event_closure('key_release')\n", - " );\n", - "\n", - " this._canvas_extra_style(canvas_div);\n", - " this.root.appendChild(canvas_div);\n", - "\n", - " var canvas = (this.canvas = document.createElement('canvas'));\n", - " canvas.classList.add('mpl-canvas');\n", - " canvas.setAttribute('style', 'box-sizing: content-box;');\n", - "\n", - " this.context = canvas.getContext('2d');\n", - "\n", - " var backingStore =\n", - " this.context.backingStorePixelRatio ||\n", - " this.context.webkitBackingStorePixelRatio ||\n", - " this.context.mozBackingStorePixelRatio ||\n", - " this.context.msBackingStorePixelRatio ||\n", - " this.context.oBackingStorePixelRatio ||\n", - " this.context.backingStorePixelRatio ||\n", - " 1;\n", - "\n", - " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", - "\n", - " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", - " 'canvas'\n", - " ));\n", - " rubberband_canvas.setAttribute(\n", - " 'style',\n", - " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", - " );\n", - "\n", - " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", - " if (this.ResizeObserver === undefined) {\n", - " if (window.ResizeObserver !== undefined) {\n", - " this.ResizeObserver = window.ResizeObserver;\n", - " } else {\n", - " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", - " this.ResizeObserver = obs.ResizeObserver;\n", - " }\n", - " }\n", - "\n", - " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", - " var nentries = entries.length;\n", - " for (var i = 0; i < nentries; i++) {\n", - " var entry = entries[i];\n", - " var width, height;\n", - " if (entry.contentBoxSize) {\n", - " if (entry.contentBoxSize instanceof Array) {\n", - " // Chrome 84 implements new version of spec.\n", - " width = entry.contentBoxSize[0].inlineSize;\n", - " height = entry.contentBoxSize[0].blockSize;\n", - " } else {\n", - " // Firefox implements old version of spec.\n", - " width = entry.contentBoxSize.inlineSize;\n", - " height = entry.contentBoxSize.blockSize;\n", - " }\n", - " } else {\n", - " // Chrome <84 implements even older version of spec.\n", - " width = entry.contentRect.width;\n", - " height = entry.contentRect.height;\n", - " }\n", - "\n", - " // Keep the size of the canvas and rubber band canvas in sync with\n", - " // the canvas container.\n", - " if (entry.devicePixelContentBoxSize) {\n", - " // Chrome 84 implements new version of spec.\n", - " canvas.setAttribute(\n", - " 'width',\n", - " entry.devicePixelContentBoxSize[0].inlineSize\n", - " );\n", - " canvas.setAttribute(\n", - " 'height',\n", - " entry.devicePixelContentBoxSize[0].blockSize\n", - " );\n", - " } else {\n", - " canvas.setAttribute('width', width * fig.ratio);\n", - " canvas.setAttribute('height', height * fig.ratio);\n", - " }\n", - " canvas.setAttribute(\n", - " 'style',\n", - " 'width: ' + width + 'px; height: ' + height + 'px;'\n", - " );\n", - "\n", - " rubberband_canvas.setAttribute('width', width);\n", - " rubberband_canvas.setAttribute('height', height);\n", - "\n", - " // And update the size in Python. We ignore the initial 0/0 size\n", - " // that occurs as the element is placed into the DOM, which should\n", - " // otherwise not happen due to the minimum size styling.\n", - " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", - " fig.request_resize(width, height);\n", - " }\n", - " }\n", - " });\n", - " this.resizeObserverInstance.observe(canvas_div);\n", - "\n", - " function on_mouse_event_closure(name) {\n", - " return function (event) {\n", - " return fig.mouse_event(event, name);\n", - " };\n", - " }\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mousedown',\n", - " on_mouse_event_closure('button_press')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseup',\n", - " on_mouse_event_closure('button_release')\n", - " );\n", - " // Throttle sequential mouse events to 1 every 20ms.\n", - " rubberband_canvas.addEventListener(\n", - " 'mousemove',\n", - " on_mouse_event_closure('motion_notify')\n", - " );\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseenter',\n", - " on_mouse_event_closure('figure_enter')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseleave',\n", - " on_mouse_event_closure('figure_leave')\n", - " );\n", - "\n", - " canvas_div.addEventListener('wheel', function (event) {\n", - " if (event.deltaY < 0) {\n", - " event.step = 1;\n", - " } else {\n", - " event.step = -1;\n", - " }\n", - " on_mouse_event_closure('scroll')(event);\n", - " });\n", - "\n", - " canvas_div.appendChild(canvas);\n", - " canvas_div.appendChild(rubberband_canvas);\n", - "\n", - " this.rubberband_context = rubberband_canvas.getContext('2d');\n", - " this.rubberband_context.strokeStyle = '#000000';\n", - "\n", - " this._resize_canvas = function (width, height, forward) {\n", - " if (forward) {\n", - " canvas_div.style.width = width + 'px';\n", - " canvas_div.style.height = height + 'px';\n", - " }\n", - " };\n", - "\n", - " // Disable right mouse context menu.\n", - " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", - " event.preventDefault();\n", - " return false;\n", - " });\n", - "\n", - " function set_focus() {\n", - " canvas.focus();\n", - " canvas_div.focus();\n", - " }\n", - "\n", - " window.setTimeout(set_focus, 100);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'mpl-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " continue;\n", - " }\n", - "\n", - " var button = (fig.buttons[name] = document.createElement('button'));\n", - " button.classList = 'mpl-widget';\n", - " button.setAttribute('role', 'button');\n", - " button.setAttribute('aria-disabled', 'false');\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - "\n", - " var icon_img = document.createElement('img');\n", - " icon_img.src = '_images/' + image + '.png';\n", - " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", - " icon_img.alt = tooltip;\n", - " button.appendChild(icon_img);\n", - "\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " var fmt_picker = document.createElement('select');\n", - " fmt_picker.classList = 'mpl-widget';\n", - " toolbar.appendChild(fmt_picker);\n", - " this.format_dropdown = fmt_picker;\n", - "\n", - " for (var ind in mpl.extensions) {\n", - " var fmt = mpl.extensions[ind];\n", - " var option = document.createElement('option');\n", - " option.selected = fmt === mpl.default_extension;\n", - " option.innerHTML = fmt;\n", - " fmt_picker.appendChild(option);\n", - " }\n", - "\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "};\n", - "\n", - "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", - " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", - " // which will in turn request a refresh of the image.\n", - " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", - "};\n", - "\n", - "mpl.figure.prototype.send_message = function (type, properties) {\n", - " properties['type'] = type;\n", - " properties['figure_id'] = this.id;\n", - " this.ws.send(JSON.stringify(properties));\n", - "};\n", - "\n", - "mpl.figure.prototype.send_draw_message = function () {\n", - " if (!this.waiting) {\n", - " this.waiting = true;\n", - " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " var format_dropdown = fig.format_dropdown;\n", - " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", - " fig.ondownload(fig, format);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", - " var size = msg['size'];\n", - " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", - " fig._resize_canvas(size[0], size[1], msg['forward']);\n", - " fig.send_message('refresh', {});\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", - " var x0 = msg['x0'] / fig.ratio;\n", - " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", - " var x1 = msg['x1'] / fig.ratio;\n", - " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", - " x0 = Math.floor(x0) + 0.5;\n", - " y0 = Math.floor(y0) + 0.5;\n", - " x1 = Math.floor(x1) + 0.5;\n", - " y1 = Math.floor(y1) + 0.5;\n", - " var min_x = Math.min(x0, x1);\n", - " var min_y = Math.min(y0, y1);\n", - " var width = Math.abs(x1 - x0);\n", - " var height = Math.abs(y1 - y0);\n", - "\n", - " fig.rubberband_context.clearRect(\n", - " 0,\n", - " 0,\n", - " fig.canvas.width / fig.ratio,\n", - " fig.canvas.height / fig.ratio\n", - " );\n", - "\n", - " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", - " // Updates the figure title.\n", - " fig.header.textContent = msg['label'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", - " var cursor = msg['cursor'];\n", - " switch (cursor) {\n", - " case 0:\n", - " cursor = 'pointer';\n", - " break;\n", - " case 1:\n", - " cursor = 'default';\n", - " break;\n", - " case 2:\n", - " cursor = 'crosshair';\n", - " break;\n", - " case 3:\n", - " cursor = 'move';\n", - " break;\n", - " }\n", - " fig.rubberband_canvas.style.cursor = cursor;\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_message = function (fig, msg) {\n", - " fig.message.textContent = msg['message'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", - " // Request the server to send over a new figure.\n", - " fig.send_draw_message();\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", - " fig.image_mode = msg['mode'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", - " for (var key in msg) {\n", - " if (!(key in fig.buttons)) {\n", - " continue;\n", - " }\n", - " fig.buttons[key].disabled = !msg[key];\n", - " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", - " if (msg['mode'] === 'PAN') {\n", - " fig.buttons['Pan'].classList.add('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " } else if (msg['mode'] === 'ZOOM') {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.add('active');\n", - " } else {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Called whenever the canvas gets updated.\n", - " this.send_message('ack', {});\n", - "};\n", - "\n", - "// A function to construct a web socket function for onmessage handling.\n", - "// Called in the figure constructor.\n", - "mpl.figure.prototype._make_on_message_function = function (fig) {\n", - " return function socket_on_message(evt) {\n", - " if (evt.data instanceof Blob) {\n", - " /* FIXME: We get \"Resource interpreted as Image but\n", - " * transferred with MIME type text/plain:\" errors on\n", - " * Chrome. But how to set the MIME type? It doesn't seem\n", - " * to be part of the websocket stream */\n", - " evt.data.type = 'image/png';\n", - "\n", - " /* Free the memory for the previous frames */\n", - " if (fig.imageObj.src) {\n", - " (window.URL || window.webkitURL).revokeObjectURL(\n", - " fig.imageObj.src\n", - " );\n", - " }\n", - "\n", - " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", - " evt.data\n", - " );\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " } else if (\n", - " typeof evt.data === 'string' &&\n", - " evt.data.slice(0, 21) === 'data:image/png;base64'\n", - " ) {\n", - " fig.imageObj.src = evt.data;\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " }\n", - "\n", - " var msg = JSON.parse(evt.data);\n", - " var msg_type = msg['type'];\n", - "\n", - " // Call the \"handle_{type}\" callback, which takes\n", - " // the figure and JSON message as its only arguments.\n", - " try {\n", - " var callback = fig['handle_' + msg_type];\n", - " } catch (e) {\n", - " console.log(\n", - " \"No handler for the '\" + msg_type + \"' message type: \",\n", - " msg\n", - " );\n", - " return;\n", - " }\n", - "\n", - " if (callback) {\n", - " try {\n", - " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", - " callback(fig, msg);\n", - " } catch (e) {\n", - " console.log(\n", - " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", - " e,\n", - " e.stack,\n", - " msg\n", - " );\n", - " }\n", - " }\n", - " };\n", - "};\n", - "\n", - "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", - "mpl.findpos = function (e) {\n", - " //this section is from http://www.quirksmode.org/js/events_properties.html\n", - " var targ;\n", - " if (!e) {\n", - " e = window.event;\n", - " }\n", - " if (e.target) {\n", - " targ = e.target;\n", - " } else if (e.srcElement) {\n", - " targ = e.srcElement;\n", - " }\n", - " if (targ.nodeType === 3) {\n", - " // defeat Safari bug\n", - " targ = targ.parentNode;\n", - " }\n", - "\n", - " // pageX,Y are the mouse positions relative to the document\n", - " var boundingRect = targ.getBoundingClientRect();\n", - " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", - " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", - "\n", - " return { x: x, y: y };\n", - "};\n", - "\n", - "/*\n", - " * return a copy of an object with only non-object keys\n", - " * we need this to avoid circular references\n", - " * http://stackoverflow.com/a/24161582/3208463\n", - " */\n", - "function simpleKeys(original) {\n", - " return Object.keys(original).reduce(function (obj, key) {\n", - " if (typeof original[key] !== 'object') {\n", - " obj[key] = original[key];\n", - " }\n", - " return obj;\n", - " }, {});\n", - "}\n", - "\n", - "mpl.figure.prototype.mouse_event = function (event, name) {\n", - " var canvas_pos = mpl.findpos(event);\n", - "\n", - " if (name === 'button_press') {\n", - " this.canvas.focus();\n", - " this.canvas_div.focus();\n", - " }\n", - "\n", - " var x = canvas_pos.x * this.ratio;\n", - " var y = canvas_pos.y * this.ratio;\n", - "\n", - " this.send_message(name, {\n", - " x: x,\n", - " y: y,\n", - " button: event.button,\n", - " step: event.step,\n", - " guiEvent: simpleKeys(event),\n", - " });\n", - "\n", - " /* This prevents the web browser from automatically changing to\n", - " * the text insertion cursor when the button is pressed. We want\n", - " * to control all of the cursor setting manually through the\n", - " * 'cursor' event from matplotlib */\n", - " event.preventDefault();\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", - " // Handle any extra behaviour associated with a key event\n", - "};\n", - "\n", - "mpl.figure.prototype.key_event = function (event, name) {\n", - " // Prevent repeat events\n", - " if (name === 'key_press') {\n", - " if (event.which === this._key) {\n", - " return;\n", - " } else {\n", - " this._key = event.which;\n", - " }\n", - " }\n", - " if (name === 'key_release') {\n", - " this._key = null;\n", - " }\n", - "\n", - " var value = '';\n", - " if (event.ctrlKey && event.which !== 17) {\n", - " value += 'ctrl+';\n", - " }\n", - " if (event.altKey && event.which !== 18) {\n", - " value += 'alt+';\n", - " }\n", - " if (event.shiftKey && event.which !== 16) {\n", - " value += 'shift+';\n", - " }\n", - "\n", - " value += 'k';\n", - " value += event.which.toString();\n", - "\n", - " this._key_event_extra(event, name);\n", - "\n", - " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", - " if (name === 'download') {\n", - " this.handle_save(this, null);\n", - " } else {\n", - " this.send_message('toolbar_button', { name: name });\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", - " this.message.textContent = tooltip;\n", - "};\n", - "\n", - "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", - "// prettier-ignore\n", - "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", - "\n", - "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", - "\n", - "mpl.default_extension = \"png\";/* global mpl */\n", - "\n", - "var comm_websocket_adapter = function (comm) {\n", - " // Create a \"websocket\"-like object which calls the given IPython comm\n", - " // object with the appropriate methods. Currently this is a non binary\n", - " // socket, so there is still some room for performance tuning.\n", - " var ws = {};\n", - "\n", - " ws.close = function () {\n", - " comm.close();\n", - " };\n", - " ws.send = function (m) {\n", - " //console.log('sending', m);\n", - " comm.send(m);\n", - " };\n", - " // Register the callback with on_msg.\n", - " comm.on_msg(function (msg) {\n", - " //console.log('receiving', msg['content']['data'], msg);\n", - " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", - " ws.onmessage(msg['content']['data']);\n", - " });\n", - " return ws;\n", - "};\n", - "\n", - "mpl.mpl_figure_comm = function (comm, msg) {\n", - " // This is the function which gets called when the mpl process\n", - " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", - "\n", - " var id = msg.content.data.id;\n", - " // Get hold of the div created by the display call when the Comm\n", - " // socket was opened in Python.\n", - " var element = document.getElementById(id);\n", - " var ws_proxy = comm_websocket_adapter(comm);\n", - "\n", - " function ondownload(figure, _format) {\n", - " window.open(figure.canvas.toDataURL());\n", - " }\n", - "\n", - " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", - "\n", - " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", - " // web socket which is closed, not our websocket->open comm proxy.\n", - " ws_proxy.onopen();\n", - "\n", - " fig.parent_element = element;\n", - " fig.cell_info = mpl.find_output_cell(\"
\");\n", - " if (!fig.cell_info) {\n", - " console.error('Failed to find cell for figure', id, fig);\n", - " return;\n", - " }\n", - " fig.cell_info[0].output_area.element.on(\n", - " 'cleared',\n", - " { fig: fig },\n", - " fig._remove_fig_handler\n", - " );\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_close = function (fig, msg) {\n", - " var width = fig.canvas.width / fig.ratio;\n", - " fig.cell_info[0].output_area.element.off(\n", - " 'cleared',\n", - " fig._remove_fig_handler\n", - " );\n", - " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", - "\n", - " // Update the output cell to use the data from the current canvas.\n", - " fig.push_to_output();\n", - " var dataURL = fig.canvas.toDataURL();\n", - " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", - " // the notebook keyboard shortcuts fail.\n", - " IPython.keyboard_manager.enable();\n", - " fig.parent_element.innerHTML =\n", - " '';\n", - " fig.close_ws(fig, msg);\n", - "};\n", - "\n", - "mpl.figure.prototype.close_ws = function (fig, msg) {\n", - " fig.send_message('closing', msg);\n", - " // fig.ws.close()\n", - "};\n", - "\n", - "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", - " // Turn the data on the canvas into data in the output cell.\n", - " var width = this.canvas.width / this.ratio;\n", - " var dataURL = this.canvas.toDataURL();\n", - " this.cell_info[1]['text/html'] =\n", - " '';\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Tell IPython that the notebook contents must change.\n", - " IPython.notebook.set_dirty(true);\n", - " this.send_message('ack', {});\n", - " var fig = this;\n", - " // Wait a second, then push the new image to the DOM so\n", - " // that it is saved nicely (might be nice to debounce this).\n", - " setTimeout(function () {\n", - " fig.push_to_output();\n", - " }, 1000);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'btn-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " var button;\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " continue;\n", - " }\n", - "\n", - " button = fig.buttons[name] = document.createElement('button');\n", - " button.classList = 'btn btn-default';\n", - " button.href = '#';\n", - " button.title = name;\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " // Add the status bar.\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message pull-right';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "\n", - " // Add the close button to the window.\n", - " var buttongrp = document.createElement('div');\n", - " buttongrp.classList = 'btn-group inline pull-right';\n", - " button = document.createElement('button');\n", - " button.classList = 'btn btn-mini btn-primary';\n", - " button.href = '#';\n", - " button.title = 'Stop Interaction';\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', function (_evt) {\n", - " fig.handle_close(fig, {});\n", - " });\n", - " button.addEventListener(\n", - " 'mouseover',\n", - " on_mouseover_closure('Stop Interaction')\n", - " );\n", - " buttongrp.appendChild(button);\n", - " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", - " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", - "};\n", - "\n", - "mpl.figure.prototype._remove_fig_handler = function (event) {\n", - " var fig = event.data.fig;\n", - " if (event.target !== this) {\n", - " // Ignore bubbled events from children.\n", - " return;\n", - " }\n", - " fig.close_ws(fig, {});\n", - "};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (el) {\n", - " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (el) {\n", - " // this is important to make the div 'focusable\n", - " el.setAttribute('tabindex', 0);\n", - " // reach out to IPython and tell the keyboard manager to turn it's self\n", - " // off when our div gets focus\n", - "\n", - " // location in version 3\n", - " if (IPython.notebook.keyboard_manager) {\n", - " IPython.notebook.keyboard_manager.register_events(el);\n", - " } else {\n", - " // location in version 2\n", - " IPython.keyboard_manager.register_events(el);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", - " var manager = IPython.notebook.keyboard_manager;\n", - " if (!manager) {\n", - " manager = IPython.keyboard_manager;\n", - " }\n", - "\n", - " // Check for shift+enter\n", - " if (event.shiftKey && event.which === 13) {\n", - " this.canvas_div.blur();\n", - " // select the cell after this one\n", - " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", - " IPython.notebook.select(index + 1);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " fig.ondownload(fig, null);\n", - "};\n", - "\n", - "mpl.find_output_cell = function (html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i = 0; i < ncells; i++) {\n", - " var cell = cells[i];\n", - " if (cell.cell_type === 'code') {\n", - " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", - " var data = cell.output_area.outputs[j];\n", - " if (data.data) {\n", - " // IPython >= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] === html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "};\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel !== null) {\n", - " IPython.notebook.kernel.comm_manager.register_target(\n", - " 'matplotlib',\n", - " mpl.mpl_figure_comm\n", - " );\n", - "}\n" - ], + "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n if (typeof WebSocket !== 'undefined') {\n return WebSocket;\n } else if (typeof MozWebSocket !== 'undefined') {\n return MozWebSocket;\n } else {\n alert(\n 'Your browser does not have WebSocket support. ' +\n 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n 'Firefox 4 and 5 are also supported but you ' +\n 'have to enable WebSockets in about:config.'\n );\n }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n this.id = figure_id;\n\n this.ws = websocket;\n\n this.supports_binary = this.ws.binaryType !== undefined;\n\n if (!this.supports_binary) {\n var warnings = document.getElementById('mpl-warnings');\n if (warnings) {\n warnings.style.display = 'block';\n warnings.textContent =\n 'This browser does not support binary websocket messages. ' +\n 'Performance may be slow.';\n }\n }\n\n this.imageObj = new Image();\n\n this.context = undefined;\n this.message = undefined;\n this.canvas = undefined;\n this.rubberband_canvas = undefined;\n this.rubberband_context = undefined;\n this.format_dropdown = undefined;\n\n this.image_mode = 'full';\n\n this.root = document.createElement('div');\n this.root.setAttribute('style', 'display: inline-block');\n this._root_extra_style(this.root);\n\n parent_element.appendChild(this.root);\n\n this._init_header(this);\n this._init_canvas(this);\n this._init_toolbar(this);\n\n var fig = this;\n\n this.waiting = false;\n\n this.ws.onopen = function () {\n fig.send_message('supports_binary', { value: fig.supports_binary });\n fig.send_message('send_image_mode', {});\n if (fig.ratio !== 1) {\n fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n }\n fig.send_message('refresh', {});\n };\n\n this.imageObj.onload = function () {\n if (fig.image_mode === 'full') {\n // Full images could contain transparency (where diff images\n // almost always do), so we need to clear the canvas so that\n // there is no ghosting.\n fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n }\n fig.context.drawImage(fig.imageObj, 0, 0);\n };\n\n this.imageObj.onunload = function () {\n fig.ws.close();\n };\n\n this.ws.onmessage = this._make_on_message_function(this);\n\n this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n var titlebar = document.createElement('div');\n titlebar.classList =\n 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n var titletext = document.createElement('div');\n titletext.classList = 'ui-dialog-title';\n titletext.setAttribute(\n 'style',\n 'width: 100%; text-align: center; padding: 3px;'\n );\n titlebar.appendChild(titletext);\n this.root.appendChild(titlebar);\n this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n var fig = this;\n\n var canvas_div = (this.canvas_div = document.createElement('div'));\n canvas_div.setAttribute(\n 'style',\n 'border: 1px solid #ddd;' +\n 'box-sizing: content-box;' +\n 'clear: both;' +\n 'min-height: 1px;' +\n 'min-width: 1px;' +\n 'outline: 0;' +\n 'overflow: hidden;' +\n 'position: relative;' +\n 'resize: both;'\n );\n\n function on_keyboard_event_closure(name) {\n return function (event) {\n return fig.key_event(event, name);\n };\n }\n\n canvas_div.addEventListener(\n 'keydown',\n on_keyboard_event_closure('key_press')\n );\n canvas_div.addEventListener(\n 'keyup',\n on_keyboard_event_closure('key_release')\n );\n\n this._canvas_extra_style(canvas_div);\n this.root.appendChild(canvas_div);\n\n var canvas = (this.canvas = document.createElement('canvas'));\n canvas.classList.add('mpl-canvas');\n canvas.setAttribute('style', 'box-sizing: content-box;');\n\n this.context = canvas.getContext('2d');\n\n var backingStore =\n this.context.backingStorePixelRatio ||\n this.context.webkitBackingStorePixelRatio ||\n this.context.mozBackingStorePixelRatio ||\n this.context.msBackingStorePixelRatio ||\n this.context.oBackingStorePixelRatio ||\n this.context.backingStorePixelRatio ||\n 1;\n\n this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n 'canvas'\n ));\n rubberband_canvas.setAttribute(\n 'style',\n 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n );\n\n // Apply a ponyfill if ResizeObserver is not implemented by browser.\n if (this.ResizeObserver === undefined) {\n if (window.ResizeObserver !== undefined) {\n this.ResizeObserver = window.ResizeObserver;\n } else {\n var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n this.ResizeObserver = obs.ResizeObserver;\n }\n }\n\n this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n var nentries = entries.length;\n for (var i = 0; i < nentries; i++) {\n var entry = entries[i];\n var width, height;\n if (entry.contentBoxSize) {\n if (entry.contentBoxSize instanceof Array) {\n // Chrome 84 implements new version of spec.\n width = entry.contentBoxSize[0].inlineSize;\n height = entry.contentBoxSize[0].blockSize;\n } else {\n // Firefox implements old version of spec.\n width = entry.contentBoxSize.inlineSize;\n height = entry.contentBoxSize.blockSize;\n }\n } else {\n // Chrome <84 implements even older version of spec.\n width = entry.contentRect.width;\n height = entry.contentRect.height;\n }\n\n // Keep the size of the canvas and rubber band canvas in sync with\n // the canvas container.\n if (entry.devicePixelContentBoxSize) {\n // Chrome 84 implements new version of spec.\n canvas.setAttribute(\n 'width',\n entry.devicePixelContentBoxSize[0].inlineSize\n );\n canvas.setAttribute(\n 'height',\n entry.devicePixelContentBoxSize[0].blockSize\n );\n } else {\n canvas.setAttribute('width', width * fig.ratio);\n canvas.setAttribute('height', height * fig.ratio);\n }\n canvas.setAttribute(\n 'style',\n 'width: ' + width + 'px; height: ' + height + 'px;'\n );\n\n rubberband_canvas.setAttribute('width', width);\n rubberband_canvas.setAttribute('height', height);\n\n // And update the size in Python. We ignore the initial 0/0 size\n // that occurs as the element is placed into the DOM, which should\n // otherwise not happen due to the minimum size styling.\n if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n fig.request_resize(width, height);\n }\n }\n });\n this.resizeObserverInstance.observe(canvas_div);\n\n function on_mouse_event_closure(name) {\n return function (event) {\n return fig.mouse_event(event, name);\n };\n }\n\n rubberband_canvas.addEventListener(\n 'mousedown',\n on_mouse_event_closure('button_press')\n );\n rubberband_canvas.addEventListener(\n 'mouseup',\n on_mouse_event_closure('button_release')\n );\n // Throttle sequential mouse events to 1 every 20ms.\n rubberband_canvas.addEventListener(\n 'mousemove',\n on_mouse_event_closure('motion_notify')\n );\n\n rubberband_canvas.addEventListener(\n 'mouseenter',\n on_mouse_event_closure('figure_enter')\n );\n rubberband_canvas.addEventListener(\n 'mouseleave',\n on_mouse_event_closure('figure_leave')\n );\n\n canvas_div.addEventListener('wheel', function (event) {\n if (event.deltaY < 0) {\n event.step = 1;\n } else {\n event.step = -1;\n }\n on_mouse_event_closure('scroll')(event);\n });\n\n canvas_div.appendChild(canvas);\n canvas_div.appendChild(rubberband_canvas);\n\n this.rubberband_context = rubberband_canvas.getContext('2d');\n this.rubberband_context.strokeStyle = '#000000';\n\n this._resize_canvas = function (width, height, forward) {\n if (forward) {\n canvas_div.style.width = width + 'px';\n canvas_div.style.height = height + 'px';\n }\n };\n\n // Disable right mouse context menu.\n this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n event.preventDefault();\n return false;\n });\n\n function set_focus() {\n canvas.focus();\n canvas_div.focus();\n }\n\n window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'mpl-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n continue;\n }\n\n var button = (fig.buttons[name] = document.createElement('button'));\n button.classList = 'mpl-widget';\n button.setAttribute('role', 'button');\n button.setAttribute('aria-disabled', 'false');\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n var icon_img = document.createElement('img');\n icon_img.src = '_images/' + image + '.png';\n icon_img.srcset = '_images/' + image + '_large.png 2x';\n icon_img.alt = tooltip;\n button.appendChild(icon_img);\n\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n var fmt_picker = document.createElement('select');\n fmt_picker.classList = 'mpl-widget';\n toolbar.appendChild(fmt_picker);\n this.format_dropdown = fmt_picker;\n\n for (var ind in mpl.extensions) {\n var fmt = mpl.extensions[ind];\n var option = document.createElement('option');\n option.selected = fmt === mpl.default_extension;\n option.innerHTML = fmt;\n fmt_picker.appendChild(option);\n }\n\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n // which will in turn request a refresh of the image.\n this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n properties['type'] = type;\n properties['figure_id'] = this.id;\n this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n if (!this.waiting) {\n this.waiting = true;\n this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n var format_dropdown = fig.format_dropdown;\n var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n var size = msg['size'];\n if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n fig._resize_canvas(size[0], size[1], msg['forward']);\n fig.send_message('refresh', {});\n }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n var x0 = msg['x0'] / fig.ratio;\n var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n var x1 = msg['x1'] / fig.ratio;\n var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n x0 = Math.floor(x0) + 0.5;\n y0 = Math.floor(y0) + 0.5;\n x1 = Math.floor(x1) + 0.5;\n y1 = Math.floor(y1) + 0.5;\n var min_x = Math.min(x0, x1);\n var min_y = Math.min(y0, y1);\n var width = Math.abs(x1 - x0);\n var height = Math.abs(y1 - y0);\n\n fig.rubberband_context.clearRect(\n 0,\n 0,\n fig.canvas.width / fig.ratio,\n fig.canvas.height / fig.ratio\n );\n\n fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n // Updates the figure title.\n fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n var cursor = msg['cursor'];\n switch (cursor) {\n case 0:\n cursor = 'pointer';\n break;\n case 1:\n cursor = 'default';\n break;\n case 2:\n cursor = 'crosshair';\n break;\n case 3:\n cursor = 'move';\n break;\n }\n fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n // Request the server to send over a new figure.\n fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n for (var key in msg) {\n if (!(key in fig.buttons)) {\n continue;\n }\n fig.buttons[key].disabled = !msg[key];\n fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n if (msg['mode'] === 'PAN') {\n fig.buttons['Pan'].classList.add('active');\n fig.buttons['Zoom'].classList.remove('active');\n } else if (msg['mode'] === 'ZOOM') {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.add('active');\n } else {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.remove('active');\n }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Called whenever the canvas gets updated.\n this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n return function socket_on_message(evt) {\n if (evt.data instanceof Blob) {\n /* FIXME: We get \"Resource interpreted as Image but\n * transferred with MIME type text/plain:\" errors on\n * Chrome. But how to set the MIME type? It doesn't seem\n * to be part of the websocket stream */\n evt.data.type = 'image/png';\n\n /* Free the memory for the previous frames */\n if (fig.imageObj.src) {\n (window.URL || window.webkitURL).revokeObjectURL(\n fig.imageObj.src\n );\n }\n\n fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n evt.data\n );\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n } else if (\n typeof evt.data === 'string' &&\n evt.data.slice(0, 21) === 'data:image/png;base64'\n ) {\n fig.imageObj.src = evt.data;\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n }\n\n var msg = JSON.parse(evt.data);\n var msg_type = msg['type'];\n\n // Call the \"handle_{type}\" callback, which takes\n // the figure and JSON message as its only arguments.\n try {\n var callback = fig['handle_' + msg_type];\n } catch (e) {\n console.log(\n \"No handler for the '\" + msg_type + \"' message type: \",\n msg\n );\n return;\n }\n\n if (callback) {\n try {\n // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n callback(fig, msg);\n } catch (e) {\n console.log(\n \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n e,\n e.stack,\n msg\n );\n }\n }\n };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n //this section is from http://www.quirksmode.org/js/events_properties.html\n var targ;\n if (!e) {\n e = window.event;\n }\n if (e.target) {\n targ = e.target;\n } else if (e.srcElement) {\n targ = e.srcElement;\n }\n if (targ.nodeType === 3) {\n // defeat Safari bug\n targ = targ.parentNode;\n }\n\n // pageX,Y are the mouse positions relative to the document\n var boundingRect = targ.getBoundingClientRect();\n var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n return Object.keys(original).reduce(function (obj, key) {\n if (typeof original[key] !== 'object') {\n obj[key] = original[key];\n }\n return obj;\n }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n var canvas_pos = mpl.findpos(event);\n\n if (name === 'button_press') {\n this.canvas.focus();\n this.canvas_div.focus();\n }\n\n var x = canvas_pos.x * this.ratio;\n var y = canvas_pos.y * this.ratio;\n\n this.send_message(name, {\n x: x,\n y: y,\n button: event.button,\n step: event.step,\n guiEvent: simpleKeys(event),\n });\n\n /* This prevents the web browser from automatically changing to\n * the text insertion cursor when the button is pressed. We want\n * to control all of the cursor setting manually through the\n * 'cursor' event from matplotlib */\n event.preventDefault();\n return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n // Prevent repeat events\n if (name === 'key_press') {\n if (event.which === this._key) {\n return;\n } else {\n this._key = event.which;\n }\n }\n if (name === 'key_release') {\n this._key = null;\n }\n\n var value = '';\n if (event.ctrlKey && event.which !== 17) {\n value += 'ctrl+';\n }\n if (event.altKey && event.which !== 18) {\n value += 'alt+';\n }\n if (event.shiftKey && event.which !== 16) {\n value += 'shift+';\n }\n\n value += 'k';\n value += event.which.toString();\n\n this._key_event_extra(event, name);\n\n this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n if (name === 'download') {\n this.handle_save(this, null);\n } else {\n this.send_message('toolbar_button', { name: name });\n }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\nmpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n\nmpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n // Create a \"websocket\"-like object which calls the given IPython comm\n // object with the appropriate methods. Currently this is a non binary\n // socket, so there is still some room for performance tuning.\n var ws = {};\n\n ws.close = function () {\n comm.close();\n };\n ws.send = function (m) {\n //console.log('sending', m);\n comm.send(m);\n };\n // Register the callback with on_msg.\n comm.on_msg(function (msg) {\n //console.log('receiving', msg['content']['data'], msg);\n // Pass the mpl event to the overridden (by mpl) onmessage function.\n ws.onmessage(msg['content']['data']);\n });\n return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n // This is the function which gets called when the mpl process\n // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n var id = msg.content.data.id;\n // Get hold of the div created by the display call when the Comm\n // socket was opened in Python.\n var element = document.getElementById(id);\n var ws_proxy = comm_websocket_adapter(comm);\n\n function ondownload(figure, _format) {\n window.open(figure.canvas.toDataURL());\n }\n\n var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n // web socket which is closed, not our websocket->open comm proxy.\n ws_proxy.onopen();\n\n fig.parent_element = element;\n fig.cell_info = mpl.find_output_cell(\"
\");\n if (!fig.cell_info) {\n console.error('Failed to find cell for figure', id, fig);\n return;\n }\n fig.cell_info[0].output_area.element.on(\n 'cleared',\n { fig: fig },\n fig._remove_fig_handler\n );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n var width = fig.canvas.width / fig.ratio;\n fig.cell_info[0].output_area.element.off(\n 'cleared',\n fig._remove_fig_handler\n );\n fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n // Update the output cell to use the data from the current canvas.\n fig.push_to_output();\n var dataURL = fig.canvas.toDataURL();\n // Re-enable the keyboard manager in IPython - without this line, in FF,\n // the notebook keyboard shortcuts fail.\n IPython.keyboard_manager.enable();\n fig.parent_element.innerHTML =\n '';\n fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n fig.send_message('closing', msg);\n // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n // Turn the data on the canvas into data in the output cell.\n var width = this.canvas.width / this.ratio;\n var dataURL = this.canvas.toDataURL();\n this.cell_info[1]['text/html'] =\n '';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Tell IPython that the notebook contents must change.\n IPython.notebook.set_dirty(true);\n this.send_message('ack', {});\n var fig = this;\n // Wait a second, then push the new image to the DOM so\n // that it is saved nicely (might be nice to debounce this).\n setTimeout(function () {\n fig.push_to_output();\n }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'btn-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n var button;\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n continue;\n }\n\n button = fig.buttons[name] = document.createElement('button');\n button.classList = 'btn btn-default';\n button.href = '#';\n button.title = name;\n button.innerHTML = '';\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n // Add the status bar.\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message pull-right';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n\n // Add the close button to the window.\n var buttongrp = document.createElement('div');\n buttongrp.classList = 'btn-group inline pull-right';\n button = document.createElement('button');\n button.classList = 'btn btn-mini btn-primary';\n button.href = '#';\n button.title = 'Stop Interaction';\n button.innerHTML = '';\n button.addEventListener('click', function (_evt) {\n fig.handle_close(fig, {});\n });\n button.addEventListener(\n 'mouseover',\n on_mouseover_closure('Stop Interaction')\n );\n buttongrp.appendChild(button);\n var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n var fig = event.data.fig;\n if (event.target !== this) {\n // Ignore bubbled events from children.\n return;\n }\n fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n // this is important to make the div 'focusable\n el.setAttribute('tabindex', 0);\n // reach out to IPython and tell the keyboard manager to turn it's self\n // off when our div gets focus\n\n // location in version 3\n if (IPython.notebook.keyboard_manager) {\n IPython.notebook.keyboard_manager.register_events(el);\n } else {\n // location in version 2\n IPython.keyboard_manager.register_events(el);\n }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n var manager = IPython.notebook.keyboard_manager;\n if (!manager) {\n manager = IPython.keyboard_manager;\n }\n\n // Check for shift+enter\n if (event.shiftKey && event.which === 13) {\n this.canvas_div.blur();\n // select the cell after this one\n var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n IPython.notebook.select(index + 1);\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n // Return the cell and output element which can be found *uniquely* in the notebook.\n // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n // IPython event is triggered only after the cells have been serialised, which for\n // our purposes (turning an active figure into a static one), is too late.\n var cells = IPython.notebook.get_cells();\n var ncells = cells.length;\n for (var i = 0; i < ncells; i++) {\n var cell = cells[i];\n if (cell.cell_type === 'code') {\n for (var j = 0; j < cell.output_area.outputs.length; j++) {\n var data = cell.output_area.outputs[j];\n if (data.data) {\n // IPython >= 3 moved mimebundle to data attribute of output\n data = data.data;\n }\n if (data['text/html'] === html_output) {\n return [cell, data, j];\n }\n }\n }\n }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n IPython.notebook.kernel.comm_manager.register_target(\n 'matplotlib',\n mpl.mpl_figure_comm\n );\n}\n", "text/plain": [ "" ] @@ -5409,955 +669,7 @@ }, { "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "/* global mpl */\n", - "window.mpl = {};\n", - "\n", - "mpl.get_websocket_type = function () {\n", - " if (typeof WebSocket !== 'undefined') {\n", - " return WebSocket;\n", - " } else if (typeof MozWebSocket !== 'undefined') {\n", - " return MozWebSocket;\n", - " } else {\n", - " alert(\n", - " 'Your browser does not have WebSocket support. ' +\n", - " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", - " 'Firefox 4 and 5 are also supported but you ' +\n", - " 'have to enable WebSockets in about:config.'\n", - " );\n", - " }\n", - "};\n", - "\n", - "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", - " this.id = figure_id;\n", - "\n", - " this.ws = websocket;\n", - "\n", - " this.supports_binary = this.ws.binaryType !== undefined;\n", - "\n", - " if (!this.supports_binary) {\n", - " var warnings = document.getElementById('mpl-warnings');\n", - " if (warnings) {\n", - " warnings.style.display = 'block';\n", - " warnings.textContent =\n", - " 'This browser does not support binary websocket messages. ' +\n", - " 'Performance may be slow.';\n", - " }\n", - " }\n", - "\n", - " this.imageObj = new Image();\n", - "\n", - " this.context = undefined;\n", - " this.message = undefined;\n", - " this.canvas = undefined;\n", - " this.rubberband_canvas = undefined;\n", - " this.rubberband_context = undefined;\n", - " this.format_dropdown = undefined;\n", - "\n", - " this.image_mode = 'full';\n", - "\n", - " this.root = document.createElement('div');\n", - " this.root.setAttribute('style', 'display: inline-block');\n", - " this._root_extra_style(this.root);\n", - "\n", - " parent_element.appendChild(this.root);\n", - "\n", - " this._init_header(this);\n", - " this._init_canvas(this);\n", - " this._init_toolbar(this);\n", - "\n", - " var fig = this;\n", - "\n", - " this.waiting = false;\n", - "\n", - " this.ws.onopen = function () {\n", - " fig.send_message('supports_binary', { value: fig.supports_binary });\n", - " fig.send_message('send_image_mode', {});\n", - " if (fig.ratio !== 1) {\n", - " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", - " }\n", - " fig.send_message('refresh', {});\n", - " };\n", - "\n", - " this.imageObj.onload = function () {\n", - " if (fig.image_mode === 'full') {\n", - " // Full images could contain transparency (where diff images\n", - " // almost always do), so we need to clear the canvas so that\n", - " // there is no ghosting.\n", - " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", - " }\n", - " fig.context.drawImage(fig.imageObj, 0, 0);\n", - " };\n", - "\n", - " this.imageObj.onunload = function () {\n", - " fig.ws.close();\n", - " };\n", - "\n", - " this.ws.onmessage = this._make_on_message_function(this);\n", - "\n", - " this.ondownload = ondownload;\n", - "};\n", - "\n", - "mpl.figure.prototype._init_header = function () {\n", - " var titlebar = document.createElement('div');\n", - " titlebar.classList =\n", - " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", - " var titletext = document.createElement('div');\n", - " titletext.classList = 'ui-dialog-title';\n", - " titletext.setAttribute(\n", - " 'style',\n", - " 'width: 100%; text-align: center; padding: 3px;'\n", - " );\n", - " titlebar.appendChild(titletext);\n", - " this.root.appendChild(titlebar);\n", - " this.header = titletext;\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._init_canvas = function () {\n", - " var fig = this;\n", - "\n", - " var canvas_div = (this.canvas_div = document.createElement('div'));\n", - " canvas_div.setAttribute(\n", - " 'style',\n", - " 'border: 1px solid #ddd;' +\n", - " 'box-sizing: content-box;' +\n", - " 'clear: both;' +\n", - " 'min-height: 1px;' +\n", - " 'min-width: 1px;' +\n", - " 'outline: 0;' +\n", - " 'overflow: hidden;' +\n", - " 'position: relative;' +\n", - " 'resize: both;'\n", - " );\n", - "\n", - " function on_keyboard_event_closure(name) {\n", - " return function (event) {\n", - " return fig.key_event(event, name);\n", - " };\n", - " }\n", - "\n", - " canvas_div.addEventListener(\n", - " 'keydown',\n", - " on_keyboard_event_closure('key_press')\n", - " );\n", - " canvas_div.addEventListener(\n", - " 'keyup',\n", - " on_keyboard_event_closure('key_release')\n", - " );\n", - "\n", - " this._canvas_extra_style(canvas_div);\n", - " this.root.appendChild(canvas_div);\n", - "\n", - " var canvas = (this.canvas = document.createElement('canvas'));\n", - " canvas.classList.add('mpl-canvas');\n", - " canvas.setAttribute('style', 'box-sizing: content-box;');\n", - "\n", - " this.context = canvas.getContext('2d');\n", - "\n", - " var backingStore =\n", - " this.context.backingStorePixelRatio ||\n", - " this.context.webkitBackingStorePixelRatio ||\n", - " this.context.mozBackingStorePixelRatio ||\n", - " this.context.msBackingStorePixelRatio ||\n", - " this.context.oBackingStorePixelRatio ||\n", - " this.context.backingStorePixelRatio ||\n", - " 1;\n", - "\n", - " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", - "\n", - " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", - " 'canvas'\n", - " ));\n", - " rubberband_canvas.setAttribute(\n", - " 'style',\n", - " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", - " );\n", - "\n", - " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", - " if (this.ResizeObserver === undefined) {\n", - " if (window.ResizeObserver !== undefined) {\n", - " this.ResizeObserver = window.ResizeObserver;\n", - " } else {\n", - " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", - " this.ResizeObserver = obs.ResizeObserver;\n", - " }\n", - " }\n", - "\n", - " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", - " var nentries = entries.length;\n", - " for (var i = 0; i < nentries; i++) {\n", - " var entry = entries[i];\n", - " var width, height;\n", - " if (entry.contentBoxSize) {\n", - " if (entry.contentBoxSize instanceof Array) {\n", - " // Chrome 84 implements new version of spec.\n", - " width = entry.contentBoxSize[0].inlineSize;\n", - " height = entry.contentBoxSize[0].blockSize;\n", - " } else {\n", - " // Firefox implements old version of spec.\n", - " width = entry.contentBoxSize.inlineSize;\n", - " height = entry.contentBoxSize.blockSize;\n", - " }\n", - " } else {\n", - " // Chrome <84 implements even older version of spec.\n", - " width = entry.contentRect.width;\n", - " height = entry.contentRect.height;\n", - " }\n", - "\n", - " // Keep the size of the canvas and rubber band canvas in sync with\n", - " // the canvas container.\n", - " if (entry.devicePixelContentBoxSize) {\n", - " // Chrome 84 implements new version of spec.\n", - " canvas.setAttribute(\n", - " 'width',\n", - " entry.devicePixelContentBoxSize[0].inlineSize\n", - " );\n", - " canvas.setAttribute(\n", - " 'height',\n", - " entry.devicePixelContentBoxSize[0].blockSize\n", - " );\n", - " } else {\n", - " canvas.setAttribute('width', width * fig.ratio);\n", - " canvas.setAttribute('height', height * fig.ratio);\n", - " }\n", - " canvas.setAttribute(\n", - " 'style',\n", - " 'width: ' + width + 'px; height: ' + height + 'px;'\n", - " );\n", - "\n", - " rubberband_canvas.setAttribute('width', width);\n", - " rubberband_canvas.setAttribute('height', height);\n", - "\n", - " // And update the size in Python. We ignore the initial 0/0 size\n", - " // that occurs as the element is placed into the DOM, which should\n", - " // otherwise not happen due to the minimum size styling.\n", - " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", - " fig.request_resize(width, height);\n", - " }\n", - " }\n", - " });\n", - " this.resizeObserverInstance.observe(canvas_div);\n", - "\n", - " function on_mouse_event_closure(name) {\n", - " return function (event) {\n", - " return fig.mouse_event(event, name);\n", - " };\n", - " }\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mousedown',\n", - " on_mouse_event_closure('button_press')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseup',\n", - " on_mouse_event_closure('button_release')\n", - " );\n", - " // Throttle sequential mouse events to 1 every 20ms.\n", - " rubberband_canvas.addEventListener(\n", - " 'mousemove',\n", - " on_mouse_event_closure('motion_notify')\n", - " );\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseenter',\n", - " on_mouse_event_closure('figure_enter')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseleave',\n", - " on_mouse_event_closure('figure_leave')\n", - " );\n", - "\n", - " canvas_div.addEventListener('wheel', function (event) {\n", - " if (event.deltaY < 0) {\n", - " event.step = 1;\n", - " } else {\n", - " event.step = -1;\n", - " }\n", - " on_mouse_event_closure('scroll')(event);\n", - " });\n", - "\n", - " canvas_div.appendChild(canvas);\n", - " canvas_div.appendChild(rubberband_canvas);\n", - "\n", - " this.rubberband_context = rubberband_canvas.getContext('2d');\n", - " this.rubberband_context.strokeStyle = '#000000';\n", - "\n", - " this._resize_canvas = function (width, height, forward) {\n", - " if (forward) {\n", - " canvas_div.style.width = width + 'px';\n", - " canvas_div.style.height = height + 'px';\n", - " }\n", - " };\n", - "\n", - " // Disable right mouse context menu.\n", - " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", - " event.preventDefault();\n", - " return false;\n", - " });\n", - "\n", - " function set_focus() {\n", - " canvas.focus();\n", - " canvas_div.focus();\n", - " }\n", - "\n", - " window.setTimeout(set_focus, 100);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'mpl-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " continue;\n", - " }\n", - "\n", - " var button = (fig.buttons[name] = document.createElement('button'));\n", - " button.classList = 'mpl-widget';\n", - " button.setAttribute('role', 'button');\n", - " button.setAttribute('aria-disabled', 'false');\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - "\n", - " var icon_img = document.createElement('img');\n", - " icon_img.src = '_images/' + image + '.png';\n", - " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", - " icon_img.alt = tooltip;\n", - " button.appendChild(icon_img);\n", - "\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " var fmt_picker = document.createElement('select');\n", - " fmt_picker.classList = 'mpl-widget';\n", - " toolbar.appendChild(fmt_picker);\n", - " this.format_dropdown = fmt_picker;\n", - "\n", - " for (var ind in mpl.extensions) {\n", - " var fmt = mpl.extensions[ind];\n", - " var option = document.createElement('option');\n", - " option.selected = fmt === mpl.default_extension;\n", - " option.innerHTML = fmt;\n", - " fmt_picker.appendChild(option);\n", - " }\n", - "\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "};\n", - "\n", - "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", - " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", - " // which will in turn request a refresh of the image.\n", - " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", - "};\n", - "\n", - "mpl.figure.prototype.send_message = function (type, properties) {\n", - " properties['type'] = type;\n", - " properties['figure_id'] = this.id;\n", - " this.ws.send(JSON.stringify(properties));\n", - "};\n", - "\n", - "mpl.figure.prototype.send_draw_message = function () {\n", - " if (!this.waiting) {\n", - " this.waiting = true;\n", - " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " var format_dropdown = fig.format_dropdown;\n", - " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", - " fig.ondownload(fig, format);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", - " var size = msg['size'];\n", - " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", - " fig._resize_canvas(size[0], size[1], msg['forward']);\n", - " fig.send_message('refresh', {});\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", - " var x0 = msg['x0'] / fig.ratio;\n", - " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", - " var x1 = msg['x1'] / fig.ratio;\n", - " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", - " x0 = Math.floor(x0) + 0.5;\n", - " y0 = Math.floor(y0) + 0.5;\n", - " x1 = Math.floor(x1) + 0.5;\n", - " y1 = Math.floor(y1) + 0.5;\n", - " var min_x = Math.min(x0, x1);\n", - " var min_y = Math.min(y0, y1);\n", - " var width = Math.abs(x1 - x0);\n", - " var height = Math.abs(y1 - y0);\n", - "\n", - " fig.rubberband_context.clearRect(\n", - " 0,\n", - " 0,\n", - " fig.canvas.width / fig.ratio,\n", - " fig.canvas.height / fig.ratio\n", - " );\n", - "\n", - " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", - " // Updates the figure title.\n", - " fig.header.textContent = msg['label'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", - " var cursor = msg['cursor'];\n", - " switch (cursor) {\n", - " case 0:\n", - " cursor = 'pointer';\n", - " break;\n", - " case 1:\n", - " cursor = 'default';\n", - " break;\n", - " case 2:\n", - " cursor = 'crosshair';\n", - " break;\n", - " case 3:\n", - " cursor = 'move';\n", - " break;\n", - " }\n", - " fig.rubberband_canvas.style.cursor = cursor;\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_message = function (fig, msg) {\n", - " fig.message.textContent = msg['message'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", - " // Request the server to send over a new figure.\n", - " fig.send_draw_message();\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", - " fig.image_mode = msg['mode'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", - " for (var key in msg) {\n", - " if (!(key in fig.buttons)) {\n", - " continue;\n", - " }\n", - " fig.buttons[key].disabled = !msg[key];\n", - " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", - " if (msg['mode'] === 'PAN') {\n", - " fig.buttons['Pan'].classList.add('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " } else if (msg['mode'] === 'ZOOM') {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.add('active');\n", - " } else {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Called whenever the canvas gets updated.\n", - " this.send_message('ack', {});\n", - "};\n", - "\n", - "// A function to construct a web socket function for onmessage handling.\n", - "// Called in the figure constructor.\n", - "mpl.figure.prototype._make_on_message_function = function (fig) {\n", - " return function socket_on_message(evt) {\n", - " if (evt.data instanceof Blob) {\n", - " /* FIXME: We get \"Resource interpreted as Image but\n", - " * transferred with MIME type text/plain:\" errors on\n", - " * Chrome. But how to set the MIME type? It doesn't seem\n", - " * to be part of the websocket stream */\n", - " evt.data.type = 'image/png';\n", - "\n", - " /* Free the memory for the previous frames */\n", - " if (fig.imageObj.src) {\n", - " (window.URL || window.webkitURL).revokeObjectURL(\n", - " fig.imageObj.src\n", - " );\n", - " }\n", - "\n", - " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", - " evt.data\n", - " );\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " } else if (\n", - " typeof evt.data === 'string' &&\n", - " evt.data.slice(0, 21) === 'data:image/png;base64'\n", - " ) {\n", - " fig.imageObj.src = evt.data;\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " }\n", - "\n", - " var msg = JSON.parse(evt.data);\n", - " var msg_type = msg['type'];\n", - "\n", - " // Call the \"handle_{type}\" callback, which takes\n", - " // the figure and JSON message as its only arguments.\n", - " try {\n", - " var callback = fig['handle_' + msg_type];\n", - " } catch (e) {\n", - " console.log(\n", - " \"No handler for the '\" + msg_type + \"' message type: \",\n", - " msg\n", - " );\n", - " return;\n", - " }\n", - "\n", - " if (callback) {\n", - " try {\n", - " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", - " callback(fig, msg);\n", - " } catch (e) {\n", - " console.log(\n", - " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", - " e,\n", - " e.stack,\n", - " msg\n", - " );\n", - " }\n", - " }\n", - " };\n", - "};\n", - "\n", - "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", - "mpl.findpos = function (e) {\n", - " //this section is from http://www.quirksmode.org/js/events_properties.html\n", - " var targ;\n", - " if (!e) {\n", - " e = window.event;\n", - " }\n", - " if (e.target) {\n", - " targ = e.target;\n", - " } else if (e.srcElement) {\n", - " targ = e.srcElement;\n", - " }\n", - " if (targ.nodeType === 3) {\n", - " // defeat Safari bug\n", - " targ = targ.parentNode;\n", - " }\n", - "\n", - " // pageX,Y are the mouse positions relative to the document\n", - " var boundingRect = targ.getBoundingClientRect();\n", - " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", - " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", - "\n", - " return { x: x, y: y };\n", - "};\n", - "\n", - "/*\n", - " * return a copy of an object with only non-object keys\n", - " * we need this to avoid circular references\n", - " * http://stackoverflow.com/a/24161582/3208463\n", - " */\n", - "function simpleKeys(original) {\n", - " return Object.keys(original).reduce(function (obj, key) {\n", - " if (typeof original[key] !== 'object') {\n", - " obj[key] = original[key];\n", - " }\n", - " return obj;\n", - " }, {});\n", - "}\n", - "\n", - "mpl.figure.prototype.mouse_event = function (event, name) {\n", - " var canvas_pos = mpl.findpos(event);\n", - "\n", - " if (name === 'button_press') {\n", - " this.canvas.focus();\n", - " this.canvas_div.focus();\n", - " }\n", - "\n", - " var x = canvas_pos.x * this.ratio;\n", - " var y = canvas_pos.y * this.ratio;\n", - "\n", - " this.send_message(name, {\n", - " x: x,\n", - " y: y,\n", - " button: event.button,\n", - " step: event.step,\n", - " guiEvent: simpleKeys(event),\n", - " });\n", - "\n", - " /* This prevents the web browser from automatically changing to\n", - " * the text insertion cursor when the button is pressed. We want\n", - " * to control all of the cursor setting manually through the\n", - " * 'cursor' event from matplotlib */\n", - " event.preventDefault();\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", - " // Handle any extra behaviour associated with a key event\n", - "};\n", - "\n", - "mpl.figure.prototype.key_event = function (event, name) {\n", - " // Prevent repeat events\n", - " if (name === 'key_press') {\n", - " if (event.which === this._key) {\n", - " return;\n", - " } else {\n", - " this._key = event.which;\n", - " }\n", - " }\n", - " if (name === 'key_release') {\n", - " this._key = null;\n", - " }\n", - "\n", - " var value = '';\n", - " if (event.ctrlKey && event.which !== 17) {\n", - " value += 'ctrl+';\n", - " }\n", - " if (event.altKey && event.which !== 18) {\n", - " value += 'alt+';\n", - " }\n", - " if (event.shiftKey && event.which !== 16) {\n", - " value += 'shift+';\n", - " }\n", - "\n", - " value += 'k';\n", - " value += event.which.toString();\n", - "\n", - " this._key_event_extra(event, name);\n", - "\n", - " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", - " if (name === 'download') {\n", - " this.handle_save(this, null);\n", - " } else {\n", - " this.send_message('toolbar_button', { name: name });\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", - " this.message.textContent = tooltip;\n", - "};\n", - "\n", - "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", - "// prettier-ignore\n", - "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", - "\n", - "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", - "\n", - "mpl.default_extension = \"png\";/* global mpl */\n", - "\n", - "var comm_websocket_adapter = function (comm) {\n", - " // Create a \"websocket\"-like object which calls the given IPython comm\n", - " // object with the appropriate methods. Currently this is a non binary\n", - " // socket, so there is still some room for performance tuning.\n", - " var ws = {};\n", - "\n", - " ws.close = function () {\n", - " comm.close();\n", - " };\n", - " ws.send = function (m) {\n", - " //console.log('sending', m);\n", - " comm.send(m);\n", - " };\n", - " // Register the callback with on_msg.\n", - " comm.on_msg(function (msg) {\n", - " //console.log('receiving', msg['content']['data'], msg);\n", - " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", - " ws.onmessage(msg['content']['data']);\n", - " });\n", - " return ws;\n", - "};\n", - "\n", - "mpl.mpl_figure_comm = function (comm, msg) {\n", - " // This is the function which gets called when the mpl process\n", - " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", - "\n", - " var id = msg.content.data.id;\n", - " // Get hold of the div created by the display call when the Comm\n", - " // socket was opened in Python.\n", - " var element = document.getElementById(id);\n", - " var ws_proxy = comm_websocket_adapter(comm);\n", - "\n", - " function ondownload(figure, _format) {\n", - " window.open(figure.canvas.toDataURL());\n", - " }\n", - "\n", - " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", - "\n", - " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", - " // web socket which is closed, not our websocket->open comm proxy.\n", - " ws_proxy.onopen();\n", - "\n", - " fig.parent_element = element;\n", - " fig.cell_info = mpl.find_output_cell(\"
\");\n", - " if (!fig.cell_info) {\n", - " console.error('Failed to find cell for figure', id, fig);\n", - " return;\n", - " }\n", - " fig.cell_info[0].output_area.element.on(\n", - " 'cleared',\n", - " { fig: fig },\n", - " fig._remove_fig_handler\n", - " );\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_close = function (fig, msg) {\n", - " var width = fig.canvas.width / fig.ratio;\n", - " fig.cell_info[0].output_area.element.off(\n", - " 'cleared',\n", - " fig._remove_fig_handler\n", - " );\n", - " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", - "\n", - " // Update the output cell to use the data from the current canvas.\n", - " fig.push_to_output();\n", - " var dataURL = fig.canvas.toDataURL();\n", - " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", - " // the notebook keyboard shortcuts fail.\n", - " IPython.keyboard_manager.enable();\n", - " fig.parent_element.innerHTML =\n", - " '';\n", - " fig.close_ws(fig, msg);\n", - "};\n", - "\n", - "mpl.figure.prototype.close_ws = function (fig, msg) {\n", - " fig.send_message('closing', msg);\n", - " // fig.ws.close()\n", - "};\n", - "\n", - "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", - " // Turn the data on the canvas into data in the output cell.\n", - " var width = this.canvas.width / this.ratio;\n", - " var dataURL = this.canvas.toDataURL();\n", - " this.cell_info[1]['text/html'] =\n", - " '';\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Tell IPython that the notebook contents must change.\n", - " IPython.notebook.set_dirty(true);\n", - " this.send_message('ack', {});\n", - " var fig = this;\n", - " // Wait a second, then push the new image to the DOM so\n", - " // that it is saved nicely (might be nice to debounce this).\n", - " setTimeout(function () {\n", - " fig.push_to_output();\n", - " }, 1000);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'btn-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " var button;\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " continue;\n", - " }\n", - "\n", - " button = fig.buttons[name] = document.createElement('button');\n", - " button.classList = 'btn btn-default';\n", - " button.href = '#';\n", - " button.title = name;\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " // Add the status bar.\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message pull-right';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "\n", - " // Add the close button to the window.\n", - " var buttongrp = document.createElement('div');\n", - " buttongrp.classList = 'btn-group inline pull-right';\n", - " button = document.createElement('button');\n", - " button.classList = 'btn btn-mini btn-primary';\n", - " button.href = '#';\n", - " button.title = 'Stop Interaction';\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', function (_evt) {\n", - " fig.handle_close(fig, {});\n", - " });\n", - " button.addEventListener(\n", - " 'mouseover',\n", - " on_mouseover_closure('Stop Interaction')\n", - " );\n", - " buttongrp.appendChild(button);\n", - " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", - " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", - "};\n", - "\n", - "mpl.figure.prototype._remove_fig_handler = function (event) {\n", - " var fig = event.data.fig;\n", - " if (event.target !== this) {\n", - " // Ignore bubbled events from children.\n", - " return;\n", - " }\n", - " fig.close_ws(fig, {});\n", - "};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (el) {\n", - " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (el) {\n", - " // this is important to make the div 'focusable\n", - " el.setAttribute('tabindex', 0);\n", - " // reach out to IPython and tell the keyboard manager to turn it's self\n", - " // off when our div gets focus\n", - "\n", - " // location in version 3\n", - " if (IPython.notebook.keyboard_manager) {\n", - " IPython.notebook.keyboard_manager.register_events(el);\n", - " } else {\n", - " // location in version 2\n", - " IPython.keyboard_manager.register_events(el);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", - " var manager = IPython.notebook.keyboard_manager;\n", - " if (!manager) {\n", - " manager = IPython.keyboard_manager;\n", - " }\n", - "\n", - " // Check for shift+enter\n", - " if (event.shiftKey && event.which === 13) {\n", - " this.canvas_div.blur();\n", - " // select the cell after this one\n", - " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", - " IPython.notebook.select(index + 1);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " fig.ondownload(fig, null);\n", - "};\n", - "\n", - "mpl.find_output_cell = function (html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i = 0; i < ncells; i++) {\n", - " var cell = cells[i];\n", - " if (cell.cell_type === 'code') {\n", - " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", - " var data = cell.output_area.outputs[j];\n", - " if (data.data) {\n", - " // IPython >= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] === html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "};\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel !== null) {\n", - " IPython.notebook.kernel.comm_manager.register_target(\n", - " 'matplotlib',\n", - " mpl.mpl_figure_comm\n", - " );\n", - "}\n" - ], + "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n if (typeof WebSocket !== 'undefined') {\n return WebSocket;\n } else if (typeof MozWebSocket !== 'undefined') {\n return MozWebSocket;\n } else {\n alert(\n 'Your browser does not have WebSocket support. ' +\n 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n 'Firefox 4 and 5 are also supported but you ' +\n 'have to enable WebSockets in about:config.'\n );\n }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n this.id = figure_id;\n\n this.ws = websocket;\n\n this.supports_binary = this.ws.binaryType !== undefined;\n\n if (!this.supports_binary) {\n var warnings = document.getElementById('mpl-warnings');\n if (warnings) {\n warnings.style.display = 'block';\n warnings.textContent =\n 'This browser does not support binary websocket messages. ' +\n 'Performance may be slow.';\n }\n }\n\n this.imageObj = new Image();\n\n this.context = undefined;\n this.message = undefined;\n this.canvas = undefined;\n this.rubberband_canvas = undefined;\n this.rubberband_context = undefined;\n this.format_dropdown = undefined;\n\n this.image_mode = 'full';\n\n this.root = document.createElement('div');\n this.root.setAttribute('style', 'display: inline-block');\n this._root_extra_style(this.root);\n\n parent_element.appendChild(this.root);\n\n this._init_header(this);\n this._init_canvas(this);\n this._init_toolbar(this);\n\n var fig = this;\n\n this.waiting = false;\n\n this.ws.onopen = function () {\n fig.send_message('supports_binary', { value: fig.supports_binary });\n fig.send_message('send_image_mode', {});\n if (fig.ratio !== 1) {\n fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n }\n fig.send_message('refresh', {});\n };\n\n this.imageObj.onload = function () {\n if (fig.image_mode === 'full') {\n // Full images could contain transparency (where diff images\n // almost always do), so we need to clear the canvas so that\n // there is no ghosting.\n fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n }\n fig.context.drawImage(fig.imageObj, 0, 0);\n };\n\n this.imageObj.onunload = function () {\n fig.ws.close();\n };\n\n this.ws.onmessage = this._make_on_message_function(this);\n\n this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n var titlebar = document.createElement('div');\n titlebar.classList =\n 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n var titletext = document.createElement('div');\n titletext.classList = 'ui-dialog-title';\n titletext.setAttribute(\n 'style',\n 'width: 100%; text-align: center; padding: 3px;'\n );\n titlebar.appendChild(titletext);\n this.root.appendChild(titlebar);\n this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n var fig = this;\n\n var canvas_div = (this.canvas_div = document.createElement('div'));\n canvas_div.setAttribute(\n 'style',\n 'border: 1px solid #ddd;' +\n 'box-sizing: content-box;' +\n 'clear: both;' +\n 'min-height: 1px;' +\n 'min-width: 1px;' +\n 'outline: 0;' +\n 'overflow: hidden;' +\n 'position: relative;' +\n 'resize: both;'\n );\n\n function on_keyboard_event_closure(name) {\n return function (event) {\n return fig.key_event(event, name);\n };\n }\n\n canvas_div.addEventListener(\n 'keydown',\n on_keyboard_event_closure('key_press')\n );\n canvas_div.addEventListener(\n 'keyup',\n on_keyboard_event_closure('key_release')\n );\n\n this._canvas_extra_style(canvas_div);\n this.root.appendChild(canvas_div);\n\n var canvas = (this.canvas = document.createElement('canvas'));\n canvas.classList.add('mpl-canvas');\n canvas.setAttribute('style', 'box-sizing: content-box;');\n\n this.context = canvas.getContext('2d');\n\n var backingStore =\n this.context.backingStorePixelRatio ||\n this.context.webkitBackingStorePixelRatio ||\n this.context.mozBackingStorePixelRatio ||\n this.context.msBackingStorePixelRatio ||\n this.context.oBackingStorePixelRatio ||\n this.context.backingStorePixelRatio ||\n 1;\n\n this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n 'canvas'\n ));\n rubberband_canvas.setAttribute(\n 'style',\n 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n );\n\n // Apply a ponyfill if ResizeObserver is not implemented by browser.\n if (this.ResizeObserver === undefined) {\n if (window.ResizeObserver !== undefined) {\n this.ResizeObserver = window.ResizeObserver;\n } else {\n var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n this.ResizeObserver = obs.ResizeObserver;\n }\n }\n\n this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n var nentries = entries.length;\n for (var i = 0; i < nentries; i++) {\n var entry = entries[i];\n var width, height;\n if (entry.contentBoxSize) {\n if (entry.contentBoxSize instanceof Array) {\n // Chrome 84 implements new version of spec.\n width = entry.contentBoxSize[0].inlineSize;\n height = entry.contentBoxSize[0].blockSize;\n } else {\n // Firefox implements old version of spec.\n width = entry.contentBoxSize.inlineSize;\n height = entry.contentBoxSize.blockSize;\n }\n } else {\n // Chrome <84 implements even older version of spec.\n width = entry.contentRect.width;\n height = entry.contentRect.height;\n }\n\n // Keep the size of the canvas and rubber band canvas in sync with\n // the canvas container.\n if (entry.devicePixelContentBoxSize) {\n // Chrome 84 implements new version of spec.\n canvas.setAttribute(\n 'width',\n entry.devicePixelContentBoxSize[0].inlineSize\n );\n canvas.setAttribute(\n 'height',\n entry.devicePixelContentBoxSize[0].blockSize\n );\n } else {\n canvas.setAttribute('width', width * fig.ratio);\n canvas.setAttribute('height', height * fig.ratio);\n }\n canvas.setAttribute(\n 'style',\n 'width: ' + width + 'px; height: ' + height + 'px;'\n );\n\n rubberband_canvas.setAttribute('width', width);\n rubberband_canvas.setAttribute('height', height);\n\n // And update the size in Python. We ignore the initial 0/0 size\n // that occurs as the element is placed into the DOM, which should\n // otherwise not happen due to the minimum size styling.\n if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n fig.request_resize(width, height);\n }\n }\n });\n this.resizeObserverInstance.observe(canvas_div);\n\n function on_mouse_event_closure(name) {\n return function (event) {\n return fig.mouse_event(event, name);\n };\n }\n\n rubberband_canvas.addEventListener(\n 'mousedown',\n on_mouse_event_closure('button_press')\n );\n rubberband_canvas.addEventListener(\n 'mouseup',\n on_mouse_event_closure('button_release')\n );\n // Throttle sequential mouse events to 1 every 20ms.\n rubberband_canvas.addEventListener(\n 'mousemove',\n on_mouse_event_closure('motion_notify')\n );\n\n rubberband_canvas.addEventListener(\n 'mouseenter',\n on_mouse_event_closure('figure_enter')\n );\n rubberband_canvas.addEventListener(\n 'mouseleave',\n on_mouse_event_closure('figure_leave')\n );\n\n canvas_div.addEventListener('wheel', function (event) {\n if (event.deltaY < 0) {\n event.step = 1;\n } else {\n event.step = -1;\n }\n on_mouse_event_closure('scroll')(event);\n });\n\n canvas_div.appendChild(canvas);\n canvas_div.appendChild(rubberband_canvas);\n\n this.rubberband_context = rubberband_canvas.getContext('2d');\n this.rubberband_context.strokeStyle = '#000000';\n\n this._resize_canvas = function (width, height, forward) {\n if (forward) {\n canvas_div.style.width = width + 'px';\n canvas_div.style.height = height + 'px';\n }\n };\n\n // Disable right mouse context menu.\n this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n event.preventDefault();\n return false;\n });\n\n function set_focus() {\n canvas.focus();\n canvas_div.focus();\n }\n\n window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'mpl-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n continue;\n }\n\n var button = (fig.buttons[name] = document.createElement('button'));\n button.classList = 'mpl-widget';\n button.setAttribute('role', 'button');\n button.setAttribute('aria-disabled', 'false');\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n var icon_img = document.createElement('img');\n icon_img.src = '_images/' + image + '.png';\n icon_img.srcset = '_images/' + image + '_large.png 2x';\n icon_img.alt = tooltip;\n button.appendChild(icon_img);\n\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n var fmt_picker = document.createElement('select');\n fmt_picker.classList = 'mpl-widget';\n toolbar.appendChild(fmt_picker);\n this.format_dropdown = fmt_picker;\n\n for (var ind in mpl.extensions) {\n var fmt = mpl.extensions[ind];\n var option = document.createElement('option');\n option.selected = fmt === mpl.default_extension;\n option.innerHTML = fmt;\n fmt_picker.appendChild(option);\n }\n\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n // which will in turn request a refresh of the image.\n this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n properties['type'] = type;\n properties['figure_id'] = this.id;\n this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n if (!this.waiting) {\n this.waiting = true;\n this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n var format_dropdown = fig.format_dropdown;\n var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n var size = msg['size'];\n if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n fig._resize_canvas(size[0], size[1], msg['forward']);\n fig.send_message('refresh', {});\n }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n var x0 = msg['x0'] / fig.ratio;\n var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n var x1 = msg['x1'] / fig.ratio;\n var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n x0 = Math.floor(x0) + 0.5;\n y0 = Math.floor(y0) + 0.5;\n x1 = Math.floor(x1) + 0.5;\n y1 = Math.floor(y1) + 0.5;\n var min_x = Math.min(x0, x1);\n var min_y = Math.min(y0, y1);\n var width = Math.abs(x1 - x0);\n var height = Math.abs(y1 - y0);\n\n fig.rubberband_context.clearRect(\n 0,\n 0,\n fig.canvas.width / fig.ratio,\n fig.canvas.height / fig.ratio\n );\n\n fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n // Updates the figure title.\n fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n var cursor = msg['cursor'];\n switch (cursor) {\n case 0:\n cursor = 'pointer';\n break;\n case 1:\n cursor = 'default';\n break;\n case 2:\n cursor = 'crosshair';\n break;\n case 3:\n cursor = 'move';\n break;\n }\n fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n // Request the server to send over a new figure.\n fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n for (var key in msg) {\n if (!(key in fig.buttons)) {\n continue;\n }\n fig.buttons[key].disabled = !msg[key];\n fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n if (msg['mode'] === 'PAN') {\n fig.buttons['Pan'].classList.add('active');\n fig.buttons['Zoom'].classList.remove('active');\n } else if (msg['mode'] === 'ZOOM') {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.add('active');\n } else {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.remove('active');\n }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Called whenever the canvas gets updated.\n this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n return function socket_on_message(evt) {\n if (evt.data instanceof Blob) {\n /* FIXME: We get \"Resource interpreted as Image but\n * transferred with MIME type text/plain:\" errors on\n * Chrome. But how to set the MIME type? It doesn't seem\n * to be part of the websocket stream */\n evt.data.type = 'image/png';\n\n /* Free the memory for the previous frames */\n if (fig.imageObj.src) {\n (window.URL || window.webkitURL).revokeObjectURL(\n fig.imageObj.src\n );\n }\n\n fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n evt.data\n );\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n } else if (\n typeof evt.data === 'string' &&\n evt.data.slice(0, 21) === 'data:image/png;base64'\n ) {\n fig.imageObj.src = evt.data;\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n }\n\n var msg = JSON.parse(evt.data);\n var msg_type = msg['type'];\n\n // Call the \"handle_{type}\" callback, which takes\n // the figure and JSON message as its only arguments.\n try {\n var callback = fig['handle_' + msg_type];\n } catch (e) {\n console.log(\n \"No handler for the '\" + msg_type + \"' message type: \",\n msg\n );\n return;\n }\n\n if (callback) {\n try {\n // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n callback(fig, msg);\n } catch (e) {\n console.log(\n \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n e,\n e.stack,\n msg\n );\n }\n }\n };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n //this section is from http://www.quirksmode.org/js/events_properties.html\n var targ;\n if (!e) {\n e = window.event;\n }\n if (e.target) {\n targ = e.target;\n } else if (e.srcElement) {\n targ = e.srcElement;\n }\n if (targ.nodeType === 3) {\n // defeat Safari bug\n targ = targ.parentNode;\n }\n\n // pageX,Y are the mouse positions relative to the document\n var boundingRect = targ.getBoundingClientRect();\n var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n return Object.keys(original).reduce(function (obj, key) {\n if (typeof original[key] !== 'object') {\n obj[key] = original[key];\n }\n return obj;\n }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n var canvas_pos = mpl.findpos(event);\n\n if (name === 'button_press') {\n this.canvas.focus();\n this.canvas_div.focus();\n }\n\n var x = canvas_pos.x * this.ratio;\n var y = canvas_pos.y * this.ratio;\n\n this.send_message(name, {\n x: x,\n y: y,\n button: event.button,\n step: event.step,\n guiEvent: simpleKeys(event),\n });\n\n /* This prevents the web browser from automatically changing to\n * the text insertion cursor when the button is pressed. We want\n * to control all of the cursor setting manually through the\n * 'cursor' event from matplotlib */\n event.preventDefault();\n return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n // Prevent repeat events\n if (name === 'key_press') {\n if (event.which === this._key) {\n return;\n } else {\n this._key = event.which;\n }\n }\n if (name === 'key_release') {\n this._key = null;\n }\n\n var value = '';\n if (event.ctrlKey && event.which !== 17) {\n value += 'ctrl+';\n }\n if (event.altKey && event.which !== 18) {\n value += 'alt+';\n }\n if (event.shiftKey && event.which !== 16) {\n value += 'shift+';\n }\n\n value += 'k';\n value += event.which.toString();\n\n this._key_event_extra(event, name);\n\n this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n if (name === 'download') {\n this.handle_save(this, null);\n } else {\n this.send_message('toolbar_button', { name: name });\n }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\nmpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n\nmpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n // Create a \"websocket\"-like object which calls the given IPython comm\n // object with the appropriate methods. Currently this is a non binary\n // socket, so there is still some room for performance tuning.\n var ws = {};\n\n ws.close = function () {\n comm.close();\n };\n ws.send = function (m) {\n //console.log('sending', m);\n comm.send(m);\n };\n // Register the callback with on_msg.\n comm.on_msg(function (msg) {\n //console.log('receiving', msg['content']['data'], msg);\n // Pass the mpl event to the overridden (by mpl) onmessage function.\n ws.onmessage(msg['content']['data']);\n });\n return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n // This is the function which gets called when the mpl process\n // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n var id = msg.content.data.id;\n // Get hold of the div created by the display call when the Comm\n // socket was opened in Python.\n var element = document.getElementById(id);\n var ws_proxy = comm_websocket_adapter(comm);\n\n function ondownload(figure, _format) {\n window.open(figure.canvas.toDataURL());\n }\n\n var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n // web socket which is closed, not our websocket->open comm proxy.\n ws_proxy.onopen();\n\n fig.parent_element = element;\n fig.cell_info = mpl.find_output_cell(\"
\");\n if (!fig.cell_info) {\n console.error('Failed to find cell for figure', id, fig);\n return;\n }\n fig.cell_info[0].output_area.element.on(\n 'cleared',\n { fig: fig },\n fig._remove_fig_handler\n );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n var width = fig.canvas.width / fig.ratio;\n fig.cell_info[0].output_area.element.off(\n 'cleared',\n fig._remove_fig_handler\n );\n fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n // Update the output cell to use the data from the current canvas.\n fig.push_to_output();\n var dataURL = fig.canvas.toDataURL();\n // Re-enable the keyboard manager in IPython - without this line, in FF,\n // the notebook keyboard shortcuts fail.\n IPython.keyboard_manager.enable();\n fig.parent_element.innerHTML =\n '';\n fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n fig.send_message('closing', msg);\n // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n // Turn the data on the canvas into data in the output cell.\n var width = this.canvas.width / this.ratio;\n var dataURL = this.canvas.toDataURL();\n this.cell_info[1]['text/html'] =\n '';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Tell IPython that the notebook contents must change.\n IPython.notebook.set_dirty(true);\n this.send_message('ack', {});\n var fig = this;\n // Wait a second, then push the new image to the DOM so\n // that it is saved nicely (might be nice to debounce this).\n setTimeout(function () {\n fig.push_to_output();\n }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'btn-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n var button;\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n continue;\n }\n\n button = fig.buttons[name] = document.createElement('button');\n button.classList = 'btn btn-default';\n button.href = '#';\n button.title = name;\n button.innerHTML = '';\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n // Add the status bar.\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message pull-right';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n\n // Add the close button to the window.\n var buttongrp = document.createElement('div');\n buttongrp.classList = 'btn-group inline pull-right';\n button = document.createElement('button');\n button.classList = 'btn btn-mini btn-primary';\n button.href = '#';\n button.title = 'Stop Interaction';\n button.innerHTML = '';\n button.addEventListener('click', function (_evt) {\n fig.handle_close(fig, {});\n });\n button.addEventListener(\n 'mouseover',\n on_mouseover_closure('Stop Interaction')\n );\n buttongrp.appendChild(button);\n var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n var fig = event.data.fig;\n if (event.target !== this) {\n // Ignore bubbled events from children.\n return;\n }\n fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n // this is important to make the div 'focusable\n el.setAttribute('tabindex', 0);\n // reach out to IPython and tell the keyboard manager to turn it's self\n // off when our div gets focus\n\n // location in version 3\n if (IPython.notebook.keyboard_manager) {\n IPython.notebook.keyboard_manager.register_events(el);\n } else {\n // location in version 2\n IPython.keyboard_manager.register_events(el);\n }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n var manager = IPython.notebook.keyboard_manager;\n if (!manager) {\n manager = IPython.keyboard_manager;\n }\n\n // Check for shift+enter\n if (event.shiftKey && event.which === 13) {\n this.canvas_div.blur();\n // select the cell after this one\n var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n IPython.notebook.select(index + 1);\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n // Return the cell and output element which can be found *uniquely* in the notebook.\n // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n // IPython event is triggered only after the cells have been serialised, which for\n // our purposes (turning an active figure into a static one), is too late.\n var cells = IPython.notebook.get_cells();\n var ncells = cells.length;\n for (var i = 0; i < ncells; i++) {\n var cell = cells[i];\n if (cell.cell_type === 'code') {\n for (var j = 0; j < cell.output_area.outputs.length; j++) {\n var data = cell.output_area.outputs[j];\n if (data.data) {\n // IPython >= 3 moved mimebundle to data attribute of output\n data = data.data;\n }\n if (data['text/html'] === html_output) {\n return [cell, data, j];\n }\n }\n }\n }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n IPython.notebook.kernel.comm_manager.register_target(\n 'matplotlib',\n mpl.mpl_figure_comm\n );\n}\n", "text/plain": [ "" ] @@ -6404,955 +716,7 @@ "outputs": [ { "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "/* global mpl */\n", - "window.mpl = {};\n", - "\n", - "mpl.get_websocket_type = function () {\n", - " if (typeof WebSocket !== 'undefined') {\n", - " return WebSocket;\n", - " } else if (typeof MozWebSocket !== 'undefined') {\n", - " return MozWebSocket;\n", - " } else {\n", - " alert(\n", - " 'Your browser does not have WebSocket support. ' +\n", - " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", - " 'Firefox 4 and 5 are also supported but you ' +\n", - " 'have to enable WebSockets in about:config.'\n", - " );\n", - " }\n", - "};\n", - "\n", - "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", - " this.id = figure_id;\n", - "\n", - " this.ws = websocket;\n", - "\n", - " this.supports_binary = this.ws.binaryType !== undefined;\n", - "\n", - " if (!this.supports_binary) {\n", - " var warnings = document.getElementById('mpl-warnings');\n", - " if (warnings) {\n", - " warnings.style.display = 'block';\n", - " warnings.textContent =\n", - " 'This browser does not support binary websocket messages. ' +\n", - " 'Performance may be slow.';\n", - " }\n", - " }\n", - "\n", - " this.imageObj = new Image();\n", - "\n", - " this.context = undefined;\n", - " this.message = undefined;\n", - " this.canvas = undefined;\n", - " this.rubberband_canvas = undefined;\n", - " this.rubberband_context = undefined;\n", - " this.format_dropdown = undefined;\n", - "\n", - " this.image_mode = 'full';\n", - "\n", - " this.root = document.createElement('div');\n", - " this.root.setAttribute('style', 'display: inline-block');\n", - " this._root_extra_style(this.root);\n", - "\n", - " parent_element.appendChild(this.root);\n", - "\n", - " this._init_header(this);\n", - " this._init_canvas(this);\n", - " this._init_toolbar(this);\n", - "\n", - " var fig = this;\n", - "\n", - " this.waiting = false;\n", - "\n", - " this.ws.onopen = function () {\n", - " fig.send_message('supports_binary', { value: fig.supports_binary });\n", - " fig.send_message('send_image_mode', {});\n", - " if (fig.ratio !== 1) {\n", - " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", - " }\n", - " fig.send_message('refresh', {});\n", - " };\n", - "\n", - " this.imageObj.onload = function () {\n", - " if (fig.image_mode === 'full') {\n", - " // Full images could contain transparency (where diff images\n", - " // almost always do), so we need to clear the canvas so that\n", - " // there is no ghosting.\n", - " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", - " }\n", - " fig.context.drawImage(fig.imageObj, 0, 0);\n", - " };\n", - "\n", - " this.imageObj.onunload = function () {\n", - " fig.ws.close();\n", - " };\n", - "\n", - " this.ws.onmessage = this._make_on_message_function(this);\n", - "\n", - " this.ondownload = ondownload;\n", - "};\n", - "\n", - "mpl.figure.prototype._init_header = function () {\n", - " var titlebar = document.createElement('div');\n", - " titlebar.classList =\n", - " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", - " var titletext = document.createElement('div');\n", - " titletext.classList = 'ui-dialog-title';\n", - " titletext.setAttribute(\n", - " 'style',\n", - " 'width: 100%; text-align: center; padding: 3px;'\n", - " );\n", - " titlebar.appendChild(titletext);\n", - " this.root.appendChild(titlebar);\n", - " this.header = titletext;\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._init_canvas = function () {\n", - " var fig = this;\n", - "\n", - " var canvas_div = (this.canvas_div = document.createElement('div'));\n", - " canvas_div.setAttribute(\n", - " 'style',\n", - " 'border: 1px solid #ddd;' +\n", - " 'box-sizing: content-box;' +\n", - " 'clear: both;' +\n", - " 'min-height: 1px;' +\n", - " 'min-width: 1px;' +\n", - " 'outline: 0;' +\n", - " 'overflow: hidden;' +\n", - " 'position: relative;' +\n", - " 'resize: both;'\n", - " );\n", - "\n", - " function on_keyboard_event_closure(name) {\n", - " return function (event) {\n", - " return fig.key_event(event, name);\n", - " };\n", - " }\n", - "\n", - " canvas_div.addEventListener(\n", - " 'keydown',\n", - " on_keyboard_event_closure('key_press')\n", - " );\n", - " canvas_div.addEventListener(\n", - " 'keyup',\n", - " on_keyboard_event_closure('key_release')\n", - " );\n", - "\n", - " this._canvas_extra_style(canvas_div);\n", - " this.root.appendChild(canvas_div);\n", - "\n", - " var canvas = (this.canvas = document.createElement('canvas'));\n", - " canvas.classList.add('mpl-canvas');\n", - " canvas.setAttribute('style', 'box-sizing: content-box;');\n", - "\n", - " this.context = canvas.getContext('2d');\n", - "\n", - " var backingStore =\n", - " this.context.backingStorePixelRatio ||\n", - " this.context.webkitBackingStorePixelRatio ||\n", - " this.context.mozBackingStorePixelRatio ||\n", - " this.context.msBackingStorePixelRatio ||\n", - " this.context.oBackingStorePixelRatio ||\n", - " this.context.backingStorePixelRatio ||\n", - " 1;\n", - "\n", - " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", - "\n", - " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", - " 'canvas'\n", - " ));\n", - " rubberband_canvas.setAttribute(\n", - " 'style',\n", - " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", - " );\n", - "\n", - " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", - " if (this.ResizeObserver === undefined) {\n", - " if (window.ResizeObserver !== undefined) {\n", - " this.ResizeObserver = window.ResizeObserver;\n", - " } else {\n", - " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", - " this.ResizeObserver = obs.ResizeObserver;\n", - " }\n", - " }\n", - "\n", - " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", - " var nentries = entries.length;\n", - " for (var i = 0; i < nentries; i++) {\n", - " var entry = entries[i];\n", - " var width, height;\n", - " if (entry.contentBoxSize) {\n", - " if (entry.contentBoxSize instanceof Array) {\n", - " // Chrome 84 implements new version of spec.\n", - " width = entry.contentBoxSize[0].inlineSize;\n", - " height = entry.contentBoxSize[0].blockSize;\n", - " } else {\n", - " // Firefox implements old version of spec.\n", - " width = entry.contentBoxSize.inlineSize;\n", - " height = entry.contentBoxSize.blockSize;\n", - " }\n", - " } else {\n", - " // Chrome <84 implements even older version of spec.\n", - " width = entry.contentRect.width;\n", - " height = entry.contentRect.height;\n", - " }\n", - "\n", - " // Keep the size of the canvas and rubber band canvas in sync with\n", - " // the canvas container.\n", - " if (entry.devicePixelContentBoxSize) {\n", - " // Chrome 84 implements new version of spec.\n", - " canvas.setAttribute(\n", - " 'width',\n", - " entry.devicePixelContentBoxSize[0].inlineSize\n", - " );\n", - " canvas.setAttribute(\n", - " 'height',\n", - " entry.devicePixelContentBoxSize[0].blockSize\n", - " );\n", - " } else {\n", - " canvas.setAttribute('width', width * fig.ratio);\n", - " canvas.setAttribute('height', height * fig.ratio);\n", - " }\n", - " canvas.setAttribute(\n", - " 'style',\n", - " 'width: ' + width + 'px; height: ' + height + 'px;'\n", - " );\n", - "\n", - " rubberband_canvas.setAttribute('width', width);\n", - " rubberband_canvas.setAttribute('height', height);\n", - "\n", - " // And update the size in Python. We ignore the initial 0/0 size\n", - " // that occurs as the element is placed into the DOM, which should\n", - " // otherwise not happen due to the minimum size styling.\n", - " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", - " fig.request_resize(width, height);\n", - " }\n", - " }\n", - " });\n", - " this.resizeObserverInstance.observe(canvas_div);\n", - "\n", - " function on_mouse_event_closure(name) {\n", - " return function (event) {\n", - " return fig.mouse_event(event, name);\n", - " };\n", - " }\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mousedown',\n", - " on_mouse_event_closure('button_press')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseup',\n", - " on_mouse_event_closure('button_release')\n", - " );\n", - " // Throttle sequential mouse events to 1 every 20ms.\n", - " rubberband_canvas.addEventListener(\n", - " 'mousemove',\n", - " on_mouse_event_closure('motion_notify')\n", - " );\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseenter',\n", - " on_mouse_event_closure('figure_enter')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseleave',\n", - " on_mouse_event_closure('figure_leave')\n", - " );\n", - "\n", - " canvas_div.addEventListener('wheel', function (event) {\n", - " if (event.deltaY < 0) {\n", - " event.step = 1;\n", - " } else {\n", - " event.step = -1;\n", - " }\n", - " on_mouse_event_closure('scroll')(event);\n", - " });\n", - "\n", - " canvas_div.appendChild(canvas);\n", - " canvas_div.appendChild(rubberband_canvas);\n", - "\n", - " this.rubberband_context = rubberband_canvas.getContext('2d');\n", - " this.rubberband_context.strokeStyle = '#000000';\n", - "\n", - " this._resize_canvas = function (width, height, forward) {\n", - " if (forward) {\n", - " canvas_div.style.width = width + 'px';\n", - " canvas_div.style.height = height + 'px';\n", - " }\n", - " };\n", - "\n", - " // Disable right mouse context menu.\n", - " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", - " event.preventDefault();\n", - " return false;\n", - " });\n", - "\n", - " function set_focus() {\n", - " canvas.focus();\n", - " canvas_div.focus();\n", - " }\n", - "\n", - " window.setTimeout(set_focus, 100);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'mpl-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " continue;\n", - " }\n", - "\n", - " var button = (fig.buttons[name] = document.createElement('button'));\n", - " button.classList = 'mpl-widget';\n", - " button.setAttribute('role', 'button');\n", - " button.setAttribute('aria-disabled', 'false');\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - "\n", - " var icon_img = document.createElement('img');\n", - " icon_img.src = '_images/' + image + '.png';\n", - " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", - " icon_img.alt = tooltip;\n", - " button.appendChild(icon_img);\n", - "\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " var fmt_picker = document.createElement('select');\n", - " fmt_picker.classList = 'mpl-widget';\n", - " toolbar.appendChild(fmt_picker);\n", - " this.format_dropdown = fmt_picker;\n", - "\n", - " for (var ind in mpl.extensions) {\n", - " var fmt = mpl.extensions[ind];\n", - " var option = document.createElement('option');\n", - " option.selected = fmt === mpl.default_extension;\n", - " option.innerHTML = fmt;\n", - " fmt_picker.appendChild(option);\n", - " }\n", - "\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "};\n", - "\n", - "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", - " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", - " // which will in turn request a refresh of the image.\n", - " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", - "};\n", - "\n", - "mpl.figure.prototype.send_message = function (type, properties) {\n", - " properties['type'] = type;\n", - " properties['figure_id'] = this.id;\n", - " this.ws.send(JSON.stringify(properties));\n", - "};\n", - "\n", - "mpl.figure.prototype.send_draw_message = function () {\n", - " if (!this.waiting) {\n", - " this.waiting = true;\n", - " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " var format_dropdown = fig.format_dropdown;\n", - " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", - " fig.ondownload(fig, format);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", - " var size = msg['size'];\n", - " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", - " fig._resize_canvas(size[0], size[1], msg['forward']);\n", - " fig.send_message('refresh', {});\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", - " var x0 = msg['x0'] / fig.ratio;\n", - " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", - " var x1 = msg['x1'] / fig.ratio;\n", - " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", - " x0 = Math.floor(x0) + 0.5;\n", - " y0 = Math.floor(y0) + 0.5;\n", - " x1 = Math.floor(x1) + 0.5;\n", - " y1 = Math.floor(y1) + 0.5;\n", - " var min_x = Math.min(x0, x1);\n", - " var min_y = Math.min(y0, y1);\n", - " var width = Math.abs(x1 - x0);\n", - " var height = Math.abs(y1 - y0);\n", - "\n", - " fig.rubberband_context.clearRect(\n", - " 0,\n", - " 0,\n", - " fig.canvas.width / fig.ratio,\n", - " fig.canvas.height / fig.ratio\n", - " );\n", - "\n", - " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", - " // Updates the figure title.\n", - " fig.header.textContent = msg['label'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", - " var cursor = msg['cursor'];\n", - " switch (cursor) {\n", - " case 0:\n", - " cursor = 'pointer';\n", - " break;\n", - " case 1:\n", - " cursor = 'default';\n", - " break;\n", - " case 2:\n", - " cursor = 'crosshair';\n", - " break;\n", - " case 3:\n", - " cursor = 'move';\n", - " break;\n", - " }\n", - " fig.rubberband_canvas.style.cursor = cursor;\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_message = function (fig, msg) {\n", - " fig.message.textContent = msg['message'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", - " // Request the server to send over a new figure.\n", - " fig.send_draw_message();\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", - " fig.image_mode = msg['mode'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", - " for (var key in msg) {\n", - " if (!(key in fig.buttons)) {\n", - " continue;\n", - " }\n", - " fig.buttons[key].disabled = !msg[key];\n", - " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", - " if (msg['mode'] === 'PAN') {\n", - " fig.buttons['Pan'].classList.add('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " } else if (msg['mode'] === 'ZOOM') {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.add('active');\n", - " } else {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Called whenever the canvas gets updated.\n", - " this.send_message('ack', {});\n", - "};\n", - "\n", - "// A function to construct a web socket function for onmessage handling.\n", - "// Called in the figure constructor.\n", - "mpl.figure.prototype._make_on_message_function = function (fig) {\n", - " return function socket_on_message(evt) {\n", - " if (evt.data instanceof Blob) {\n", - " /* FIXME: We get \"Resource interpreted as Image but\n", - " * transferred with MIME type text/plain:\" errors on\n", - " * Chrome. But how to set the MIME type? It doesn't seem\n", - " * to be part of the websocket stream */\n", - " evt.data.type = 'image/png';\n", - "\n", - " /* Free the memory for the previous frames */\n", - " if (fig.imageObj.src) {\n", - " (window.URL || window.webkitURL).revokeObjectURL(\n", - " fig.imageObj.src\n", - " );\n", - " }\n", - "\n", - " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", - " evt.data\n", - " );\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " } else if (\n", - " typeof evt.data === 'string' &&\n", - " evt.data.slice(0, 21) === 'data:image/png;base64'\n", - " ) {\n", - " fig.imageObj.src = evt.data;\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " }\n", - "\n", - " var msg = JSON.parse(evt.data);\n", - " var msg_type = msg['type'];\n", - "\n", - " // Call the \"handle_{type}\" callback, which takes\n", - " // the figure and JSON message as its only arguments.\n", - " try {\n", - " var callback = fig['handle_' + msg_type];\n", - " } catch (e) {\n", - " console.log(\n", - " \"No handler for the '\" + msg_type + \"' message type: \",\n", - " msg\n", - " );\n", - " return;\n", - " }\n", - "\n", - " if (callback) {\n", - " try {\n", - " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", - " callback(fig, msg);\n", - " } catch (e) {\n", - " console.log(\n", - " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", - " e,\n", - " e.stack,\n", - " msg\n", - " );\n", - " }\n", - " }\n", - " };\n", - "};\n", - "\n", - "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", - "mpl.findpos = function (e) {\n", - " //this section is from http://www.quirksmode.org/js/events_properties.html\n", - " var targ;\n", - " if (!e) {\n", - " e = window.event;\n", - " }\n", - " if (e.target) {\n", - " targ = e.target;\n", - " } else if (e.srcElement) {\n", - " targ = e.srcElement;\n", - " }\n", - " if (targ.nodeType === 3) {\n", - " // defeat Safari bug\n", - " targ = targ.parentNode;\n", - " }\n", - "\n", - " // pageX,Y are the mouse positions relative to the document\n", - " var boundingRect = targ.getBoundingClientRect();\n", - " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", - " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", - "\n", - " return { x: x, y: y };\n", - "};\n", - "\n", - "/*\n", - " * return a copy of an object with only non-object keys\n", - " * we need this to avoid circular references\n", - " * http://stackoverflow.com/a/24161582/3208463\n", - " */\n", - "function simpleKeys(original) {\n", - " return Object.keys(original).reduce(function (obj, key) {\n", - " if (typeof original[key] !== 'object') {\n", - " obj[key] = original[key];\n", - " }\n", - " return obj;\n", - " }, {});\n", - "}\n", - "\n", - "mpl.figure.prototype.mouse_event = function (event, name) {\n", - " var canvas_pos = mpl.findpos(event);\n", - "\n", - " if (name === 'button_press') {\n", - " this.canvas.focus();\n", - " this.canvas_div.focus();\n", - " }\n", - "\n", - " var x = canvas_pos.x * this.ratio;\n", - " var y = canvas_pos.y * this.ratio;\n", - "\n", - " this.send_message(name, {\n", - " x: x,\n", - " y: y,\n", - " button: event.button,\n", - " step: event.step,\n", - " guiEvent: simpleKeys(event),\n", - " });\n", - "\n", - " /* This prevents the web browser from automatically changing to\n", - " * the text insertion cursor when the button is pressed. We want\n", - " * to control all of the cursor setting manually through the\n", - " * 'cursor' event from matplotlib */\n", - " event.preventDefault();\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", - " // Handle any extra behaviour associated with a key event\n", - "};\n", - "\n", - "mpl.figure.prototype.key_event = function (event, name) {\n", - " // Prevent repeat events\n", - " if (name === 'key_press') {\n", - " if (event.which === this._key) {\n", - " return;\n", - " } else {\n", - " this._key = event.which;\n", - " }\n", - " }\n", - " if (name === 'key_release') {\n", - " this._key = null;\n", - " }\n", - "\n", - " var value = '';\n", - " if (event.ctrlKey && event.which !== 17) {\n", - " value += 'ctrl+';\n", - " }\n", - " if (event.altKey && event.which !== 18) {\n", - " value += 'alt+';\n", - " }\n", - " if (event.shiftKey && event.which !== 16) {\n", - " value += 'shift+';\n", - " }\n", - "\n", - " value += 'k';\n", - " value += event.which.toString();\n", - "\n", - " this._key_event_extra(event, name);\n", - "\n", - " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", - " if (name === 'download') {\n", - " this.handle_save(this, null);\n", - " } else {\n", - " this.send_message('toolbar_button', { name: name });\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", - " this.message.textContent = tooltip;\n", - "};\n", - "\n", - "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", - "// prettier-ignore\n", - "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", - "\n", - "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", - "\n", - "mpl.default_extension = \"png\";/* global mpl */\n", - "\n", - "var comm_websocket_adapter = function (comm) {\n", - " // Create a \"websocket\"-like object which calls the given IPython comm\n", - " // object with the appropriate methods. Currently this is a non binary\n", - " // socket, so there is still some room for performance tuning.\n", - " var ws = {};\n", - "\n", - " ws.close = function () {\n", - " comm.close();\n", - " };\n", - " ws.send = function (m) {\n", - " //console.log('sending', m);\n", - " comm.send(m);\n", - " };\n", - " // Register the callback with on_msg.\n", - " comm.on_msg(function (msg) {\n", - " //console.log('receiving', msg['content']['data'], msg);\n", - " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", - " ws.onmessage(msg['content']['data']);\n", - " });\n", - " return ws;\n", - "};\n", - "\n", - "mpl.mpl_figure_comm = function (comm, msg) {\n", - " // This is the function which gets called when the mpl process\n", - " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", - "\n", - " var id = msg.content.data.id;\n", - " // Get hold of the div created by the display call when the Comm\n", - " // socket was opened in Python.\n", - " var element = document.getElementById(id);\n", - " var ws_proxy = comm_websocket_adapter(comm);\n", - "\n", - " function ondownload(figure, _format) {\n", - " window.open(figure.canvas.toDataURL());\n", - " }\n", - "\n", - " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", - "\n", - " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", - " // web socket which is closed, not our websocket->open comm proxy.\n", - " ws_proxy.onopen();\n", - "\n", - " fig.parent_element = element;\n", - " fig.cell_info = mpl.find_output_cell(\"
\");\n", - " if (!fig.cell_info) {\n", - " console.error('Failed to find cell for figure', id, fig);\n", - " return;\n", - " }\n", - " fig.cell_info[0].output_area.element.on(\n", - " 'cleared',\n", - " { fig: fig },\n", - " fig._remove_fig_handler\n", - " );\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_close = function (fig, msg) {\n", - " var width = fig.canvas.width / fig.ratio;\n", - " fig.cell_info[0].output_area.element.off(\n", - " 'cleared',\n", - " fig._remove_fig_handler\n", - " );\n", - " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", - "\n", - " // Update the output cell to use the data from the current canvas.\n", - " fig.push_to_output();\n", - " var dataURL = fig.canvas.toDataURL();\n", - " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", - " // the notebook keyboard shortcuts fail.\n", - " IPython.keyboard_manager.enable();\n", - " fig.parent_element.innerHTML =\n", - " '';\n", - " fig.close_ws(fig, msg);\n", - "};\n", - "\n", - "mpl.figure.prototype.close_ws = function (fig, msg) {\n", - " fig.send_message('closing', msg);\n", - " // fig.ws.close()\n", - "};\n", - "\n", - "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", - " // Turn the data on the canvas into data in the output cell.\n", - " var width = this.canvas.width / this.ratio;\n", - " var dataURL = this.canvas.toDataURL();\n", - " this.cell_info[1]['text/html'] =\n", - " '';\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Tell IPython that the notebook contents must change.\n", - " IPython.notebook.set_dirty(true);\n", - " this.send_message('ack', {});\n", - " var fig = this;\n", - " // Wait a second, then push the new image to the DOM so\n", - " // that it is saved nicely (might be nice to debounce this).\n", - " setTimeout(function () {\n", - " fig.push_to_output();\n", - " }, 1000);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'btn-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " var button;\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " continue;\n", - " }\n", - "\n", - " button = fig.buttons[name] = document.createElement('button');\n", - " button.classList = 'btn btn-default';\n", - " button.href = '#';\n", - " button.title = name;\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " // Add the status bar.\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message pull-right';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "\n", - " // Add the close button to the window.\n", - " var buttongrp = document.createElement('div');\n", - " buttongrp.classList = 'btn-group inline pull-right';\n", - " button = document.createElement('button');\n", - " button.classList = 'btn btn-mini btn-primary';\n", - " button.href = '#';\n", - " button.title = 'Stop Interaction';\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', function (_evt) {\n", - " fig.handle_close(fig, {});\n", - " });\n", - " button.addEventListener(\n", - " 'mouseover',\n", - " on_mouseover_closure('Stop Interaction')\n", - " );\n", - " buttongrp.appendChild(button);\n", - " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", - " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", - "};\n", - "\n", - "mpl.figure.prototype._remove_fig_handler = function (event) {\n", - " var fig = event.data.fig;\n", - " if (event.target !== this) {\n", - " // Ignore bubbled events from children.\n", - " return;\n", - " }\n", - " fig.close_ws(fig, {});\n", - "};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (el) {\n", - " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (el) {\n", - " // this is important to make the div 'focusable\n", - " el.setAttribute('tabindex', 0);\n", - " // reach out to IPython and tell the keyboard manager to turn it's self\n", - " // off when our div gets focus\n", - "\n", - " // location in version 3\n", - " if (IPython.notebook.keyboard_manager) {\n", - " IPython.notebook.keyboard_manager.register_events(el);\n", - " } else {\n", - " // location in version 2\n", - " IPython.keyboard_manager.register_events(el);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", - " var manager = IPython.notebook.keyboard_manager;\n", - " if (!manager) {\n", - " manager = IPython.keyboard_manager;\n", - " }\n", - "\n", - " // Check for shift+enter\n", - " if (event.shiftKey && event.which === 13) {\n", - " this.canvas_div.blur();\n", - " // select the cell after this one\n", - " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", - " IPython.notebook.select(index + 1);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " fig.ondownload(fig, null);\n", - "};\n", - "\n", - "mpl.find_output_cell = function (html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i = 0; i < ncells; i++) {\n", - " var cell = cells[i];\n", - " if (cell.cell_type === 'code') {\n", - " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", - " var data = cell.output_area.outputs[j];\n", - " if (data.data) {\n", - " // IPython >= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] === html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "};\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel !== null) {\n", - " IPython.notebook.kernel.comm_manager.register_target(\n", - " 'matplotlib',\n", - " mpl.mpl_figure_comm\n", - " );\n", - "}\n" - ], + "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n if (typeof WebSocket !== 'undefined') {\n return WebSocket;\n } else if (typeof MozWebSocket !== 'undefined') {\n return MozWebSocket;\n } else {\n alert(\n 'Your browser does not have WebSocket support. ' +\n 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n 'Firefox 4 and 5 are also supported but you ' +\n 'have to enable WebSockets in about:config.'\n );\n }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n this.id = figure_id;\n\n this.ws = websocket;\n\n this.supports_binary = this.ws.binaryType !== undefined;\n\n if (!this.supports_binary) {\n var warnings = document.getElementById('mpl-warnings');\n if (warnings) {\n warnings.style.display = 'block';\n warnings.textContent =\n 'This browser does not support binary websocket messages. ' +\n 'Performance may be slow.';\n }\n }\n\n this.imageObj = new Image();\n\n this.context = undefined;\n this.message = undefined;\n this.canvas = undefined;\n this.rubberband_canvas = undefined;\n this.rubberband_context = undefined;\n this.format_dropdown = undefined;\n\n this.image_mode = 'full';\n\n this.root = document.createElement('div');\n this.root.setAttribute('style', 'display: inline-block');\n this._root_extra_style(this.root);\n\n parent_element.appendChild(this.root);\n\n this._init_header(this);\n this._init_canvas(this);\n this._init_toolbar(this);\n\n var fig = this;\n\n this.waiting = false;\n\n this.ws.onopen = function () {\n fig.send_message('supports_binary', { value: fig.supports_binary });\n fig.send_message('send_image_mode', {});\n if (fig.ratio !== 1) {\n fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n }\n fig.send_message('refresh', {});\n };\n\n this.imageObj.onload = function () {\n if (fig.image_mode === 'full') {\n // Full images could contain transparency (where diff images\n // almost always do), so we need to clear the canvas so that\n // there is no ghosting.\n fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n }\n fig.context.drawImage(fig.imageObj, 0, 0);\n };\n\n this.imageObj.onunload = function () {\n fig.ws.close();\n };\n\n this.ws.onmessage = this._make_on_message_function(this);\n\n this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n var titlebar = document.createElement('div');\n titlebar.classList =\n 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n var titletext = document.createElement('div');\n titletext.classList = 'ui-dialog-title';\n titletext.setAttribute(\n 'style',\n 'width: 100%; text-align: center; padding: 3px;'\n );\n titlebar.appendChild(titletext);\n this.root.appendChild(titlebar);\n this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n var fig = this;\n\n var canvas_div = (this.canvas_div = document.createElement('div'));\n canvas_div.setAttribute(\n 'style',\n 'border: 1px solid #ddd;' +\n 'box-sizing: content-box;' +\n 'clear: both;' +\n 'min-height: 1px;' +\n 'min-width: 1px;' +\n 'outline: 0;' +\n 'overflow: hidden;' +\n 'position: relative;' +\n 'resize: both;'\n );\n\n function on_keyboard_event_closure(name) {\n return function (event) {\n return fig.key_event(event, name);\n };\n }\n\n canvas_div.addEventListener(\n 'keydown',\n on_keyboard_event_closure('key_press')\n );\n canvas_div.addEventListener(\n 'keyup',\n on_keyboard_event_closure('key_release')\n );\n\n this._canvas_extra_style(canvas_div);\n this.root.appendChild(canvas_div);\n\n var canvas = (this.canvas = document.createElement('canvas'));\n canvas.classList.add('mpl-canvas');\n canvas.setAttribute('style', 'box-sizing: content-box;');\n\n this.context = canvas.getContext('2d');\n\n var backingStore =\n this.context.backingStorePixelRatio ||\n this.context.webkitBackingStorePixelRatio ||\n this.context.mozBackingStorePixelRatio ||\n this.context.msBackingStorePixelRatio ||\n this.context.oBackingStorePixelRatio ||\n this.context.backingStorePixelRatio ||\n 1;\n\n this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n 'canvas'\n ));\n rubberband_canvas.setAttribute(\n 'style',\n 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n );\n\n // Apply a ponyfill if ResizeObserver is not implemented by browser.\n if (this.ResizeObserver === undefined) {\n if (window.ResizeObserver !== undefined) {\n this.ResizeObserver = window.ResizeObserver;\n } else {\n var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n this.ResizeObserver = obs.ResizeObserver;\n }\n }\n\n this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n var nentries = entries.length;\n for (var i = 0; i < nentries; i++) {\n var entry = entries[i];\n var width, height;\n if (entry.contentBoxSize) {\n if (entry.contentBoxSize instanceof Array) {\n // Chrome 84 implements new version of spec.\n width = entry.contentBoxSize[0].inlineSize;\n height = entry.contentBoxSize[0].blockSize;\n } else {\n // Firefox implements old version of spec.\n width = entry.contentBoxSize.inlineSize;\n height = entry.contentBoxSize.blockSize;\n }\n } else {\n // Chrome <84 implements even older version of spec.\n width = entry.contentRect.width;\n height = entry.contentRect.height;\n }\n\n // Keep the size of the canvas and rubber band canvas in sync with\n // the canvas container.\n if (entry.devicePixelContentBoxSize) {\n // Chrome 84 implements new version of spec.\n canvas.setAttribute(\n 'width',\n entry.devicePixelContentBoxSize[0].inlineSize\n );\n canvas.setAttribute(\n 'height',\n entry.devicePixelContentBoxSize[0].blockSize\n );\n } else {\n canvas.setAttribute('width', width * fig.ratio);\n canvas.setAttribute('height', height * fig.ratio);\n }\n canvas.setAttribute(\n 'style',\n 'width: ' + width + 'px; height: ' + height + 'px;'\n );\n\n rubberband_canvas.setAttribute('width', width);\n rubberband_canvas.setAttribute('height', height);\n\n // And update the size in Python. We ignore the initial 0/0 size\n // that occurs as the element is placed into the DOM, which should\n // otherwise not happen due to the minimum size styling.\n if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n fig.request_resize(width, height);\n }\n }\n });\n this.resizeObserverInstance.observe(canvas_div);\n\n function on_mouse_event_closure(name) {\n return function (event) {\n return fig.mouse_event(event, name);\n };\n }\n\n rubberband_canvas.addEventListener(\n 'mousedown',\n on_mouse_event_closure('button_press')\n );\n rubberband_canvas.addEventListener(\n 'mouseup',\n on_mouse_event_closure('button_release')\n );\n // Throttle sequential mouse events to 1 every 20ms.\n rubberband_canvas.addEventListener(\n 'mousemove',\n on_mouse_event_closure('motion_notify')\n );\n\n rubberband_canvas.addEventListener(\n 'mouseenter',\n on_mouse_event_closure('figure_enter')\n );\n rubberband_canvas.addEventListener(\n 'mouseleave',\n on_mouse_event_closure('figure_leave')\n );\n\n canvas_div.addEventListener('wheel', function (event) {\n if (event.deltaY < 0) {\n event.step = 1;\n } else {\n event.step = -1;\n }\n on_mouse_event_closure('scroll')(event);\n });\n\n canvas_div.appendChild(canvas);\n canvas_div.appendChild(rubberband_canvas);\n\n this.rubberband_context = rubberband_canvas.getContext('2d');\n this.rubberband_context.strokeStyle = '#000000';\n\n this._resize_canvas = function (width, height, forward) {\n if (forward) {\n canvas_div.style.width = width + 'px';\n canvas_div.style.height = height + 'px';\n }\n };\n\n // Disable right mouse context menu.\n this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n event.preventDefault();\n return false;\n });\n\n function set_focus() {\n canvas.focus();\n canvas_div.focus();\n }\n\n window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'mpl-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n continue;\n }\n\n var button = (fig.buttons[name] = document.createElement('button'));\n button.classList = 'mpl-widget';\n button.setAttribute('role', 'button');\n button.setAttribute('aria-disabled', 'false');\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n var icon_img = document.createElement('img');\n icon_img.src = '_images/' + image + '.png';\n icon_img.srcset = '_images/' + image + '_large.png 2x';\n icon_img.alt = tooltip;\n button.appendChild(icon_img);\n\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n var fmt_picker = document.createElement('select');\n fmt_picker.classList = 'mpl-widget';\n toolbar.appendChild(fmt_picker);\n this.format_dropdown = fmt_picker;\n\n for (var ind in mpl.extensions) {\n var fmt = mpl.extensions[ind];\n var option = document.createElement('option');\n option.selected = fmt === mpl.default_extension;\n option.innerHTML = fmt;\n fmt_picker.appendChild(option);\n }\n\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n // which will in turn request a refresh of the image.\n this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n properties['type'] = type;\n properties['figure_id'] = this.id;\n this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n if (!this.waiting) {\n this.waiting = true;\n this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n var format_dropdown = fig.format_dropdown;\n var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n var size = msg['size'];\n if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n fig._resize_canvas(size[0], size[1], msg['forward']);\n fig.send_message('refresh', {});\n }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n var x0 = msg['x0'] / fig.ratio;\n var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n var x1 = msg['x1'] / fig.ratio;\n var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n x0 = Math.floor(x0) + 0.5;\n y0 = Math.floor(y0) + 0.5;\n x1 = Math.floor(x1) + 0.5;\n y1 = Math.floor(y1) + 0.5;\n var min_x = Math.min(x0, x1);\n var min_y = Math.min(y0, y1);\n var width = Math.abs(x1 - x0);\n var height = Math.abs(y1 - y0);\n\n fig.rubberband_context.clearRect(\n 0,\n 0,\n fig.canvas.width / fig.ratio,\n fig.canvas.height / fig.ratio\n );\n\n fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n // Updates the figure title.\n fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n var cursor = msg['cursor'];\n switch (cursor) {\n case 0:\n cursor = 'pointer';\n break;\n case 1:\n cursor = 'default';\n break;\n case 2:\n cursor = 'crosshair';\n break;\n case 3:\n cursor = 'move';\n break;\n }\n fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n // Request the server to send over a new figure.\n fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n for (var key in msg) {\n if (!(key in fig.buttons)) {\n continue;\n }\n fig.buttons[key].disabled = !msg[key];\n fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n if (msg['mode'] === 'PAN') {\n fig.buttons['Pan'].classList.add('active');\n fig.buttons['Zoom'].classList.remove('active');\n } else if (msg['mode'] === 'ZOOM') {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.add('active');\n } else {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.remove('active');\n }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Called whenever the canvas gets updated.\n this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n return function socket_on_message(evt) {\n if (evt.data instanceof Blob) {\n /* FIXME: We get \"Resource interpreted as Image but\n * transferred with MIME type text/plain:\" errors on\n * Chrome. But how to set the MIME type? It doesn't seem\n * to be part of the websocket stream */\n evt.data.type = 'image/png';\n\n /* Free the memory for the previous frames */\n if (fig.imageObj.src) {\n (window.URL || window.webkitURL).revokeObjectURL(\n fig.imageObj.src\n );\n }\n\n fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n evt.data\n );\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n } else if (\n typeof evt.data === 'string' &&\n evt.data.slice(0, 21) === 'data:image/png;base64'\n ) {\n fig.imageObj.src = evt.data;\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n }\n\n var msg = JSON.parse(evt.data);\n var msg_type = msg['type'];\n\n // Call the \"handle_{type}\" callback, which takes\n // the figure and JSON message as its only arguments.\n try {\n var callback = fig['handle_' + msg_type];\n } catch (e) {\n console.log(\n \"No handler for the '\" + msg_type + \"' message type: \",\n msg\n );\n return;\n }\n\n if (callback) {\n try {\n // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n callback(fig, msg);\n } catch (e) {\n console.log(\n \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n e,\n e.stack,\n msg\n );\n }\n }\n };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n //this section is from http://www.quirksmode.org/js/events_properties.html\n var targ;\n if (!e) {\n e = window.event;\n }\n if (e.target) {\n targ = e.target;\n } else if (e.srcElement) {\n targ = e.srcElement;\n }\n if (targ.nodeType === 3) {\n // defeat Safari bug\n targ = targ.parentNode;\n }\n\n // pageX,Y are the mouse positions relative to the document\n var boundingRect = targ.getBoundingClientRect();\n var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n return Object.keys(original).reduce(function (obj, key) {\n if (typeof original[key] !== 'object') {\n obj[key] = original[key];\n }\n return obj;\n }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n var canvas_pos = mpl.findpos(event);\n\n if (name === 'button_press') {\n this.canvas.focus();\n this.canvas_div.focus();\n }\n\n var x = canvas_pos.x * this.ratio;\n var y = canvas_pos.y * this.ratio;\n\n this.send_message(name, {\n x: x,\n y: y,\n button: event.button,\n step: event.step,\n guiEvent: simpleKeys(event),\n });\n\n /* This prevents the web browser from automatically changing to\n * the text insertion cursor when the button is pressed. We want\n * to control all of the cursor setting manually through the\n * 'cursor' event from matplotlib */\n event.preventDefault();\n return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n // Prevent repeat events\n if (name === 'key_press') {\n if (event.which === this._key) {\n return;\n } else {\n this._key = event.which;\n }\n }\n if (name === 'key_release') {\n this._key = null;\n }\n\n var value = '';\n if (event.ctrlKey && event.which !== 17) {\n value += 'ctrl+';\n }\n if (event.altKey && event.which !== 18) {\n value += 'alt+';\n }\n if (event.shiftKey && event.which !== 16) {\n value += 'shift+';\n }\n\n value += 'k';\n value += event.which.toString();\n\n this._key_event_extra(event, name);\n\n this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n if (name === 'download') {\n this.handle_save(this, null);\n } else {\n this.send_message('toolbar_button', { name: name });\n }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\nmpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n\nmpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n // Create a \"websocket\"-like object which calls the given IPython comm\n // object with the appropriate methods. Currently this is a non binary\n // socket, so there is still some room for performance tuning.\n var ws = {};\n\n ws.close = function () {\n comm.close();\n };\n ws.send = function (m) {\n //console.log('sending', m);\n comm.send(m);\n };\n // Register the callback with on_msg.\n comm.on_msg(function (msg) {\n //console.log('receiving', msg['content']['data'], msg);\n // Pass the mpl event to the overridden (by mpl) onmessage function.\n ws.onmessage(msg['content']['data']);\n });\n return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n // This is the function which gets called when the mpl process\n // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n var id = msg.content.data.id;\n // Get hold of the div created by the display call when the Comm\n // socket was opened in Python.\n var element = document.getElementById(id);\n var ws_proxy = comm_websocket_adapter(comm);\n\n function ondownload(figure, _format) {\n window.open(figure.canvas.toDataURL());\n }\n\n var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n // web socket which is closed, not our websocket->open comm proxy.\n ws_proxy.onopen();\n\n fig.parent_element = element;\n fig.cell_info = mpl.find_output_cell(\"
\");\n if (!fig.cell_info) {\n console.error('Failed to find cell for figure', id, fig);\n return;\n }\n fig.cell_info[0].output_area.element.on(\n 'cleared',\n { fig: fig },\n fig._remove_fig_handler\n );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n var width = fig.canvas.width / fig.ratio;\n fig.cell_info[0].output_area.element.off(\n 'cleared',\n fig._remove_fig_handler\n );\n fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n // Update the output cell to use the data from the current canvas.\n fig.push_to_output();\n var dataURL = fig.canvas.toDataURL();\n // Re-enable the keyboard manager in IPython - without this line, in FF,\n // the notebook keyboard shortcuts fail.\n IPython.keyboard_manager.enable();\n fig.parent_element.innerHTML =\n '';\n fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n fig.send_message('closing', msg);\n // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n // Turn the data on the canvas into data in the output cell.\n var width = this.canvas.width / this.ratio;\n var dataURL = this.canvas.toDataURL();\n this.cell_info[1]['text/html'] =\n '';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Tell IPython that the notebook contents must change.\n IPython.notebook.set_dirty(true);\n this.send_message('ack', {});\n var fig = this;\n // Wait a second, then push the new image to the DOM so\n // that it is saved nicely (might be nice to debounce this).\n setTimeout(function () {\n fig.push_to_output();\n }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'btn-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n var button;\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n continue;\n }\n\n button = fig.buttons[name] = document.createElement('button');\n button.classList = 'btn btn-default';\n button.href = '#';\n button.title = name;\n button.innerHTML = '';\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n // Add the status bar.\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message pull-right';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n\n // Add the close button to the window.\n var buttongrp = document.createElement('div');\n buttongrp.classList = 'btn-group inline pull-right';\n button = document.createElement('button');\n button.classList = 'btn btn-mini btn-primary';\n button.href = '#';\n button.title = 'Stop Interaction';\n button.innerHTML = '';\n button.addEventListener('click', function (_evt) {\n fig.handle_close(fig, {});\n });\n button.addEventListener(\n 'mouseover',\n on_mouseover_closure('Stop Interaction')\n );\n buttongrp.appendChild(button);\n var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n var fig = event.data.fig;\n if (event.target !== this) {\n // Ignore bubbled events from children.\n return;\n }\n fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n // this is important to make the div 'focusable\n el.setAttribute('tabindex', 0);\n // reach out to IPython and tell the keyboard manager to turn it's self\n // off when our div gets focus\n\n // location in version 3\n if (IPython.notebook.keyboard_manager) {\n IPython.notebook.keyboard_manager.register_events(el);\n } else {\n // location in version 2\n IPython.keyboard_manager.register_events(el);\n }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n var manager = IPython.notebook.keyboard_manager;\n if (!manager) {\n manager = IPython.keyboard_manager;\n }\n\n // Check for shift+enter\n if (event.shiftKey && event.which === 13) {\n this.canvas_div.blur();\n // select the cell after this one\n var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n IPython.notebook.select(index + 1);\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n // Return the cell and output element which can be found *uniquely* in the notebook.\n // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n // IPython event is triggered only after the cells have been serialised, which for\n // our purposes (turning an active figure into a static one), is too late.\n var cells = IPython.notebook.get_cells();\n var ncells = cells.length;\n for (var i = 0; i < ncells; i++) {\n var cell = cells[i];\n if (cell.cell_type === 'code') {\n for (var j = 0; j < cell.output_area.outputs.length; j++) {\n var data = cell.output_area.outputs[j];\n if (data.data) {\n // IPython >= 3 moved mimebundle to data attribute of output\n data = data.data;\n }\n if (data['text/html'] === html_output) {\n return [cell, data, j];\n }\n }\n }\n }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n IPython.notebook.kernel.comm_manager.register_target(\n 'matplotlib',\n mpl.mpl_figure_comm\n );\n}\n", "text/plain": [ "" ] @@ -7374,955 +738,7 @@ }, { "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "/* global mpl */\n", - "window.mpl = {};\n", - "\n", - "mpl.get_websocket_type = function () {\n", - " if (typeof WebSocket !== 'undefined') {\n", - " return WebSocket;\n", - " } else if (typeof MozWebSocket !== 'undefined') {\n", - " return MozWebSocket;\n", - " } else {\n", - " alert(\n", - " 'Your browser does not have WebSocket support. ' +\n", - " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", - " 'Firefox 4 and 5 are also supported but you ' +\n", - " 'have to enable WebSockets in about:config.'\n", - " );\n", - " }\n", - "};\n", - "\n", - "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", - " this.id = figure_id;\n", - "\n", - " this.ws = websocket;\n", - "\n", - " this.supports_binary = this.ws.binaryType !== undefined;\n", - "\n", - " if (!this.supports_binary) {\n", - " var warnings = document.getElementById('mpl-warnings');\n", - " if (warnings) {\n", - " warnings.style.display = 'block';\n", - " warnings.textContent =\n", - " 'This browser does not support binary websocket messages. ' +\n", - " 'Performance may be slow.';\n", - " }\n", - " }\n", - "\n", - " this.imageObj = new Image();\n", - "\n", - " this.context = undefined;\n", - " this.message = undefined;\n", - " this.canvas = undefined;\n", - " this.rubberband_canvas = undefined;\n", - " this.rubberband_context = undefined;\n", - " this.format_dropdown = undefined;\n", - "\n", - " this.image_mode = 'full';\n", - "\n", - " this.root = document.createElement('div');\n", - " this.root.setAttribute('style', 'display: inline-block');\n", - " this._root_extra_style(this.root);\n", - "\n", - " parent_element.appendChild(this.root);\n", - "\n", - " this._init_header(this);\n", - " this._init_canvas(this);\n", - " this._init_toolbar(this);\n", - "\n", - " var fig = this;\n", - "\n", - " this.waiting = false;\n", - "\n", - " this.ws.onopen = function () {\n", - " fig.send_message('supports_binary', { value: fig.supports_binary });\n", - " fig.send_message('send_image_mode', {});\n", - " if (fig.ratio !== 1) {\n", - " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", - " }\n", - " fig.send_message('refresh', {});\n", - " };\n", - "\n", - " this.imageObj.onload = function () {\n", - " if (fig.image_mode === 'full') {\n", - " // Full images could contain transparency (where diff images\n", - " // almost always do), so we need to clear the canvas so that\n", - " // there is no ghosting.\n", - " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", - " }\n", - " fig.context.drawImage(fig.imageObj, 0, 0);\n", - " };\n", - "\n", - " this.imageObj.onunload = function () {\n", - " fig.ws.close();\n", - " };\n", - "\n", - " this.ws.onmessage = this._make_on_message_function(this);\n", - "\n", - " this.ondownload = ondownload;\n", - "};\n", - "\n", - "mpl.figure.prototype._init_header = function () {\n", - " var titlebar = document.createElement('div');\n", - " titlebar.classList =\n", - " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", - " var titletext = document.createElement('div');\n", - " titletext.classList = 'ui-dialog-title';\n", - " titletext.setAttribute(\n", - " 'style',\n", - " 'width: 100%; text-align: center; padding: 3px;'\n", - " );\n", - " titlebar.appendChild(titletext);\n", - " this.root.appendChild(titlebar);\n", - " this.header = titletext;\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._init_canvas = function () {\n", - " var fig = this;\n", - "\n", - " var canvas_div = (this.canvas_div = document.createElement('div'));\n", - " canvas_div.setAttribute(\n", - " 'style',\n", - " 'border: 1px solid #ddd;' +\n", - " 'box-sizing: content-box;' +\n", - " 'clear: both;' +\n", - " 'min-height: 1px;' +\n", - " 'min-width: 1px;' +\n", - " 'outline: 0;' +\n", - " 'overflow: hidden;' +\n", - " 'position: relative;' +\n", - " 'resize: both;'\n", - " );\n", - "\n", - " function on_keyboard_event_closure(name) {\n", - " return function (event) {\n", - " return fig.key_event(event, name);\n", - " };\n", - " }\n", - "\n", - " canvas_div.addEventListener(\n", - " 'keydown',\n", - " on_keyboard_event_closure('key_press')\n", - " );\n", - " canvas_div.addEventListener(\n", - " 'keyup',\n", - " on_keyboard_event_closure('key_release')\n", - " );\n", - "\n", - " this._canvas_extra_style(canvas_div);\n", - " this.root.appendChild(canvas_div);\n", - "\n", - " var canvas = (this.canvas = document.createElement('canvas'));\n", - " canvas.classList.add('mpl-canvas');\n", - " canvas.setAttribute('style', 'box-sizing: content-box;');\n", - "\n", - " this.context = canvas.getContext('2d');\n", - "\n", - " var backingStore =\n", - " this.context.backingStorePixelRatio ||\n", - " this.context.webkitBackingStorePixelRatio ||\n", - " this.context.mozBackingStorePixelRatio ||\n", - " this.context.msBackingStorePixelRatio ||\n", - " this.context.oBackingStorePixelRatio ||\n", - " this.context.backingStorePixelRatio ||\n", - " 1;\n", - "\n", - " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", - "\n", - " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", - " 'canvas'\n", - " ));\n", - " rubberband_canvas.setAttribute(\n", - " 'style',\n", - " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", - " );\n", - "\n", - " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", - " if (this.ResizeObserver === undefined) {\n", - " if (window.ResizeObserver !== undefined) {\n", - " this.ResizeObserver = window.ResizeObserver;\n", - " } else {\n", - " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", - " this.ResizeObserver = obs.ResizeObserver;\n", - " }\n", - " }\n", - "\n", - " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", - " var nentries = entries.length;\n", - " for (var i = 0; i < nentries; i++) {\n", - " var entry = entries[i];\n", - " var width, height;\n", - " if (entry.contentBoxSize) {\n", - " if (entry.contentBoxSize instanceof Array) {\n", - " // Chrome 84 implements new version of spec.\n", - " width = entry.contentBoxSize[0].inlineSize;\n", - " height = entry.contentBoxSize[0].blockSize;\n", - " } else {\n", - " // Firefox implements old version of spec.\n", - " width = entry.contentBoxSize.inlineSize;\n", - " height = entry.contentBoxSize.blockSize;\n", - " }\n", - " } else {\n", - " // Chrome <84 implements even older version of spec.\n", - " width = entry.contentRect.width;\n", - " height = entry.contentRect.height;\n", - " }\n", - "\n", - " // Keep the size of the canvas and rubber band canvas in sync with\n", - " // the canvas container.\n", - " if (entry.devicePixelContentBoxSize) {\n", - " // Chrome 84 implements new version of spec.\n", - " canvas.setAttribute(\n", - " 'width',\n", - " entry.devicePixelContentBoxSize[0].inlineSize\n", - " );\n", - " canvas.setAttribute(\n", - " 'height',\n", - " entry.devicePixelContentBoxSize[0].blockSize\n", - " );\n", - " } else {\n", - " canvas.setAttribute('width', width * fig.ratio);\n", - " canvas.setAttribute('height', height * fig.ratio);\n", - " }\n", - " canvas.setAttribute(\n", - " 'style',\n", - " 'width: ' + width + 'px; height: ' + height + 'px;'\n", - " );\n", - "\n", - " rubberband_canvas.setAttribute('width', width);\n", - " rubberband_canvas.setAttribute('height', height);\n", - "\n", - " // And update the size in Python. We ignore the initial 0/0 size\n", - " // that occurs as the element is placed into the DOM, which should\n", - " // otherwise not happen due to the minimum size styling.\n", - " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", - " fig.request_resize(width, height);\n", - " }\n", - " }\n", - " });\n", - " this.resizeObserverInstance.observe(canvas_div);\n", - "\n", - " function on_mouse_event_closure(name) {\n", - " return function (event) {\n", - " return fig.mouse_event(event, name);\n", - " };\n", - " }\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mousedown',\n", - " on_mouse_event_closure('button_press')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseup',\n", - " on_mouse_event_closure('button_release')\n", - " );\n", - " // Throttle sequential mouse events to 1 every 20ms.\n", - " rubberband_canvas.addEventListener(\n", - " 'mousemove',\n", - " on_mouse_event_closure('motion_notify')\n", - " );\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseenter',\n", - " on_mouse_event_closure('figure_enter')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseleave',\n", - " on_mouse_event_closure('figure_leave')\n", - " );\n", - "\n", - " canvas_div.addEventListener('wheel', function (event) {\n", - " if (event.deltaY < 0) {\n", - " event.step = 1;\n", - " } else {\n", - " event.step = -1;\n", - " }\n", - " on_mouse_event_closure('scroll')(event);\n", - " });\n", - "\n", - " canvas_div.appendChild(canvas);\n", - " canvas_div.appendChild(rubberband_canvas);\n", - "\n", - " this.rubberband_context = rubberband_canvas.getContext('2d');\n", - " this.rubberband_context.strokeStyle = '#000000';\n", - "\n", - " this._resize_canvas = function (width, height, forward) {\n", - " if (forward) {\n", - " canvas_div.style.width = width + 'px';\n", - " canvas_div.style.height = height + 'px';\n", - " }\n", - " };\n", - "\n", - " // Disable right mouse context menu.\n", - " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", - " event.preventDefault();\n", - " return false;\n", - " });\n", - "\n", - " function set_focus() {\n", - " canvas.focus();\n", - " canvas_div.focus();\n", - " }\n", - "\n", - " window.setTimeout(set_focus, 100);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'mpl-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " continue;\n", - " }\n", - "\n", - " var button = (fig.buttons[name] = document.createElement('button'));\n", - " button.classList = 'mpl-widget';\n", - " button.setAttribute('role', 'button');\n", - " button.setAttribute('aria-disabled', 'false');\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - "\n", - " var icon_img = document.createElement('img');\n", - " icon_img.src = '_images/' + image + '.png';\n", - " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", - " icon_img.alt = tooltip;\n", - " button.appendChild(icon_img);\n", - "\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " var fmt_picker = document.createElement('select');\n", - " fmt_picker.classList = 'mpl-widget';\n", - " toolbar.appendChild(fmt_picker);\n", - " this.format_dropdown = fmt_picker;\n", - "\n", - " for (var ind in mpl.extensions) {\n", - " var fmt = mpl.extensions[ind];\n", - " var option = document.createElement('option');\n", - " option.selected = fmt === mpl.default_extension;\n", - " option.innerHTML = fmt;\n", - " fmt_picker.appendChild(option);\n", - " }\n", - "\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "};\n", - "\n", - "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", - " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", - " // which will in turn request a refresh of the image.\n", - " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", - "};\n", - "\n", - "mpl.figure.prototype.send_message = function (type, properties) {\n", - " properties['type'] = type;\n", - " properties['figure_id'] = this.id;\n", - " this.ws.send(JSON.stringify(properties));\n", - "};\n", - "\n", - "mpl.figure.prototype.send_draw_message = function () {\n", - " if (!this.waiting) {\n", - " this.waiting = true;\n", - " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " var format_dropdown = fig.format_dropdown;\n", - " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", - " fig.ondownload(fig, format);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", - " var size = msg['size'];\n", - " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", - " fig._resize_canvas(size[0], size[1], msg['forward']);\n", - " fig.send_message('refresh', {});\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", - " var x0 = msg['x0'] / fig.ratio;\n", - " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", - " var x1 = msg['x1'] / fig.ratio;\n", - " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", - " x0 = Math.floor(x0) + 0.5;\n", - " y0 = Math.floor(y0) + 0.5;\n", - " x1 = Math.floor(x1) + 0.5;\n", - " y1 = Math.floor(y1) + 0.5;\n", - " var min_x = Math.min(x0, x1);\n", - " var min_y = Math.min(y0, y1);\n", - " var width = Math.abs(x1 - x0);\n", - " var height = Math.abs(y1 - y0);\n", - "\n", - " fig.rubberband_context.clearRect(\n", - " 0,\n", - " 0,\n", - " fig.canvas.width / fig.ratio,\n", - " fig.canvas.height / fig.ratio\n", - " );\n", - "\n", - " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", - " // Updates the figure title.\n", - " fig.header.textContent = msg['label'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", - " var cursor = msg['cursor'];\n", - " switch (cursor) {\n", - " case 0:\n", - " cursor = 'pointer';\n", - " break;\n", - " case 1:\n", - " cursor = 'default';\n", - " break;\n", - " case 2:\n", - " cursor = 'crosshair';\n", - " break;\n", - " case 3:\n", - " cursor = 'move';\n", - " break;\n", - " }\n", - " fig.rubberband_canvas.style.cursor = cursor;\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_message = function (fig, msg) {\n", - " fig.message.textContent = msg['message'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", - " // Request the server to send over a new figure.\n", - " fig.send_draw_message();\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", - " fig.image_mode = msg['mode'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", - " for (var key in msg) {\n", - " if (!(key in fig.buttons)) {\n", - " continue;\n", - " }\n", - " fig.buttons[key].disabled = !msg[key];\n", - " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", - " if (msg['mode'] === 'PAN') {\n", - " fig.buttons['Pan'].classList.add('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " } else if (msg['mode'] === 'ZOOM') {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.add('active');\n", - " } else {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Called whenever the canvas gets updated.\n", - " this.send_message('ack', {});\n", - "};\n", - "\n", - "// A function to construct a web socket function for onmessage handling.\n", - "// Called in the figure constructor.\n", - "mpl.figure.prototype._make_on_message_function = function (fig) {\n", - " return function socket_on_message(evt) {\n", - " if (evt.data instanceof Blob) {\n", - " /* FIXME: We get \"Resource interpreted as Image but\n", - " * transferred with MIME type text/plain:\" errors on\n", - " * Chrome. But how to set the MIME type? It doesn't seem\n", - " * to be part of the websocket stream */\n", - " evt.data.type = 'image/png';\n", - "\n", - " /* Free the memory for the previous frames */\n", - " if (fig.imageObj.src) {\n", - " (window.URL || window.webkitURL).revokeObjectURL(\n", - " fig.imageObj.src\n", - " );\n", - " }\n", - "\n", - " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", - " evt.data\n", - " );\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " } else if (\n", - " typeof evt.data === 'string' &&\n", - " evt.data.slice(0, 21) === 'data:image/png;base64'\n", - " ) {\n", - " fig.imageObj.src = evt.data;\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " }\n", - "\n", - " var msg = JSON.parse(evt.data);\n", - " var msg_type = msg['type'];\n", - "\n", - " // Call the \"handle_{type}\" callback, which takes\n", - " // the figure and JSON message as its only arguments.\n", - " try {\n", - " var callback = fig['handle_' + msg_type];\n", - " } catch (e) {\n", - " console.log(\n", - " \"No handler for the '\" + msg_type + \"' message type: \",\n", - " msg\n", - " );\n", - " return;\n", - " }\n", - "\n", - " if (callback) {\n", - " try {\n", - " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", - " callback(fig, msg);\n", - " } catch (e) {\n", - " console.log(\n", - " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", - " e,\n", - " e.stack,\n", - " msg\n", - " );\n", - " }\n", - " }\n", - " };\n", - "};\n", - "\n", - "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", - "mpl.findpos = function (e) {\n", - " //this section is from http://www.quirksmode.org/js/events_properties.html\n", - " var targ;\n", - " if (!e) {\n", - " e = window.event;\n", - " }\n", - " if (e.target) {\n", - " targ = e.target;\n", - " } else if (e.srcElement) {\n", - " targ = e.srcElement;\n", - " }\n", - " if (targ.nodeType === 3) {\n", - " // defeat Safari bug\n", - " targ = targ.parentNode;\n", - " }\n", - "\n", - " // pageX,Y are the mouse positions relative to the document\n", - " var boundingRect = targ.getBoundingClientRect();\n", - " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", - " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", - "\n", - " return { x: x, y: y };\n", - "};\n", - "\n", - "/*\n", - " * return a copy of an object with only non-object keys\n", - " * we need this to avoid circular references\n", - " * http://stackoverflow.com/a/24161582/3208463\n", - " */\n", - "function simpleKeys(original) {\n", - " return Object.keys(original).reduce(function (obj, key) {\n", - " if (typeof original[key] !== 'object') {\n", - " obj[key] = original[key];\n", - " }\n", - " return obj;\n", - " }, {});\n", - "}\n", - "\n", - "mpl.figure.prototype.mouse_event = function (event, name) {\n", - " var canvas_pos = mpl.findpos(event);\n", - "\n", - " if (name === 'button_press') {\n", - " this.canvas.focus();\n", - " this.canvas_div.focus();\n", - " }\n", - "\n", - " var x = canvas_pos.x * this.ratio;\n", - " var y = canvas_pos.y * this.ratio;\n", - "\n", - " this.send_message(name, {\n", - " x: x,\n", - " y: y,\n", - " button: event.button,\n", - " step: event.step,\n", - " guiEvent: simpleKeys(event),\n", - " });\n", - "\n", - " /* This prevents the web browser from automatically changing to\n", - " * the text insertion cursor when the button is pressed. We want\n", - " * to control all of the cursor setting manually through the\n", - " * 'cursor' event from matplotlib */\n", - " event.preventDefault();\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", - " // Handle any extra behaviour associated with a key event\n", - "};\n", - "\n", - "mpl.figure.prototype.key_event = function (event, name) {\n", - " // Prevent repeat events\n", - " if (name === 'key_press') {\n", - " if (event.which === this._key) {\n", - " return;\n", - " } else {\n", - " this._key = event.which;\n", - " }\n", - " }\n", - " if (name === 'key_release') {\n", - " this._key = null;\n", - " }\n", - "\n", - " var value = '';\n", - " if (event.ctrlKey && event.which !== 17) {\n", - " value += 'ctrl+';\n", - " }\n", - " if (event.altKey && event.which !== 18) {\n", - " value += 'alt+';\n", - " }\n", - " if (event.shiftKey && event.which !== 16) {\n", - " value += 'shift+';\n", - " }\n", - "\n", - " value += 'k';\n", - " value += event.which.toString();\n", - "\n", - " this._key_event_extra(event, name);\n", - "\n", - " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", - " if (name === 'download') {\n", - " this.handle_save(this, null);\n", - " } else {\n", - " this.send_message('toolbar_button', { name: name });\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", - " this.message.textContent = tooltip;\n", - "};\n", - "\n", - "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", - "// prettier-ignore\n", - "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", - "\n", - "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", - "\n", - "mpl.default_extension = \"png\";/* global mpl */\n", - "\n", - "var comm_websocket_adapter = function (comm) {\n", - " // Create a \"websocket\"-like object which calls the given IPython comm\n", - " // object with the appropriate methods. Currently this is a non binary\n", - " // socket, so there is still some room for performance tuning.\n", - " var ws = {};\n", - "\n", - " ws.close = function () {\n", - " comm.close();\n", - " };\n", - " ws.send = function (m) {\n", - " //console.log('sending', m);\n", - " comm.send(m);\n", - " };\n", - " // Register the callback with on_msg.\n", - " comm.on_msg(function (msg) {\n", - " //console.log('receiving', msg['content']['data'], msg);\n", - " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", - " ws.onmessage(msg['content']['data']);\n", - " });\n", - " return ws;\n", - "};\n", - "\n", - "mpl.mpl_figure_comm = function (comm, msg) {\n", - " // This is the function which gets called when the mpl process\n", - " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", - "\n", - " var id = msg.content.data.id;\n", - " // Get hold of the div created by the display call when the Comm\n", - " // socket was opened in Python.\n", - " var element = document.getElementById(id);\n", - " var ws_proxy = comm_websocket_adapter(comm);\n", - "\n", - " function ondownload(figure, _format) {\n", - " window.open(figure.canvas.toDataURL());\n", - " }\n", - "\n", - " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", - "\n", - " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", - " // web socket which is closed, not our websocket->open comm proxy.\n", - " ws_proxy.onopen();\n", - "\n", - " fig.parent_element = element;\n", - " fig.cell_info = mpl.find_output_cell(\"
\");\n", - " if (!fig.cell_info) {\n", - " console.error('Failed to find cell for figure', id, fig);\n", - " return;\n", - " }\n", - " fig.cell_info[0].output_area.element.on(\n", - " 'cleared',\n", - " { fig: fig },\n", - " fig._remove_fig_handler\n", - " );\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_close = function (fig, msg) {\n", - " var width = fig.canvas.width / fig.ratio;\n", - " fig.cell_info[0].output_area.element.off(\n", - " 'cleared',\n", - " fig._remove_fig_handler\n", - " );\n", - " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", - "\n", - " // Update the output cell to use the data from the current canvas.\n", - " fig.push_to_output();\n", - " var dataURL = fig.canvas.toDataURL();\n", - " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", - " // the notebook keyboard shortcuts fail.\n", - " IPython.keyboard_manager.enable();\n", - " fig.parent_element.innerHTML =\n", - " '';\n", - " fig.close_ws(fig, msg);\n", - "};\n", - "\n", - "mpl.figure.prototype.close_ws = function (fig, msg) {\n", - " fig.send_message('closing', msg);\n", - " // fig.ws.close()\n", - "};\n", - "\n", - "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", - " // Turn the data on the canvas into data in the output cell.\n", - " var width = this.canvas.width / this.ratio;\n", - " var dataURL = this.canvas.toDataURL();\n", - " this.cell_info[1]['text/html'] =\n", - " '';\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Tell IPython that the notebook contents must change.\n", - " IPython.notebook.set_dirty(true);\n", - " this.send_message('ack', {});\n", - " var fig = this;\n", - " // Wait a second, then push the new image to the DOM so\n", - " // that it is saved nicely (might be nice to debounce this).\n", - " setTimeout(function () {\n", - " fig.push_to_output();\n", - " }, 1000);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'btn-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " var button;\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " continue;\n", - " }\n", - "\n", - " button = fig.buttons[name] = document.createElement('button');\n", - " button.classList = 'btn btn-default';\n", - " button.href = '#';\n", - " button.title = name;\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " // Add the status bar.\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message pull-right';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "\n", - " // Add the close button to the window.\n", - " var buttongrp = document.createElement('div');\n", - " buttongrp.classList = 'btn-group inline pull-right';\n", - " button = document.createElement('button');\n", - " button.classList = 'btn btn-mini btn-primary';\n", - " button.href = '#';\n", - " button.title = 'Stop Interaction';\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', function (_evt) {\n", - " fig.handle_close(fig, {});\n", - " });\n", - " button.addEventListener(\n", - " 'mouseover',\n", - " on_mouseover_closure('Stop Interaction')\n", - " );\n", - " buttongrp.appendChild(button);\n", - " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", - " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", - "};\n", - "\n", - "mpl.figure.prototype._remove_fig_handler = function (event) {\n", - " var fig = event.data.fig;\n", - " if (event.target !== this) {\n", - " // Ignore bubbled events from children.\n", - " return;\n", - " }\n", - " fig.close_ws(fig, {});\n", - "};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (el) {\n", - " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (el) {\n", - " // this is important to make the div 'focusable\n", - " el.setAttribute('tabindex', 0);\n", - " // reach out to IPython and tell the keyboard manager to turn it's self\n", - " // off when our div gets focus\n", - "\n", - " // location in version 3\n", - " if (IPython.notebook.keyboard_manager) {\n", - " IPython.notebook.keyboard_manager.register_events(el);\n", - " } else {\n", - " // location in version 2\n", - " IPython.keyboard_manager.register_events(el);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", - " var manager = IPython.notebook.keyboard_manager;\n", - " if (!manager) {\n", - " manager = IPython.keyboard_manager;\n", - " }\n", - "\n", - " // Check for shift+enter\n", - " if (event.shiftKey && event.which === 13) {\n", - " this.canvas_div.blur();\n", - " // select the cell after this one\n", - " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", - " IPython.notebook.select(index + 1);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " fig.ondownload(fig, null);\n", - "};\n", - "\n", - "mpl.find_output_cell = function (html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i = 0; i < ncells; i++) {\n", - " var cell = cells[i];\n", - " if (cell.cell_type === 'code') {\n", - " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", - " var data = cell.output_area.outputs[j];\n", - " if (data.data) {\n", - " // IPython >= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] === html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "};\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel !== null) {\n", - " IPython.notebook.kernel.comm_manager.register_target(\n", - " 'matplotlib',\n", - " mpl.mpl_figure_comm\n", - " );\n", - "}\n" - ], + "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n if (typeof WebSocket !== 'undefined') {\n return WebSocket;\n } else if (typeof MozWebSocket !== 'undefined') {\n return MozWebSocket;\n } else {\n alert(\n 'Your browser does not have WebSocket support. ' +\n 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n 'Firefox 4 and 5 are also supported but you ' +\n 'have to enable WebSockets in about:config.'\n );\n }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n this.id = figure_id;\n\n this.ws = websocket;\n\n this.supports_binary = this.ws.binaryType !== undefined;\n\n if (!this.supports_binary) {\n var warnings = document.getElementById('mpl-warnings');\n if (warnings) {\n warnings.style.display = 'block';\n warnings.textContent =\n 'This browser does not support binary websocket messages. ' +\n 'Performance may be slow.';\n }\n }\n\n this.imageObj = new Image();\n\n this.context = undefined;\n this.message = undefined;\n this.canvas = undefined;\n this.rubberband_canvas = undefined;\n this.rubberband_context = undefined;\n this.format_dropdown = undefined;\n\n this.image_mode = 'full';\n\n this.root = document.createElement('div');\n this.root.setAttribute('style', 'display: inline-block');\n this._root_extra_style(this.root);\n\n parent_element.appendChild(this.root);\n\n this._init_header(this);\n this._init_canvas(this);\n this._init_toolbar(this);\n\n var fig = this;\n\n this.waiting = false;\n\n this.ws.onopen = function () {\n fig.send_message('supports_binary', { value: fig.supports_binary });\n fig.send_message('send_image_mode', {});\n if (fig.ratio !== 1) {\n fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n }\n fig.send_message('refresh', {});\n };\n\n this.imageObj.onload = function () {\n if (fig.image_mode === 'full') {\n // Full images could contain transparency (where diff images\n // almost always do), so we need to clear the canvas so that\n // there is no ghosting.\n fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n }\n fig.context.drawImage(fig.imageObj, 0, 0);\n };\n\n this.imageObj.onunload = function () {\n fig.ws.close();\n };\n\n this.ws.onmessage = this._make_on_message_function(this);\n\n this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n var titlebar = document.createElement('div');\n titlebar.classList =\n 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n var titletext = document.createElement('div');\n titletext.classList = 'ui-dialog-title';\n titletext.setAttribute(\n 'style',\n 'width: 100%; text-align: center; padding: 3px;'\n );\n titlebar.appendChild(titletext);\n this.root.appendChild(titlebar);\n this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n var fig = this;\n\n var canvas_div = (this.canvas_div = document.createElement('div'));\n canvas_div.setAttribute(\n 'style',\n 'border: 1px solid #ddd;' +\n 'box-sizing: content-box;' +\n 'clear: both;' +\n 'min-height: 1px;' +\n 'min-width: 1px;' +\n 'outline: 0;' +\n 'overflow: hidden;' +\n 'position: relative;' +\n 'resize: both;'\n );\n\n function on_keyboard_event_closure(name) {\n return function (event) {\n return fig.key_event(event, name);\n };\n }\n\n canvas_div.addEventListener(\n 'keydown',\n on_keyboard_event_closure('key_press')\n );\n canvas_div.addEventListener(\n 'keyup',\n on_keyboard_event_closure('key_release')\n );\n\n this._canvas_extra_style(canvas_div);\n this.root.appendChild(canvas_div);\n\n var canvas = (this.canvas = document.createElement('canvas'));\n canvas.classList.add('mpl-canvas');\n canvas.setAttribute('style', 'box-sizing: content-box;');\n\n this.context = canvas.getContext('2d');\n\n var backingStore =\n this.context.backingStorePixelRatio ||\n this.context.webkitBackingStorePixelRatio ||\n this.context.mozBackingStorePixelRatio ||\n this.context.msBackingStorePixelRatio ||\n this.context.oBackingStorePixelRatio ||\n this.context.backingStorePixelRatio ||\n 1;\n\n this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n 'canvas'\n ));\n rubberband_canvas.setAttribute(\n 'style',\n 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n );\n\n // Apply a ponyfill if ResizeObserver is not implemented by browser.\n if (this.ResizeObserver === undefined) {\n if (window.ResizeObserver !== undefined) {\n this.ResizeObserver = window.ResizeObserver;\n } else {\n var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n this.ResizeObserver = obs.ResizeObserver;\n }\n }\n\n this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n var nentries = entries.length;\n for (var i = 0; i < nentries; i++) {\n var entry = entries[i];\n var width, height;\n if (entry.contentBoxSize) {\n if (entry.contentBoxSize instanceof Array) {\n // Chrome 84 implements new version of spec.\n width = entry.contentBoxSize[0].inlineSize;\n height = entry.contentBoxSize[0].blockSize;\n } else {\n // Firefox implements old version of spec.\n width = entry.contentBoxSize.inlineSize;\n height = entry.contentBoxSize.blockSize;\n }\n } else {\n // Chrome <84 implements even older version of spec.\n width = entry.contentRect.width;\n height = entry.contentRect.height;\n }\n\n // Keep the size of the canvas and rubber band canvas in sync with\n // the canvas container.\n if (entry.devicePixelContentBoxSize) {\n // Chrome 84 implements new version of spec.\n canvas.setAttribute(\n 'width',\n entry.devicePixelContentBoxSize[0].inlineSize\n );\n canvas.setAttribute(\n 'height',\n entry.devicePixelContentBoxSize[0].blockSize\n );\n } else {\n canvas.setAttribute('width', width * fig.ratio);\n canvas.setAttribute('height', height * fig.ratio);\n }\n canvas.setAttribute(\n 'style',\n 'width: ' + width + 'px; height: ' + height + 'px;'\n );\n\n rubberband_canvas.setAttribute('width', width);\n rubberband_canvas.setAttribute('height', height);\n\n // And update the size in Python. We ignore the initial 0/0 size\n // that occurs as the element is placed into the DOM, which should\n // otherwise not happen due to the minimum size styling.\n if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n fig.request_resize(width, height);\n }\n }\n });\n this.resizeObserverInstance.observe(canvas_div);\n\n function on_mouse_event_closure(name) {\n return function (event) {\n return fig.mouse_event(event, name);\n };\n }\n\n rubberband_canvas.addEventListener(\n 'mousedown',\n on_mouse_event_closure('button_press')\n );\n rubberband_canvas.addEventListener(\n 'mouseup',\n on_mouse_event_closure('button_release')\n );\n // Throttle sequential mouse events to 1 every 20ms.\n rubberband_canvas.addEventListener(\n 'mousemove',\n on_mouse_event_closure('motion_notify')\n );\n\n rubberband_canvas.addEventListener(\n 'mouseenter',\n on_mouse_event_closure('figure_enter')\n );\n rubberband_canvas.addEventListener(\n 'mouseleave',\n on_mouse_event_closure('figure_leave')\n );\n\n canvas_div.addEventListener('wheel', function (event) {\n if (event.deltaY < 0) {\n event.step = 1;\n } else {\n event.step = -1;\n }\n on_mouse_event_closure('scroll')(event);\n });\n\n canvas_div.appendChild(canvas);\n canvas_div.appendChild(rubberband_canvas);\n\n this.rubberband_context = rubberband_canvas.getContext('2d');\n this.rubberband_context.strokeStyle = '#000000';\n\n this._resize_canvas = function (width, height, forward) {\n if (forward) {\n canvas_div.style.width = width + 'px';\n canvas_div.style.height = height + 'px';\n }\n };\n\n // Disable right mouse context menu.\n this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n event.preventDefault();\n return false;\n });\n\n function set_focus() {\n canvas.focus();\n canvas_div.focus();\n }\n\n window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'mpl-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n continue;\n }\n\n var button = (fig.buttons[name] = document.createElement('button'));\n button.classList = 'mpl-widget';\n button.setAttribute('role', 'button');\n button.setAttribute('aria-disabled', 'false');\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n var icon_img = document.createElement('img');\n icon_img.src = '_images/' + image + '.png';\n icon_img.srcset = '_images/' + image + '_large.png 2x';\n icon_img.alt = tooltip;\n button.appendChild(icon_img);\n\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n var fmt_picker = document.createElement('select');\n fmt_picker.classList = 'mpl-widget';\n toolbar.appendChild(fmt_picker);\n this.format_dropdown = fmt_picker;\n\n for (var ind in mpl.extensions) {\n var fmt = mpl.extensions[ind];\n var option = document.createElement('option');\n option.selected = fmt === mpl.default_extension;\n option.innerHTML = fmt;\n fmt_picker.appendChild(option);\n }\n\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n // which will in turn request a refresh of the image.\n this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n properties['type'] = type;\n properties['figure_id'] = this.id;\n this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n if (!this.waiting) {\n this.waiting = true;\n this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n var format_dropdown = fig.format_dropdown;\n var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n var size = msg['size'];\n if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n fig._resize_canvas(size[0], size[1], msg['forward']);\n fig.send_message('refresh', {});\n }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n var x0 = msg['x0'] / fig.ratio;\n var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n var x1 = msg['x1'] / fig.ratio;\n var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n x0 = Math.floor(x0) + 0.5;\n y0 = Math.floor(y0) + 0.5;\n x1 = Math.floor(x1) + 0.5;\n y1 = Math.floor(y1) + 0.5;\n var min_x = Math.min(x0, x1);\n var min_y = Math.min(y0, y1);\n var width = Math.abs(x1 - x0);\n var height = Math.abs(y1 - y0);\n\n fig.rubberband_context.clearRect(\n 0,\n 0,\n fig.canvas.width / fig.ratio,\n fig.canvas.height / fig.ratio\n );\n\n fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n // Updates the figure title.\n fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n var cursor = msg['cursor'];\n switch (cursor) {\n case 0:\n cursor = 'pointer';\n break;\n case 1:\n cursor = 'default';\n break;\n case 2:\n cursor = 'crosshair';\n break;\n case 3:\n cursor = 'move';\n break;\n }\n fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n // Request the server to send over a new figure.\n fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n for (var key in msg) {\n if (!(key in fig.buttons)) {\n continue;\n }\n fig.buttons[key].disabled = !msg[key];\n fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n if (msg['mode'] === 'PAN') {\n fig.buttons['Pan'].classList.add('active');\n fig.buttons['Zoom'].classList.remove('active');\n } else if (msg['mode'] === 'ZOOM') {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.add('active');\n } else {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.remove('active');\n }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Called whenever the canvas gets updated.\n this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n return function socket_on_message(evt) {\n if (evt.data instanceof Blob) {\n /* FIXME: We get \"Resource interpreted as Image but\n * transferred with MIME type text/plain:\" errors on\n * Chrome. But how to set the MIME type? It doesn't seem\n * to be part of the websocket stream */\n evt.data.type = 'image/png';\n\n /* Free the memory for the previous frames */\n if (fig.imageObj.src) {\n (window.URL || window.webkitURL).revokeObjectURL(\n fig.imageObj.src\n );\n }\n\n fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n evt.data\n );\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n } else if (\n typeof evt.data === 'string' &&\n evt.data.slice(0, 21) === 'data:image/png;base64'\n ) {\n fig.imageObj.src = evt.data;\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n }\n\n var msg = JSON.parse(evt.data);\n var msg_type = msg['type'];\n\n // Call the \"handle_{type}\" callback, which takes\n // the figure and JSON message as its only arguments.\n try {\n var callback = fig['handle_' + msg_type];\n } catch (e) {\n console.log(\n \"No handler for the '\" + msg_type + \"' message type: \",\n msg\n );\n return;\n }\n\n if (callback) {\n try {\n // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n callback(fig, msg);\n } catch (e) {\n console.log(\n \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n e,\n e.stack,\n msg\n );\n }\n }\n };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n //this section is from http://www.quirksmode.org/js/events_properties.html\n var targ;\n if (!e) {\n e = window.event;\n }\n if (e.target) {\n targ = e.target;\n } else if (e.srcElement) {\n targ = e.srcElement;\n }\n if (targ.nodeType === 3) {\n // defeat Safari bug\n targ = targ.parentNode;\n }\n\n // pageX,Y are the mouse positions relative to the document\n var boundingRect = targ.getBoundingClientRect();\n var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n return Object.keys(original).reduce(function (obj, key) {\n if (typeof original[key] !== 'object') {\n obj[key] = original[key];\n }\n return obj;\n }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n var canvas_pos = mpl.findpos(event);\n\n if (name === 'button_press') {\n this.canvas.focus();\n this.canvas_div.focus();\n }\n\n var x = canvas_pos.x * this.ratio;\n var y = canvas_pos.y * this.ratio;\n\n this.send_message(name, {\n x: x,\n y: y,\n button: event.button,\n step: event.step,\n guiEvent: simpleKeys(event),\n });\n\n /* This prevents the web browser from automatically changing to\n * the text insertion cursor when the button is pressed. We want\n * to control all of the cursor setting manually through the\n * 'cursor' event from matplotlib */\n event.preventDefault();\n return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n // Prevent repeat events\n if (name === 'key_press') {\n if (event.which === this._key) {\n return;\n } else {\n this._key = event.which;\n }\n }\n if (name === 'key_release') {\n this._key = null;\n }\n\n var value = '';\n if (event.ctrlKey && event.which !== 17) {\n value += 'ctrl+';\n }\n if (event.altKey && event.which !== 18) {\n value += 'alt+';\n }\n if (event.shiftKey && event.which !== 16) {\n value += 'shift+';\n }\n\n value += 'k';\n value += event.which.toString();\n\n this._key_event_extra(event, name);\n\n this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n if (name === 'download') {\n this.handle_save(this, null);\n } else {\n this.send_message('toolbar_button', { name: name });\n }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\nmpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n\nmpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n // Create a \"websocket\"-like object which calls the given IPython comm\n // object with the appropriate methods. Currently this is a non binary\n // socket, so there is still some room for performance tuning.\n var ws = {};\n\n ws.close = function () {\n comm.close();\n };\n ws.send = function (m) {\n //console.log('sending', m);\n comm.send(m);\n };\n // Register the callback with on_msg.\n comm.on_msg(function (msg) {\n //console.log('receiving', msg['content']['data'], msg);\n // Pass the mpl event to the overridden (by mpl) onmessage function.\n ws.onmessage(msg['content']['data']);\n });\n return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n // This is the function which gets called when the mpl process\n // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n var id = msg.content.data.id;\n // Get hold of the div created by the display call when the Comm\n // socket was opened in Python.\n var element = document.getElementById(id);\n var ws_proxy = comm_websocket_adapter(comm);\n\n function ondownload(figure, _format) {\n window.open(figure.canvas.toDataURL());\n }\n\n var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n // web socket which is closed, not our websocket->open comm proxy.\n ws_proxy.onopen();\n\n fig.parent_element = element;\n fig.cell_info = mpl.find_output_cell(\"
\");\n if (!fig.cell_info) {\n console.error('Failed to find cell for figure', id, fig);\n return;\n }\n fig.cell_info[0].output_area.element.on(\n 'cleared',\n { fig: fig },\n fig._remove_fig_handler\n );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n var width = fig.canvas.width / fig.ratio;\n fig.cell_info[0].output_area.element.off(\n 'cleared',\n fig._remove_fig_handler\n );\n fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n // Update the output cell to use the data from the current canvas.\n fig.push_to_output();\n var dataURL = fig.canvas.toDataURL();\n // Re-enable the keyboard manager in IPython - without this line, in FF,\n // the notebook keyboard shortcuts fail.\n IPython.keyboard_manager.enable();\n fig.parent_element.innerHTML =\n '';\n fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n fig.send_message('closing', msg);\n // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n // Turn the data on the canvas into data in the output cell.\n var width = this.canvas.width / this.ratio;\n var dataURL = this.canvas.toDataURL();\n this.cell_info[1]['text/html'] =\n '';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Tell IPython that the notebook contents must change.\n IPython.notebook.set_dirty(true);\n this.send_message('ack', {});\n var fig = this;\n // Wait a second, then push the new image to the DOM so\n // that it is saved nicely (might be nice to debounce this).\n setTimeout(function () {\n fig.push_to_output();\n }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'btn-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n var button;\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n continue;\n }\n\n button = fig.buttons[name] = document.createElement('button');\n button.classList = 'btn btn-default';\n button.href = '#';\n button.title = name;\n button.innerHTML = '';\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n // Add the status bar.\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message pull-right';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n\n // Add the close button to the window.\n var buttongrp = document.createElement('div');\n buttongrp.classList = 'btn-group inline pull-right';\n button = document.createElement('button');\n button.classList = 'btn btn-mini btn-primary';\n button.href = '#';\n button.title = 'Stop Interaction';\n button.innerHTML = '';\n button.addEventListener('click', function (_evt) {\n fig.handle_close(fig, {});\n });\n button.addEventListener(\n 'mouseover',\n on_mouseover_closure('Stop Interaction')\n );\n buttongrp.appendChild(button);\n var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n var fig = event.data.fig;\n if (event.target !== this) {\n // Ignore bubbled events from children.\n return;\n }\n fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n // this is important to make the div 'focusable\n el.setAttribute('tabindex', 0);\n // reach out to IPython and tell the keyboard manager to turn it's self\n // off when our div gets focus\n\n // location in version 3\n if (IPython.notebook.keyboard_manager) {\n IPython.notebook.keyboard_manager.register_events(el);\n } else {\n // location in version 2\n IPython.keyboard_manager.register_events(el);\n }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n var manager = IPython.notebook.keyboard_manager;\n if (!manager) {\n manager = IPython.keyboard_manager;\n }\n\n // Check for shift+enter\n if (event.shiftKey && event.which === 13) {\n this.canvas_div.blur();\n // select the cell after this one\n var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n IPython.notebook.select(index + 1);\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n // Return the cell and output element which can be found *uniquely* in the notebook.\n // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n // IPython event is triggered only after the cells have been serialised, which for\n // our purposes (turning an active figure into a static one), is too late.\n var cells = IPython.notebook.get_cells();\n var ncells = cells.length;\n for (var i = 0; i < ncells; i++) {\n var cell = cells[i];\n if (cell.cell_type === 'code') {\n for (var j = 0; j < cell.output_area.outputs.length; j++) {\n var data = cell.output_area.outputs[j];\n if (data.data) {\n // IPython >= 3 moved mimebundle to data attribute of output\n data = data.data;\n }\n if (data['text/html'] === html_output) {\n return [cell, data, j];\n }\n }\n }\n }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n IPython.notebook.kernel.comm_manager.register_target(\n 'matplotlib',\n mpl.mpl_figure_comm\n );\n}\n", "text/plain": [ "" ] @@ -8354,9 +770,9 @@ "source": [ "## Second multi-simulation layer only: Parameter Sweep\n", "\n", - "In pyleecan a Parameter Sweep is defined with a VarParam object. The design variables are set with ParamExplorer objects and the same Datakeeper as for a VarLoadCurrent (Id, Id, Tem_av...) will be automatically defined as output. Other Datakeepers can be defined in simu.var_simu.datakeeper_list.\n", + "In pyleecan a Parameter Sweep is defined with a VarParamSweep object. The design variables are set with ParamExplorer objects and the same Datakeeper as for a VarLoadCurrent (Id, Id, Tem_av...) will be automatically defined as output. Other Datakeepers can be defined in simu.var_simu.datakeeper_list.\n", "\n", - "VarParam and VarLoadCurrent inherit from the same class VarSimu. This is why most of the parameter of VarLoadCurrent are also available in VarParam and that both classes share the same behaviour. The main difference is how the simulation list is defined. Technically a VarLoadCurrent could be defined with a VarParam using ParamExplorer on Id / Iq / Tem_av_ref.\n", + "VarParamSweep and VarLoadCurrent inherit from the same class VarSimu. This is why most of the parameter of VarLoadCurrent are also available in VarParamSweep and that both classes share the same behaviour. The main difference is how the simulation list is defined. Technically a VarLoadCurrent could be defined with a VarParamSweep using ParamExplorer on Id / Iq / Tem_av_ref.\n", "\n", "For this tutorial, only one ParamExplorer is defined: a linspace on the stator slot opening. The is_reuse_femm_file is desactivated as each simulation will have a different machine and is_keep_all_output is activated to show the full content of the xoutput object." ] @@ -8377,14 +793,14 @@ } ], "source": [ - "from pyleecan.Classes.VarParam import VarParam\n", + "from pyleecan.Classes.VarParamSweep import VarParamSweep\n", "from pyleecan.Classes.ParamExplorerInterval import ParamExplorerInterval\n", "\n", "simu_sweep = simu_ref.copy()\n", "simu_sweep.mag.import_file = None\n", "\n", "# Multi-simulation to change machine parameters\n", - "sweep = VarParam(\n", + "sweep = VarParamSweep(\n", " stop_if_error=True,\n", " is_reuse_femm_file=False,\n", " is_keep_all_output=True,\n", @@ -8530,955 +946,7 @@ "outputs": [ { "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "/* global mpl */\n", - "window.mpl = {};\n", - "\n", - "mpl.get_websocket_type = function () {\n", - " if (typeof WebSocket !== 'undefined') {\n", - " return WebSocket;\n", - " } else if (typeof MozWebSocket !== 'undefined') {\n", - " return MozWebSocket;\n", - " } else {\n", - " alert(\n", - " 'Your browser does not have WebSocket support. ' +\n", - " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", - " 'Firefox 4 and 5 are also supported but you ' +\n", - " 'have to enable WebSockets in about:config.'\n", - " );\n", - " }\n", - "};\n", - "\n", - "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", - " this.id = figure_id;\n", - "\n", - " this.ws = websocket;\n", - "\n", - " this.supports_binary = this.ws.binaryType !== undefined;\n", - "\n", - " if (!this.supports_binary) {\n", - " var warnings = document.getElementById('mpl-warnings');\n", - " if (warnings) {\n", - " warnings.style.display = 'block';\n", - " warnings.textContent =\n", - " 'This browser does not support binary websocket messages. ' +\n", - " 'Performance may be slow.';\n", - " }\n", - " }\n", - "\n", - " this.imageObj = new Image();\n", - "\n", - " this.context = undefined;\n", - " this.message = undefined;\n", - " this.canvas = undefined;\n", - " this.rubberband_canvas = undefined;\n", - " this.rubberband_context = undefined;\n", - " this.format_dropdown = undefined;\n", - "\n", - " this.image_mode = 'full';\n", - "\n", - " this.root = document.createElement('div');\n", - " this.root.setAttribute('style', 'display: inline-block');\n", - " this._root_extra_style(this.root);\n", - "\n", - " parent_element.appendChild(this.root);\n", - "\n", - " this._init_header(this);\n", - " this._init_canvas(this);\n", - " this._init_toolbar(this);\n", - "\n", - " var fig = this;\n", - "\n", - " this.waiting = false;\n", - "\n", - " this.ws.onopen = function () {\n", - " fig.send_message('supports_binary', { value: fig.supports_binary });\n", - " fig.send_message('send_image_mode', {});\n", - " if (fig.ratio !== 1) {\n", - " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", - " }\n", - " fig.send_message('refresh', {});\n", - " };\n", - "\n", - " this.imageObj.onload = function () {\n", - " if (fig.image_mode === 'full') {\n", - " // Full images could contain transparency (where diff images\n", - " // almost always do), so we need to clear the canvas so that\n", - " // there is no ghosting.\n", - " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", - " }\n", - " fig.context.drawImage(fig.imageObj, 0, 0);\n", - " };\n", - "\n", - " this.imageObj.onunload = function () {\n", - " fig.ws.close();\n", - " };\n", - "\n", - " this.ws.onmessage = this._make_on_message_function(this);\n", - "\n", - " this.ondownload = ondownload;\n", - "};\n", - "\n", - "mpl.figure.prototype._init_header = function () {\n", - " var titlebar = document.createElement('div');\n", - " titlebar.classList =\n", - " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", - " var titletext = document.createElement('div');\n", - " titletext.classList = 'ui-dialog-title';\n", - " titletext.setAttribute(\n", - " 'style',\n", - " 'width: 100%; text-align: center; padding: 3px;'\n", - " );\n", - " titlebar.appendChild(titletext);\n", - " this.root.appendChild(titlebar);\n", - " this.header = titletext;\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._init_canvas = function () {\n", - " var fig = this;\n", - "\n", - " var canvas_div = (this.canvas_div = document.createElement('div'));\n", - " canvas_div.setAttribute(\n", - " 'style',\n", - " 'border: 1px solid #ddd;' +\n", - " 'box-sizing: content-box;' +\n", - " 'clear: both;' +\n", - " 'min-height: 1px;' +\n", - " 'min-width: 1px;' +\n", - " 'outline: 0;' +\n", - " 'overflow: hidden;' +\n", - " 'position: relative;' +\n", - " 'resize: both;'\n", - " );\n", - "\n", - " function on_keyboard_event_closure(name) {\n", - " return function (event) {\n", - " return fig.key_event(event, name);\n", - " };\n", - " }\n", - "\n", - " canvas_div.addEventListener(\n", - " 'keydown',\n", - " on_keyboard_event_closure('key_press')\n", - " );\n", - " canvas_div.addEventListener(\n", - " 'keyup',\n", - " on_keyboard_event_closure('key_release')\n", - " );\n", - "\n", - " this._canvas_extra_style(canvas_div);\n", - " this.root.appendChild(canvas_div);\n", - "\n", - " var canvas = (this.canvas = document.createElement('canvas'));\n", - " canvas.classList.add('mpl-canvas');\n", - " canvas.setAttribute('style', 'box-sizing: content-box;');\n", - "\n", - " this.context = canvas.getContext('2d');\n", - "\n", - " var backingStore =\n", - " this.context.backingStorePixelRatio ||\n", - " this.context.webkitBackingStorePixelRatio ||\n", - " this.context.mozBackingStorePixelRatio ||\n", - " this.context.msBackingStorePixelRatio ||\n", - " this.context.oBackingStorePixelRatio ||\n", - " this.context.backingStorePixelRatio ||\n", - " 1;\n", - "\n", - " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", - "\n", - " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", - " 'canvas'\n", - " ));\n", - " rubberband_canvas.setAttribute(\n", - " 'style',\n", - " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", - " );\n", - "\n", - " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", - " if (this.ResizeObserver === undefined) {\n", - " if (window.ResizeObserver !== undefined) {\n", - " this.ResizeObserver = window.ResizeObserver;\n", - " } else {\n", - " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", - " this.ResizeObserver = obs.ResizeObserver;\n", - " }\n", - " }\n", - "\n", - " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", - " var nentries = entries.length;\n", - " for (var i = 0; i < nentries; i++) {\n", - " var entry = entries[i];\n", - " var width, height;\n", - " if (entry.contentBoxSize) {\n", - " if (entry.contentBoxSize instanceof Array) {\n", - " // Chrome 84 implements new version of spec.\n", - " width = entry.contentBoxSize[0].inlineSize;\n", - " height = entry.contentBoxSize[0].blockSize;\n", - " } else {\n", - " // Firefox implements old version of spec.\n", - " width = entry.contentBoxSize.inlineSize;\n", - " height = entry.contentBoxSize.blockSize;\n", - " }\n", - " } else {\n", - " // Chrome <84 implements even older version of spec.\n", - " width = entry.contentRect.width;\n", - " height = entry.contentRect.height;\n", - " }\n", - "\n", - " // Keep the size of the canvas and rubber band canvas in sync with\n", - " // the canvas container.\n", - " if (entry.devicePixelContentBoxSize) {\n", - " // Chrome 84 implements new version of spec.\n", - " canvas.setAttribute(\n", - " 'width',\n", - " entry.devicePixelContentBoxSize[0].inlineSize\n", - " );\n", - " canvas.setAttribute(\n", - " 'height',\n", - " entry.devicePixelContentBoxSize[0].blockSize\n", - " );\n", - " } else {\n", - " canvas.setAttribute('width', width * fig.ratio);\n", - " canvas.setAttribute('height', height * fig.ratio);\n", - " }\n", - " canvas.setAttribute(\n", - " 'style',\n", - " 'width: ' + width + 'px; height: ' + height + 'px;'\n", - " );\n", - "\n", - " rubberband_canvas.setAttribute('width', width);\n", - " rubberband_canvas.setAttribute('height', height);\n", - "\n", - " // And update the size in Python. We ignore the initial 0/0 size\n", - " // that occurs as the element is placed into the DOM, which should\n", - " // otherwise not happen due to the minimum size styling.\n", - " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", - " fig.request_resize(width, height);\n", - " }\n", - " }\n", - " });\n", - " this.resizeObserverInstance.observe(canvas_div);\n", - "\n", - " function on_mouse_event_closure(name) {\n", - " return function (event) {\n", - " return fig.mouse_event(event, name);\n", - " };\n", - " }\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mousedown',\n", - " on_mouse_event_closure('button_press')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseup',\n", - " on_mouse_event_closure('button_release')\n", - " );\n", - " // Throttle sequential mouse events to 1 every 20ms.\n", - " rubberband_canvas.addEventListener(\n", - " 'mousemove',\n", - " on_mouse_event_closure('motion_notify')\n", - " );\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseenter',\n", - " on_mouse_event_closure('figure_enter')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseleave',\n", - " on_mouse_event_closure('figure_leave')\n", - " );\n", - "\n", - " canvas_div.addEventListener('wheel', function (event) {\n", - " if (event.deltaY < 0) {\n", - " event.step = 1;\n", - " } else {\n", - " event.step = -1;\n", - " }\n", - " on_mouse_event_closure('scroll')(event);\n", - " });\n", - "\n", - " canvas_div.appendChild(canvas);\n", - " canvas_div.appendChild(rubberband_canvas);\n", - "\n", - " this.rubberband_context = rubberband_canvas.getContext('2d');\n", - " this.rubberband_context.strokeStyle = '#000000';\n", - "\n", - " this._resize_canvas = function (width, height, forward) {\n", - " if (forward) {\n", - " canvas_div.style.width = width + 'px';\n", - " canvas_div.style.height = height + 'px';\n", - " }\n", - " };\n", - "\n", - " // Disable right mouse context menu.\n", - " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", - " event.preventDefault();\n", - " return false;\n", - " });\n", - "\n", - " function set_focus() {\n", - " canvas.focus();\n", - " canvas_div.focus();\n", - " }\n", - "\n", - " window.setTimeout(set_focus, 100);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'mpl-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " continue;\n", - " }\n", - "\n", - " var button = (fig.buttons[name] = document.createElement('button'));\n", - " button.classList = 'mpl-widget';\n", - " button.setAttribute('role', 'button');\n", - " button.setAttribute('aria-disabled', 'false');\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - "\n", - " var icon_img = document.createElement('img');\n", - " icon_img.src = '_images/' + image + '.png';\n", - " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", - " icon_img.alt = tooltip;\n", - " button.appendChild(icon_img);\n", - "\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " var fmt_picker = document.createElement('select');\n", - " fmt_picker.classList = 'mpl-widget';\n", - " toolbar.appendChild(fmt_picker);\n", - " this.format_dropdown = fmt_picker;\n", - "\n", - " for (var ind in mpl.extensions) {\n", - " var fmt = mpl.extensions[ind];\n", - " var option = document.createElement('option');\n", - " option.selected = fmt === mpl.default_extension;\n", - " option.innerHTML = fmt;\n", - " fmt_picker.appendChild(option);\n", - " }\n", - "\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "};\n", - "\n", - "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", - " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", - " // which will in turn request a refresh of the image.\n", - " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", - "};\n", - "\n", - "mpl.figure.prototype.send_message = function (type, properties) {\n", - " properties['type'] = type;\n", - " properties['figure_id'] = this.id;\n", - " this.ws.send(JSON.stringify(properties));\n", - "};\n", - "\n", - "mpl.figure.prototype.send_draw_message = function () {\n", - " if (!this.waiting) {\n", - " this.waiting = true;\n", - " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " var format_dropdown = fig.format_dropdown;\n", - " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", - " fig.ondownload(fig, format);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", - " var size = msg['size'];\n", - " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", - " fig._resize_canvas(size[0], size[1], msg['forward']);\n", - " fig.send_message('refresh', {});\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", - " var x0 = msg['x0'] / fig.ratio;\n", - " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", - " var x1 = msg['x1'] / fig.ratio;\n", - " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", - " x0 = Math.floor(x0) + 0.5;\n", - " y0 = Math.floor(y0) + 0.5;\n", - " x1 = Math.floor(x1) + 0.5;\n", - " y1 = Math.floor(y1) + 0.5;\n", - " var min_x = Math.min(x0, x1);\n", - " var min_y = Math.min(y0, y1);\n", - " var width = Math.abs(x1 - x0);\n", - " var height = Math.abs(y1 - y0);\n", - "\n", - " fig.rubberband_context.clearRect(\n", - " 0,\n", - " 0,\n", - " fig.canvas.width / fig.ratio,\n", - " fig.canvas.height / fig.ratio\n", - " );\n", - "\n", - " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", - " // Updates the figure title.\n", - " fig.header.textContent = msg['label'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", - " var cursor = msg['cursor'];\n", - " switch (cursor) {\n", - " case 0:\n", - " cursor = 'pointer';\n", - " break;\n", - " case 1:\n", - " cursor = 'default';\n", - " break;\n", - " case 2:\n", - " cursor = 'crosshair';\n", - " break;\n", - " case 3:\n", - " cursor = 'move';\n", - " break;\n", - " }\n", - " fig.rubberband_canvas.style.cursor = cursor;\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_message = function (fig, msg) {\n", - " fig.message.textContent = msg['message'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", - " // Request the server to send over a new figure.\n", - " fig.send_draw_message();\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", - " fig.image_mode = msg['mode'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", - " for (var key in msg) {\n", - " if (!(key in fig.buttons)) {\n", - " continue;\n", - " }\n", - " fig.buttons[key].disabled = !msg[key];\n", - " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", - " if (msg['mode'] === 'PAN') {\n", - " fig.buttons['Pan'].classList.add('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " } else if (msg['mode'] === 'ZOOM') {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.add('active');\n", - " } else {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Called whenever the canvas gets updated.\n", - " this.send_message('ack', {});\n", - "};\n", - "\n", - "// A function to construct a web socket function for onmessage handling.\n", - "// Called in the figure constructor.\n", - "mpl.figure.prototype._make_on_message_function = function (fig) {\n", - " return function socket_on_message(evt) {\n", - " if (evt.data instanceof Blob) {\n", - " /* FIXME: We get \"Resource interpreted as Image but\n", - " * transferred with MIME type text/plain:\" errors on\n", - " * Chrome. But how to set the MIME type? It doesn't seem\n", - " * to be part of the websocket stream */\n", - " evt.data.type = 'image/png';\n", - "\n", - " /* Free the memory for the previous frames */\n", - " if (fig.imageObj.src) {\n", - " (window.URL || window.webkitURL).revokeObjectURL(\n", - " fig.imageObj.src\n", - " );\n", - " }\n", - "\n", - " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", - " evt.data\n", - " );\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " } else if (\n", - " typeof evt.data === 'string' &&\n", - " evt.data.slice(0, 21) === 'data:image/png;base64'\n", - " ) {\n", - " fig.imageObj.src = evt.data;\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " }\n", - "\n", - " var msg = JSON.parse(evt.data);\n", - " var msg_type = msg['type'];\n", - "\n", - " // Call the \"handle_{type}\" callback, which takes\n", - " // the figure and JSON message as its only arguments.\n", - " try {\n", - " var callback = fig['handle_' + msg_type];\n", - " } catch (e) {\n", - " console.log(\n", - " \"No handler for the '\" + msg_type + \"' message type: \",\n", - " msg\n", - " );\n", - " return;\n", - " }\n", - "\n", - " if (callback) {\n", - " try {\n", - " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", - " callback(fig, msg);\n", - " } catch (e) {\n", - " console.log(\n", - " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", - " e,\n", - " e.stack,\n", - " msg\n", - " );\n", - " }\n", - " }\n", - " };\n", - "};\n", - "\n", - "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", - "mpl.findpos = function (e) {\n", - " //this section is from http://www.quirksmode.org/js/events_properties.html\n", - " var targ;\n", - " if (!e) {\n", - " e = window.event;\n", - " }\n", - " if (e.target) {\n", - " targ = e.target;\n", - " } else if (e.srcElement) {\n", - " targ = e.srcElement;\n", - " }\n", - " if (targ.nodeType === 3) {\n", - " // defeat Safari bug\n", - " targ = targ.parentNode;\n", - " }\n", - "\n", - " // pageX,Y are the mouse positions relative to the document\n", - " var boundingRect = targ.getBoundingClientRect();\n", - " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", - " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", - "\n", - " return { x: x, y: y };\n", - "};\n", - "\n", - "/*\n", - " * return a copy of an object with only non-object keys\n", - " * we need this to avoid circular references\n", - " * http://stackoverflow.com/a/24161582/3208463\n", - " */\n", - "function simpleKeys(original) {\n", - " return Object.keys(original).reduce(function (obj, key) {\n", - " if (typeof original[key] !== 'object') {\n", - " obj[key] = original[key];\n", - " }\n", - " return obj;\n", - " }, {});\n", - "}\n", - "\n", - "mpl.figure.prototype.mouse_event = function (event, name) {\n", - " var canvas_pos = mpl.findpos(event);\n", - "\n", - " if (name === 'button_press') {\n", - " this.canvas.focus();\n", - " this.canvas_div.focus();\n", - " }\n", - "\n", - " var x = canvas_pos.x * this.ratio;\n", - " var y = canvas_pos.y * this.ratio;\n", - "\n", - " this.send_message(name, {\n", - " x: x,\n", - " y: y,\n", - " button: event.button,\n", - " step: event.step,\n", - " guiEvent: simpleKeys(event),\n", - " });\n", - "\n", - " /* This prevents the web browser from automatically changing to\n", - " * the text insertion cursor when the button is pressed. We want\n", - " * to control all of the cursor setting manually through the\n", - " * 'cursor' event from matplotlib */\n", - " event.preventDefault();\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", - " // Handle any extra behaviour associated with a key event\n", - "};\n", - "\n", - "mpl.figure.prototype.key_event = function (event, name) {\n", - " // Prevent repeat events\n", - " if (name === 'key_press') {\n", - " if (event.which === this._key) {\n", - " return;\n", - " } else {\n", - " this._key = event.which;\n", - " }\n", - " }\n", - " if (name === 'key_release') {\n", - " this._key = null;\n", - " }\n", - "\n", - " var value = '';\n", - " if (event.ctrlKey && event.which !== 17) {\n", - " value += 'ctrl+';\n", - " }\n", - " if (event.altKey && event.which !== 18) {\n", - " value += 'alt+';\n", - " }\n", - " if (event.shiftKey && event.which !== 16) {\n", - " value += 'shift+';\n", - " }\n", - "\n", - " value += 'k';\n", - " value += event.which.toString();\n", - "\n", - " this._key_event_extra(event, name);\n", - "\n", - " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", - " if (name === 'download') {\n", - " this.handle_save(this, null);\n", - " } else {\n", - " this.send_message('toolbar_button', { name: name });\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", - " this.message.textContent = tooltip;\n", - "};\n", - "\n", - "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", - "// prettier-ignore\n", - "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", - "\n", - "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", - "\n", - "mpl.default_extension = \"png\";/* global mpl */\n", - "\n", - "var comm_websocket_adapter = function (comm) {\n", - " // Create a \"websocket\"-like object which calls the given IPython comm\n", - " // object with the appropriate methods. Currently this is a non binary\n", - " // socket, so there is still some room for performance tuning.\n", - " var ws = {};\n", - "\n", - " ws.close = function () {\n", - " comm.close();\n", - " };\n", - " ws.send = function (m) {\n", - " //console.log('sending', m);\n", - " comm.send(m);\n", - " };\n", - " // Register the callback with on_msg.\n", - " comm.on_msg(function (msg) {\n", - " //console.log('receiving', msg['content']['data'], msg);\n", - " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", - " ws.onmessage(msg['content']['data']);\n", - " });\n", - " return ws;\n", - "};\n", - "\n", - "mpl.mpl_figure_comm = function (comm, msg) {\n", - " // This is the function which gets called when the mpl process\n", - " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", - "\n", - " var id = msg.content.data.id;\n", - " // Get hold of the div created by the display call when the Comm\n", - " // socket was opened in Python.\n", - " var element = document.getElementById(id);\n", - " var ws_proxy = comm_websocket_adapter(comm);\n", - "\n", - " function ondownload(figure, _format) {\n", - " window.open(figure.canvas.toDataURL());\n", - " }\n", - "\n", - " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", - "\n", - " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", - " // web socket which is closed, not our websocket->open comm proxy.\n", - " ws_proxy.onopen();\n", - "\n", - " fig.parent_element = element;\n", - " fig.cell_info = mpl.find_output_cell(\"
\");\n", - " if (!fig.cell_info) {\n", - " console.error('Failed to find cell for figure', id, fig);\n", - " return;\n", - " }\n", - " fig.cell_info[0].output_area.element.on(\n", - " 'cleared',\n", - " { fig: fig },\n", - " fig._remove_fig_handler\n", - " );\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_close = function (fig, msg) {\n", - " var width = fig.canvas.width / fig.ratio;\n", - " fig.cell_info[0].output_area.element.off(\n", - " 'cleared',\n", - " fig._remove_fig_handler\n", - " );\n", - " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", - "\n", - " // Update the output cell to use the data from the current canvas.\n", - " fig.push_to_output();\n", - " var dataURL = fig.canvas.toDataURL();\n", - " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", - " // the notebook keyboard shortcuts fail.\n", - " IPython.keyboard_manager.enable();\n", - " fig.parent_element.innerHTML =\n", - " '';\n", - " fig.close_ws(fig, msg);\n", - "};\n", - "\n", - "mpl.figure.prototype.close_ws = function (fig, msg) {\n", - " fig.send_message('closing', msg);\n", - " // fig.ws.close()\n", - "};\n", - "\n", - "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", - " // Turn the data on the canvas into data in the output cell.\n", - " var width = this.canvas.width / this.ratio;\n", - " var dataURL = this.canvas.toDataURL();\n", - " this.cell_info[1]['text/html'] =\n", - " '';\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Tell IPython that the notebook contents must change.\n", - " IPython.notebook.set_dirty(true);\n", - " this.send_message('ack', {});\n", - " var fig = this;\n", - " // Wait a second, then push the new image to the DOM so\n", - " // that it is saved nicely (might be nice to debounce this).\n", - " setTimeout(function () {\n", - " fig.push_to_output();\n", - " }, 1000);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'btn-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " var button;\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " continue;\n", - " }\n", - "\n", - " button = fig.buttons[name] = document.createElement('button');\n", - " button.classList = 'btn btn-default';\n", - " button.href = '#';\n", - " button.title = name;\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " // Add the status bar.\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message pull-right';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "\n", - " // Add the close button to the window.\n", - " var buttongrp = document.createElement('div');\n", - " buttongrp.classList = 'btn-group inline pull-right';\n", - " button = document.createElement('button');\n", - " button.classList = 'btn btn-mini btn-primary';\n", - " button.href = '#';\n", - " button.title = 'Stop Interaction';\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', function (_evt) {\n", - " fig.handle_close(fig, {});\n", - " });\n", - " button.addEventListener(\n", - " 'mouseover',\n", - " on_mouseover_closure('Stop Interaction')\n", - " );\n", - " buttongrp.appendChild(button);\n", - " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", - " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", - "};\n", - "\n", - "mpl.figure.prototype._remove_fig_handler = function (event) {\n", - " var fig = event.data.fig;\n", - " if (event.target !== this) {\n", - " // Ignore bubbled events from children.\n", - " return;\n", - " }\n", - " fig.close_ws(fig, {});\n", - "};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (el) {\n", - " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (el) {\n", - " // this is important to make the div 'focusable\n", - " el.setAttribute('tabindex', 0);\n", - " // reach out to IPython and tell the keyboard manager to turn it's self\n", - " // off when our div gets focus\n", - "\n", - " // location in version 3\n", - " if (IPython.notebook.keyboard_manager) {\n", - " IPython.notebook.keyboard_manager.register_events(el);\n", - " } else {\n", - " // location in version 2\n", - " IPython.keyboard_manager.register_events(el);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", - " var manager = IPython.notebook.keyboard_manager;\n", - " if (!manager) {\n", - " manager = IPython.keyboard_manager;\n", - " }\n", - "\n", - " // Check for shift+enter\n", - " if (event.shiftKey && event.which === 13) {\n", - " this.canvas_div.blur();\n", - " // select the cell after this one\n", - " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", - " IPython.notebook.select(index + 1);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " fig.ondownload(fig, null);\n", - "};\n", - "\n", - "mpl.find_output_cell = function (html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i = 0; i < ncells; i++) {\n", - " var cell = cells[i];\n", - " if (cell.cell_type === 'code') {\n", - " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", - " var data = cell.output_area.outputs[j];\n", - " if (data.data) {\n", - " // IPython >= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] === html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "};\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel !== null) {\n", - " IPython.notebook.kernel.comm_manager.register_target(\n", - " 'matplotlib',\n", - " mpl.mpl_figure_comm\n", - " );\n", - "}\n" - ], + "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n if (typeof WebSocket !== 'undefined') {\n return WebSocket;\n } else if (typeof MozWebSocket !== 'undefined') {\n return MozWebSocket;\n } else {\n alert(\n 'Your browser does not have WebSocket support. ' +\n 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n 'Firefox 4 and 5 are also supported but you ' +\n 'have to enable WebSockets in about:config.'\n );\n }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n this.id = figure_id;\n\n this.ws = websocket;\n\n this.supports_binary = this.ws.binaryType !== undefined;\n\n if (!this.supports_binary) {\n var warnings = document.getElementById('mpl-warnings');\n if (warnings) {\n warnings.style.display = 'block';\n warnings.textContent =\n 'This browser does not support binary websocket messages. ' +\n 'Performance may be slow.';\n }\n }\n\n this.imageObj = new Image();\n\n this.context = undefined;\n this.message = undefined;\n this.canvas = undefined;\n this.rubberband_canvas = undefined;\n this.rubberband_context = undefined;\n this.format_dropdown = undefined;\n\n this.image_mode = 'full';\n\n this.root = document.createElement('div');\n this.root.setAttribute('style', 'display: inline-block');\n this._root_extra_style(this.root);\n\n parent_element.appendChild(this.root);\n\n this._init_header(this);\n this._init_canvas(this);\n this._init_toolbar(this);\n\n var fig = this;\n\n this.waiting = false;\n\n this.ws.onopen = function () {\n fig.send_message('supports_binary', { value: fig.supports_binary });\n fig.send_message('send_image_mode', {});\n if (fig.ratio !== 1) {\n fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n }\n fig.send_message('refresh', {});\n };\n\n this.imageObj.onload = function () {\n if (fig.image_mode === 'full') {\n // Full images could contain transparency (where diff images\n // almost always do), so we need to clear the canvas so that\n // there is no ghosting.\n fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n }\n fig.context.drawImage(fig.imageObj, 0, 0);\n };\n\n this.imageObj.onunload = function () {\n fig.ws.close();\n };\n\n this.ws.onmessage = this._make_on_message_function(this);\n\n this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n var titlebar = document.createElement('div');\n titlebar.classList =\n 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n var titletext = document.createElement('div');\n titletext.classList = 'ui-dialog-title';\n titletext.setAttribute(\n 'style',\n 'width: 100%; text-align: center; padding: 3px;'\n );\n titlebar.appendChild(titletext);\n this.root.appendChild(titlebar);\n this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n var fig = this;\n\n var canvas_div = (this.canvas_div = document.createElement('div'));\n canvas_div.setAttribute(\n 'style',\n 'border: 1px solid #ddd;' +\n 'box-sizing: content-box;' +\n 'clear: both;' +\n 'min-height: 1px;' +\n 'min-width: 1px;' +\n 'outline: 0;' +\n 'overflow: hidden;' +\n 'position: relative;' +\n 'resize: both;'\n );\n\n function on_keyboard_event_closure(name) {\n return function (event) {\n return fig.key_event(event, name);\n };\n }\n\n canvas_div.addEventListener(\n 'keydown',\n on_keyboard_event_closure('key_press')\n );\n canvas_div.addEventListener(\n 'keyup',\n on_keyboard_event_closure('key_release')\n );\n\n this._canvas_extra_style(canvas_div);\n this.root.appendChild(canvas_div);\n\n var canvas = (this.canvas = document.createElement('canvas'));\n canvas.classList.add('mpl-canvas');\n canvas.setAttribute('style', 'box-sizing: content-box;');\n\n this.context = canvas.getContext('2d');\n\n var backingStore =\n this.context.backingStorePixelRatio ||\n this.context.webkitBackingStorePixelRatio ||\n this.context.mozBackingStorePixelRatio ||\n this.context.msBackingStorePixelRatio ||\n this.context.oBackingStorePixelRatio ||\n this.context.backingStorePixelRatio ||\n 1;\n\n this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n 'canvas'\n ));\n rubberband_canvas.setAttribute(\n 'style',\n 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n );\n\n // Apply a ponyfill if ResizeObserver is not implemented by browser.\n if (this.ResizeObserver === undefined) {\n if (window.ResizeObserver !== undefined) {\n this.ResizeObserver = window.ResizeObserver;\n } else {\n var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n this.ResizeObserver = obs.ResizeObserver;\n }\n }\n\n this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n var nentries = entries.length;\n for (var i = 0; i < nentries; i++) {\n var entry = entries[i];\n var width, height;\n if (entry.contentBoxSize) {\n if (entry.contentBoxSize instanceof Array) {\n // Chrome 84 implements new version of spec.\n width = entry.contentBoxSize[0].inlineSize;\n height = entry.contentBoxSize[0].blockSize;\n } else {\n // Firefox implements old version of spec.\n width = entry.contentBoxSize.inlineSize;\n height = entry.contentBoxSize.blockSize;\n }\n } else {\n // Chrome <84 implements even older version of spec.\n width = entry.contentRect.width;\n height = entry.contentRect.height;\n }\n\n // Keep the size of the canvas and rubber band canvas in sync with\n // the canvas container.\n if (entry.devicePixelContentBoxSize) {\n // Chrome 84 implements new version of spec.\n canvas.setAttribute(\n 'width',\n entry.devicePixelContentBoxSize[0].inlineSize\n );\n canvas.setAttribute(\n 'height',\n entry.devicePixelContentBoxSize[0].blockSize\n );\n } else {\n canvas.setAttribute('width', width * fig.ratio);\n canvas.setAttribute('height', height * fig.ratio);\n }\n canvas.setAttribute(\n 'style',\n 'width: ' + width + 'px; height: ' + height + 'px;'\n );\n\n rubberband_canvas.setAttribute('width', width);\n rubberband_canvas.setAttribute('height', height);\n\n // And update the size in Python. We ignore the initial 0/0 size\n // that occurs as the element is placed into the DOM, which should\n // otherwise not happen due to the minimum size styling.\n if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n fig.request_resize(width, height);\n }\n }\n });\n this.resizeObserverInstance.observe(canvas_div);\n\n function on_mouse_event_closure(name) {\n return function (event) {\n return fig.mouse_event(event, name);\n };\n }\n\n rubberband_canvas.addEventListener(\n 'mousedown',\n on_mouse_event_closure('button_press')\n );\n rubberband_canvas.addEventListener(\n 'mouseup',\n on_mouse_event_closure('button_release')\n );\n // Throttle sequential mouse events to 1 every 20ms.\n rubberband_canvas.addEventListener(\n 'mousemove',\n on_mouse_event_closure('motion_notify')\n );\n\n rubberband_canvas.addEventListener(\n 'mouseenter',\n on_mouse_event_closure('figure_enter')\n );\n rubberband_canvas.addEventListener(\n 'mouseleave',\n on_mouse_event_closure('figure_leave')\n );\n\n canvas_div.addEventListener('wheel', function (event) {\n if (event.deltaY < 0) {\n event.step = 1;\n } else {\n event.step = -1;\n }\n on_mouse_event_closure('scroll')(event);\n });\n\n canvas_div.appendChild(canvas);\n canvas_div.appendChild(rubberband_canvas);\n\n this.rubberband_context = rubberband_canvas.getContext('2d');\n this.rubberband_context.strokeStyle = '#000000';\n\n this._resize_canvas = function (width, height, forward) {\n if (forward) {\n canvas_div.style.width = width + 'px';\n canvas_div.style.height = height + 'px';\n }\n };\n\n // Disable right mouse context menu.\n this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n event.preventDefault();\n return false;\n });\n\n function set_focus() {\n canvas.focus();\n canvas_div.focus();\n }\n\n window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'mpl-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n continue;\n }\n\n var button = (fig.buttons[name] = document.createElement('button'));\n button.classList = 'mpl-widget';\n button.setAttribute('role', 'button');\n button.setAttribute('aria-disabled', 'false');\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n var icon_img = document.createElement('img');\n icon_img.src = '_images/' + image + '.png';\n icon_img.srcset = '_images/' + image + '_large.png 2x';\n icon_img.alt = tooltip;\n button.appendChild(icon_img);\n\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n var fmt_picker = document.createElement('select');\n fmt_picker.classList = 'mpl-widget';\n toolbar.appendChild(fmt_picker);\n this.format_dropdown = fmt_picker;\n\n for (var ind in mpl.extensions) {\n var fmt = mpl.extensions[ind];\n var option = document.createElement('option');\n option.selected = fmt === mpl.default_extension;\n option.innerHTML = fmt;\n fmt_picker.appendChild(option);\n }\n\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n // which will in turn request a refresh of the image.\n this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n properties['type'] = type;\n properties['figure_id'] = this.id;\n this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n if (!this.waiting) {\n this.waiting = true;\n this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n var format_dropdown = fig.format_dropdown;\n var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n var size = msg['size'];\n if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n fig._resize_canvas(size[0], size[1], msg['forward']);\n fig.send_message('refresh', {});\n }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n var x0 = msg['x0'] / fig.ratio;\n var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n var x1 = msg['x1'] / fig.ratio;\n var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n x0 = Math.floor(x0) + 0.5;\n y0 = Math.floor(y0) + 0.5;\n x1 = Math.floor(x1) + 0.5;\n y1 = Math.floor(y1) + 0.5;\n var min_x = Math.min(x0, x1);\n var min_y = Math.min(y0, y1);\n var width = Math.abs(x1 - x0);\n var height = Math.abs(y1 - y0);\n\n fig.rubberband_context.clearRect(\n 0,\n 0,\n fig.canvas.width / fig.ratio,\n fig.canvas.height / fig.ratio\n );\n\n fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n // Updates the figure title.\n fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n var cursor = msg['cursor'];\n switch (cursor) {\n case 0:\n cursor = 'pointer';\n break;\n case 1:\n cursor = 'default';\n break;\n case 2:\n cursor = 'crosshair';\n break;\n case 3:\n cursor = 'move';\n break;\n }\n fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n // Request the server to send over a new figure.\n fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n for (var key in msg) {\n if (!(key in fig.buttons)) {\n continue;\n }\n fig.buttons[key].disabled = !msg[key];\n fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n if (msg['mode'] === 'PAN') {\n fig.buttons['Pan'].classList.add('active');\n fig.buttons['Zoom'].classList.remove('active');\n } else if (msg['mode'] === 'ZOOM') {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.add('active');\n } else {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.remove('active');\n }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Called whenever the canvas gets updated.\n this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n return function socket_on_message(evt) {\n if (evt.data instanceof Blob) {\n /* FIXME: We get \"Resource interpreted as Image but\n * transferred with MIME type text/plain:\" errors on\n * Chrome. But how to set the MIME type? It doesn't seem\n * to be part of the websocket stream */\n evt.data.type = 'image/png';\n\n /* Free the memory for the previous frames */\n if (fig.imageObj.src) {\n (window.URL || window.webkitURL).revokeObjectURL(\n fig.imageObj.src\n );\n }\n\n fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n evt.data\n );\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n } else if (\n typeof evt.data === 'string' &&\n evt.data.slice(0, 21) === 'data:image/png;base64'\n ) {\n fig.imageObj.src = evt.data;\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n }\n\n var msg = JSON.parse(evt.data);\n var msg_type = msg['type'];\n\n // Call the \"handle_{type}\" callback, which takes\n // the figure and JSON message as its only arguments.\n try {\n var callback = fig['handle_' + msg_type];\n } catch (e) {\n console.log(\n \"No handler for the '\" + msg_type + \"' message type: \",\n msg\n );\n return;\n }\n\n if (callback) {\n try {\n // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n callback(fig, msg);\n } catch (e) {\n console.log(\n \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n e,\n e.stack,\n msg\n );\n }\n }\n };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n //this section is from http://www.quirksmode.org/js/events_properties.html\n var targ;\n if (!e) {\n e = window.event;\n }\n if (e.target) {\n targ = e.target;\n } else if (e.srcElement) {\n targ = e.srcElement;\n }\n if (targ.nodeType === 3) {\n // defeat Safari bug\n targ = targ.parentNode;\n }\n\n // pageX,Y are the mouse positions relative to the document\n var boundingRect = targ.getBoundingClientRect();\n var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n return Object.keys(original).reduce(function (obj, key) {\n if (typeof original[key] !== 'object') {\n obj[key] = original[key];\n }\n return obj;\n }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n var canvas_pos = mpl.findpos(event);\n\n if (name === 'button_press') {\n this.canvas.focus();\n this.canvas_div.focus();\n }\n\n var x = canvas_pos.x * this.ratio;\n var y = canvas_pos.y * this.ratio;\n\n this.send_message(name, {\n x: x,\n y: y,\n button: event.button,\n step: event.step,\n guiEvent: simpleKeys(event),\n });\n\n /* This prevents the web browser from automatically changing to\n * the text insertion cursor when the button is pressed. We want\n * to control all of the cursor setting manually through the\n * 'cursor' event from matplotlib */\n event.preventDefault();\n return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n // Prevent repeat events\n if (name === 'key_press') {\n if (event.which === this._key) {\n return;\n } else {\n this._key = event.which;\n }\n }\n if (name === 'key_release') {\n this._key = null;\n }\n\n var value = '';\n if (event.ctrlKey && event.which !== 17) {\n value += 'ctrl+';\n }\n if (event.altKey && event.which !== 18) {\n value += 'alt+';\n }\n if (event.shiftKey && event.which !== 16) {\n value += 'shift+';\n }\n\n value += 'k';\n value += event.which.toString();\n\n this._key_event_extra(event, name);\n\n this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n if (name === 'download') {\n this.handle_save(this, null);\n } else {\n this.send_message('toolbar_button', { name: name });\n }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\nmpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n\nmpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n // Create a \"websocket\"-like object which calls the given IPython comm\n // object with the appropriate methods. Currently this is a non binary\n // socket, so there is still some room for performance tuning.\n var ws = {};\n\n ws.close = function () {\n comm.close();\n };\n ws.send = function (m) {\n //console.log('sending', m);\n comm.send(m);\n };\n // Register the callback with on_msg.\n comm.on_msg(function (msg) {\n //console.log('receiving', msg['content']['data'], msg);\n // Pass the mpl event to the overridden (by mpl) onmessage function.\n ws.onmessage(msg['content']['data']);\n });\n return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n // This is the function which gets called when the mpl process\n // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n var id = msg.content.data.id;\n // Get hold of the div created by the display call when the Comm\n // socket was opened in Python.\n var element = document.getElementById(id);\n var ws_proxy = comm_websocket_adapter(comm);\n\n function ondownload(figure, _format) {\n window.open(figure.canvas.toDataURL());\n }\n\n var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n // web socket which is closed, not our websocket->open comm proxy.\n ws_proxy.onopen();\n\n fig.parent_element = element;\n fig.cell_info = mpl.find_output_cell(\"
\");\n if (!fig.cell_info) {\n console.error('Failed to find cell for figure', id, fig);\n return;\n }\n fig.cell_info[0].output_area.element.on(\n 'cleared',\n { fig: fig },\n fig._remove_fig_handler\n );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n var width = fig.canvas.width / fig.ratio;\n fig.cell_info[0].output_area.element.off(\n 'cleared',\n fig._remove_fig_handler\n );\n fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n // Update the output cell to use the data from the current canvas.\n fig.push_to_output();\n var dataURL = fig.canvas.toDataURL();\n // Re-enable the keyboard manager in IPython - without this line, in FF,\n // the notebook keyboard shortcuts fail.\n IPython.keyboard_manager.enable();\n fig.parent_element.innerHTML =\n '';\n fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n fig.send_message('closing', msg);\n // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n // Turn the data on the canvas into data in the output cell.\n var width = this.canvas.width / this.ratio;\n var dataURL = this.canvas.toDataURL();\n this.cell_info[1]['text/html'] =\n '';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Tell IPython that the notebook contents must change.\n IPython.notebook.set_dirty(true);\n this.send_message('ack', {});\n var fig = this;\n // Wait a second, then push the new image to the DOM so\n // that it is saved nicely (might be nice to debounce this).\n setTimeout(function () {\n fig.push_to_output();\n }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'btn-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n var button;\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n continue;\n }\n\n button = fig.buttons[name] = document.createElement('button');\n button.classList = 'btn btn-default';\n button.href = '#';\n button.title = name;\n button.innerHTML = '';\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n // Add the status bar.\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message pull-right';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n\n // Add the close button to the window.\n var buttongrp = document.createElement('div');\n buttongrp.classList = 'btn-group inline pull-right';\n button = document.createElement('button');\n button.classList = 'btn btn-mini btn-primary';\n button.href = '#';\n button.title = 'Stop Interaction';\n button.innerHTML = '';\n button.addEventListener('click', function (_evt) {\n fig.handle_close(fig, {});\n });\n button.addEventListener(\n 'mouseover',\n on_mouseover_closure('Stop Interaction')\n );\n buttongrp.appendChild(button);\n var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n var fig = event.data.fig;\n if (event.target !== this) {\n // Ignore bubbled events from children.\n return;\n }\n fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n // this is important to make the div 'focusable\n el.setAttribute('tabindex', 0);\n // reach out to IPython and tell the keyboard manager to turn it's self\n // off when our div gets focus\n\n // location in version 3\n if (IPython.notebook.keyboard_manager) {\n IPython.notebook.keyboard_manager.register_events(el);\n } else {\n // location in version 2\n IPython.keyboard_manager.register_events(el);\n }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n var manager = IPython.notebook.keyboard_manager;\n if (!manager) {\n manager = IPython.keyboard_manager;\n }\n\n // Check for shift+enter\n if (event.shiftKey && event.which === 13) {\n this.canvas_div.blur();\n // select the cell after this one\n var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n IPython.notebook.select(index + 1);\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n // Return the cell and output element which can be found *uniquely* in the notebook.\n // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n // IPython event is triggered only after the cells have been serialised, which for\n // our purposes (turning an active figure into a static one), is too late.\n var cells = IPython.notebook.get_cells();\n var ncells = cells.length;\n for (var i = 0; i < ncells; i++) {\n var cell = cells[i];\n if (cell.cell_type === 'code') {\n for (var j = 0; j < cell.output_area.outputs.length; j++) {\n var data = cell.output_area.outputs[j];\n if (data.data) {\n // IPython >= 3 moved mimebundle to data attribute of output\n data = data.data;\n }\n if (data['text/html'] === html_output) {\n return [cell, data, j];\n }\n }\n }\n }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n IPython.notebook.kernel.comm_manager.register_target(\n 'matplotlib',\n mpl.mpl_figure_comm\n );\n}\n", "text/plain": [ "" ] @@ -9570,955 +1038,7 @@ "outputs": [ { "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "/* global mpl */\n", - "window.mpl = {};\n", - "\n", - "mpl.get_websocket_type = function () {\n", - " if (typeof WebSocket !== 'undefined') {\n", - " return WebSocket;\n", - " } else if (typeof MozWebSocket !== 'undefined') {\n", - " return MozWebSocket;\n", - " } else {\n", - " alert(\n", - " 'Your browser does not have WebSocket support. ' +\n", - " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", - " 'Firefox 4 and 5 are also supported but you ' +\n", - " 'have to enable WebSockets in about:config.'\n", - " );\n", - " }\n", - "};\n", - "\n", - "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", - " this.id = figure_id;\n", - "\n", - " this.ws = websocket;\n", - "\n", - " this.supports_binary = this.ws.binaryType !== undefined;\n", - "\n", - " if (!this.supports_binary) {\n", - " var warnings = document.getElementById('mpl-warnings');\n", - " if (warnings) {\n", - " warnings.style.display = 'block';\n", - " warnings.textContent =\n", - " 'This browser does not support binary websocket messages. ' +\n", - " 'Performance may be slow.';\n", - " }\n", - " }\n", - "\n", - " this.imageObj = new Image();\n", - "\n", - " this.context = undefined;\n", - " this.message = undefined;\n", - " this.canvas = undefined;\n", - " this.rubberband_canvas = undefined;\n", - " this.rubberband_context = undefined;\n", - " this.format_dropdown = undefined;\n", - "\n", - " this.image_mode = 'full';\n", - "\n", - " this.root = document.createElement('div');\n", - " this.root.setAttribute('style', 'display: inline-block');\n", - " this._root_extra_style(this.root);\n", - "\n", - " parent_element.appendChild(this.root);\n", - "\n", - " this._init_header(this);\n", - " this._init_canvas(this);\n", - " this._init_toolbar(this);\n", - "\n", - " var fig = this;\n", - "\n", - " this.waiting = false;\n", - "\n", - " this.ws.onopen = function () {\n", - " fig.send_message('supports_binary', { value: fig.supports_binary });\n", - " fig.send_message('send_image_mode', {});\n", - " if (fig.ratio !== 1) {\n", - " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", - " }\n", - " fig.send_message('refresh', {});\n", - " };\n", - "\n", - " this.imageObj.onload = function () {\n", - " if (fig.image_mode === 'full') {\n", - " // Full images could contain transparency (where diff images\n", - " // almost always do), so we need to clear the canvas so that\n", - " // there is no ghosting.\n", - " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", - " }\n", - " fig.context.drawImage(fig.imageObj, 0, 0);\n", - " };\n", - "\n", - " this.imageObj.onunload = function () {\n", - " fig.ws.close();\n", - " };\n", - "\n", - " this.ws.onmessage = this._make_on_message_function(this);\n", - "\n", - " this.ondownload = ondownload;\n", - "};\n", - "\n", - "mpl.figure.prototype._init_header = function () {\n", - " var titlebar = document.createElement('div');\n", - " titlebar.classList =\n", - " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", - " var titletext = document.createElement('div');\n", - " titletext.classList = 'ui-dialog-title';\n", - " titletext.setAttribute(\n", - " 'style',\n", - " 'width: 100%; text-align: center; padding: 3px;'\n", - " );\n", - " titlebar.appendChild(titletext);\n", - " this.root.appendChild(titlebar);\n", - " this.header = titletext;\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._init_canvas = function () {\n", - " var fig = this;\n", - "\n", - " var canvas_div = (this.canvas_div = document.createElement('div'));\n", - " canvas_div.setAttribute(\n", - " 'style',\n", - " 'border: 1px solid #ddd;' +\n", - " 'box-sizing: content-box;' +\n", - " 'clear: both;' +\n", - " 'min-height: 1px;' +\n", - " 'min-width: 1px;' +\n", - " 'outline: 0;' +\n", - " 'overflow: hidden;' +\n", - " 'position: relative;' +\n", - " 'resize: both;'\n", - " );\n", - "\n", - " function on_keyboard_event_closure(name) {\n", - " return function (event) {\n", - " return fig.key_event(event, name);\n", - " };\n", - " }\n", - "\n", - " canvas_div.addEventListener(\n", - " 'keydown',\n", - " on_keyboard_event_closure('key_press')\n", - " );\n", - " canvas_div.addEventListener(\n", - " 'keyup',\n", - " on_keyboard_event_closure('key_release')\n", - " );\n", - "\n", - " this._canvas_extra_style(canvas_div);\n", - " this.root.appendChild(canvas_div);\n", - "\n", - " var canvas = (this.canvas = document.createElement('canvas'));\n", - " canvas.classList.add('mpl-canvas');\n", - " canvas.setAttribute('style', 'box-sizing: content-box;');\n", - "\n", - " this.context = canvas.getContext('2d');\n", - "\n", - " var backingStore =\n", - " this.context.backingStorePixelRatio ||\n", - " this.context.webkitBackingStorePixelRatio ||\n", - " this.context.mozBackingStorePixelRatio ||\n", - " this.context.msBackingStorePixelRatio ||\n", - " this.context.oBackingStorePixelRatio ||\n", - " this.context.backingStorePixelRatio ||\n", - " 1;\n", - "\n", - " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", - "\n", - " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", - " 'canvas'\n", - " ));\n", - " rubberband_canvas.setAttribute(\n", - " 'style',\n", - " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", - " );\n", - "\n", - " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", - " if (this.ResizeObserver === undefined) {\n", - " if (window.ResizeObserver !== undefined) {\n", - " this.ResizeObserver = window.ResizeObserver;\n", - " } else {\n", - " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", - " this.ResizeObserver = obs.ResizeObserver;\n", - " }\n", - " }\n", - "\n", - " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", - " var nentries = entries.length;\n", - " for (var i = 0; i < nentries; i++) {\n", - " var entry = entries[i];\n", - " var width, height;\n", - " if (entry.contentBoxSize) {\n", - " if (entry.contentBoxSize instanceof Array) {\n", - " // Chrome 84 implements new version of spec.\n", - " width = entry.contentBoxSize[0].inlineSize;\n", - " height = entry.contentBoxSize[0].blockSize;\n", - " } else {\n", - " // Firefox implements old version of spec.\n", - " width = entry.contentBoxSize.inlineSize;\n", - " height = entry.contentBoxSize.blockSize;\n", - " }\n", - " } else {\n", - " // Chrome <84 implements even older version of spec.\n", - " width = entry.contentRect.width;\n", - " height = entry.contentRect.height;\n", - " }\n", - "\n", - " // Keep the size of the canvas and rubber band canvas in sync with\n", - " // the canvas container.\n", - " if (entry.devicePixelContentBoxSize) {\n", - " // Chrome 84 implements new version of spec.\n", - " canvas.setAttribute(\n", - " 'width',\n", - " entry.devicePixelContentBoxSize[0].inlineSize\n", - " );\n", - " canvas.setAttribute(\n", - " 'height',\n", - " entry.devicePixelContentBoxSize[0].blockSize\n", - " );\n", - " } else {\n", - " canvas.setAttribute('width', width * fig.ratio);\n", - " canvas.setAttribute('height', height * fig.ratio);\n", - " }\n", - " canvas.setAttribute(\n", - " 'style',\n", - " 'width: ' + width + 'px; height: ' + height + 'px;'\n", - " );\n", - "\n", - " rubberband_canvas.setAttribute('width', width);\n", - " rubberband_canvas.setAttribute('height', height);\n", - "\n", - " // And update the size in Python. We ignore the initial 0/0 size\n", - " // that occurs as the element is placed into the DOM, which should\n", - " // otherwise not happen due to the minimum size styling.\n", - " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", - " fig.request_resize(width, height);\n", - " }\n", - " }\n", - " });\n", - " this.resizeObserverInstance.observe(canvas_div);\n", - "\n", - " function on_mouse_event_closure(name) {\n", - " return function (event) {\n", - " return fig.mouse_event(event, name);\n", - " };\n", - " }\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mousedown',\n", - " on_mouse_event_closure('button_press')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseup',\n", - " on_mouse_event_closure('button_release')\n", - " );\n", - " // Throttle sequential mouse events to 1 every 20ms.\n", - " rubberband_canvas.addEventListener(\n", - " 'mousemove',\n", - " on_mouse_event_closure('motion_notify')\n", - " );\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseenter',\n", - " on_mouse_event_closure('figure_enter')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseleave',\n", - " on_mouse_event_closure('figure_leave')\n", - " );\n", - "\n", - " canvas_div.addEventListener('wheel', function (event) {\n", - " if (event.deltaY < 0) {\n", - " event.step = 1;\n", - " } else {\n", - " event.step = -1;\n", - " }\n", - " on_mouse_event_closure('scroll')(event);\n", - " });\n", - "\n", - " canvas_div.appendChild(canvas);\n", - " canvas_div.appendChild(rubberband_canvas);\n", - "\n", - " this.rubberband_context = rubberband_canvas.getContext('2d');\n", - " this.rubberband_context.strokeStyle = '#000000';\n", - "\n", - " this._resize_canvas = function (width, height, forward) {\n", - " if (forward) {\n", - " canvas_div.style.width = width + 'px';\n", - " canvas_div.style.height = height + 'px';\n", - " }\n", - " };\n", - "\n", - " // Disable right mouse context menu.\n", - " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", - " event.preventDefault();\n", - " return false;\n", - " });\n", - "\n", - " function set_focus() {\n", - " canvas.focus();\n", - " canvas_div.focus();\n", - " }\n", - "\n", - " window.setTimeout(set_focus, 100);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'mpl-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " continue;\n", - " }\n", - "\n", - " var button = (fig.buttons[name] = document.createElement('button'));\n", - " button.classList = 'mpl-widget';\n", - " button.setAttribute('role', 'button');\n", - " button.setAttribute('aria-disabled', 'false');\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - "\n", - " var icon_img = document.createElement('img');\n", - " icon_img.src = '_images/' + image + '.png';\n", - " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", - " icon_img.alt = tooltip;\n", - " button.appendChild(icon_img);\n", - "\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " var fmt_picker = document.createElement('select');\n", - " fmt_picker.classList = 'mpl-widget';\n", - " toolbar.appendChild(fmt_picker);\n", - " this.format_dropdown = fmt_picker;\n", - "\n", - " for (var ind in mpl.extensions) {\n", - " var fmt = mpl.extensions[ind];\n", - " var option = document.createElement('option');\n", - " option.selected = fmt === mpl.default_extension;\n", - " option.innerHTML = fmt;\n", - " fmt_picker.appendChild(option);\n", - " }\n", - "\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "};\n", - "\n", - "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", - " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", - " // which will in turn request a refresh of the image.\n", - " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", - "};\n", - "\n", - "mpl.figure.prototype.send_message = function (type, properties) {\n", - " properties['type'] = type;\n", - " properties['figure_id'] = this.id;\n", - " this.ws.send(JSON.stringify(properties));\n", - "};\n", - "\n", - "mpl.figure.prototype.send_draw_message = function () {\n", - " if (!this.waiting) {\n", - " this.waiting = true;\n", - " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " var format_dropdown = fig.format_dropdown;\n", - " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", - " fig.ondownload(fig, format);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", - " var size = msg['size'];\n", - " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", - " fig._resize_canvas(size[0], size[1], msg['forward']);\n", - " fig.send_message('refresh', {});\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", - " var x0 = msg['x0'] / fig.ratio;\n", - " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", - " var x1 = msg['x1'] / fig.ratio;\n", - " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", - " x0 = Math.floor(x0) + 0.5;\n", - " y0 = Math.floor(y0) + 0.5;\n", - " x1 = Math.floor(x1) + 0.5;\n", - " y1 = Math.floor(y1) + 0.5;\n", - " var min_x = Math.min(x0, x1);\n", - " var min_y = Math.min(y0, y1);\n", - " var width = Math.abs(x1 - x0);\n", - " var height = Math.abs(y1 - y0);\n", - "\n", - " fig.rubberband_context.clearRect(\n", - " 0,\n", - " 0,\n", - " fig.canvas.width / fig.ratio,\n", - " fig.canvas.height / fig.ratio\n", - " );\n", - "\n", - " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", - " // Updates the figure title.\n", - " fig.header.textContent = msg['label'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", - " var cursor = msg['cursor'];\n", - " switch (cursor) {\n", - " case 0:\n", - " cursor = 'pointer';\n", - " break;\n", - " case 1:\n", - " cursor = 'default';\n", - " break;\n", - " case 2:\n", - " cursor = 'crosshair';\n", - " break;\n", - " case 3:\n", - " cursor = 'move';\n", - " break;\n", - " }\n", - " fig.rubberband_canvas.style.cursor = cursor;\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_message = function (fig, msg) {\n", - " fig.message.textContent = msg['message'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", - " // Request the server to send over a new figure.\n", - " fig.send_draw_message();\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", - " fig.image_mode = msg['mode'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", - " for (var key in msg) {\n", - " if (!(key in fig.buttons)) {\n", - " continue;\n", - " }\n", - " fig.buttons[key].disabled = !msg[key];\n", - " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", - " if (msg['mode'] === 'PAN') {\n", - " fig.buttons['Pan'].classList.add('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " } else if (msg['mode'] === 'ZOOM') {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.add('active');\n", - " } else {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Called whenever the canvas gets updated.\n", - " this.send_message('ack', {});\n", - "};\n", - "\n", - "// A function to construct a web socket function for onmessage handling.\n", - "// Called in the figure constructor.\n", - "mpl.figure.prototype._make_on_message_function = function (fig) {\n", - " return function socket_on_message(evt) {\n", - " if (evt.data instanceof Blob) {\n", - " /* FIXME: We get \"Resource interpreted as Image but\n", - " * transferred with MIME type text/plain:\" errors on\n", - " * Chrome. But how to set the MIME type? It doesn't seem\n", - " * to be part of the websocket stream */\n", - " evt.data.type = 'image/png';\n", - "\n", - " /* Free the memory for the previous frames */\n", - " if (fig.imageObj.src) {\n", - " (window.URL || window.webkitURL).revokeObjectURL(\n", - " fig.imageObj.src\n", - " );\n", - " }\n", - "\n", - " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", - " evt.data\n", - " );\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " } else if (\n", - " typeof evt.data === 'string' &&\n", - " evt.data.slice(0, 21) === 'data:image/png;base64'\n", - " ) {\n", - " fig.imageObj.src = evt.data;\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " }\n", - "\n", - " var msg = JSON.parse(evt.data);\n", - " var msg_type = msg['type'];\n", - "\n", - " // Call the \"handle_{type}\" callback, which takes\n", - " // the figure and JSON message as its only arguments.\n", - " try {\n", - " var callback = fig['handle_' + msg_type];\n", - " } catch (e) {\n", - " console.log(\n", - " \"No handler for the '\" + msg_type + \"' message type: \",\n", - " msg\n", - " );\n", - " return;\n", - " }\n", - "\n", - " if (callback) {\n", - " try {\n", - " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", - " callback(fig, msg);\n", - " } catch (e) {\n", - " console.log(\n", - " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", - " e,\n", - " e.stack,\n", - " msg\n", - " );\n", - " }\n", - " }\n", - " };\n", - "};\n", - "\n", - "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", - "mpl.findpos = function (e) {\n", - " //this section is from http://www.quirksmode.org/js/events_properties.html\n", - " var targ;\n", - " if (!e) {\n", - " e = window.event;\n", - " }\n", - " if (e.target) {\n", - " targ = e.target;\n", - " } else if (e.srcElement) {\n", - " targ = e.srcElement;\n", - " }\n", - " if (targ.nodeType === 3) {\n", - " // defeat Safari bug\n", - " targ = targ.parentNode;\n", - " }\n", - "\n", - " // pageX,Y are the mouse positions relative to the document\n", - " var boundingRect = targ.getBoundingClientRect();\n", - " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", - " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", - "\n", - " return { x: x, y: y };\n", - "};\n", - "\n", - "/*\n", - " * return a copy of an object with only non-object keys\n", - " * we need this to avoid circular references\n", - " * http://stackoverflow.com/a/24161582/3208463\n", - " */\n", - "function simpleKeys(original) {\n", - " return Object.keys(original).reduce(function (obj, key) {\n", - " if (typeof original[key] !== 'object') {\n", - " obj[key] = original[key];\n", - " }\n", - " return obj;\n", - " }, {});\n", - "}\n", - "\n", - "mpl.figure.prototype.mouse_event = function (event, name) {\n", - " var canvas_pos = mpl.findpos(event);\n", - "\n", - " if (name === 'button_press') {\n", - " this.canvas.focus();\n", - " this.canvas_div.focus();\n", - " }\n", - "\n", - " var x = canvas_pos.x * this.ratio;\n", - " var y = canvas_pos.y * this.ratio;\n", - "\n", - " this.send_message(name, {\n", - " x: x,\n", - " y: y,\n", - " button: event.button,\n", - " step: event.step,\n", - " guiEvent: simpleKeys(event),\n", - " });\n", - "\n", - " /* This prevents the web browser from automatically changing to\n", - " * the text insertion cursor when the button is pressed. We want\n", - " * to control all of the cursor setting manually through the\n", - " * 'cursor' event from matplotlib */\n", - " event.preventDefault();\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", - " // Handle any extra behaviour associated with a key event\n", - "};\n", - "\n", - "mpl.figure.prototype.key_event = function (event, name) {\n", - " // Prevent repeat events\n", - " if (name === 'key_press') {\n", - " if (event.which === this._key) {\n", - " return;\n", - " } else {\n", - " this._key = event.which;\n", - " }\n", - " }\n", - " if (name === 'key_release') {\n", - " this._key = null;\n", - " }\n", - "\n", - " var value = '';\n", - " if (event.ctrlKey && event.which !== 17) {\n", - " value += 'ctrl+';\n", - " }\n", - " if (event.altKey && event.which !== 18) {\n", - " value += 'alt+';\n", - " }\n", - " if (event.shiftKey && event.which !== 16) {\n", - " value += 'shift+';\n", - " }\n", - "\n", - " value += 'k';\n", - " value += event.which.toString();\n", - "\n", - " this._key_event_extra(event, name);\n", - "\n", - " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", - " if (name === 'download') {\n", - " this.handle_save(this, null);\n", - " } else {\n", - " this.send_message('toolbar_button', { name: name });\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", - " this.message.textContent = tooltip;\n", - "};\n", - "\n", - "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", - "// prettier-ignore\n", - "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", - "\n", - "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", - "\n", - "mpl.default_extension = \"png\";/* global mpl */\n", - "\n", - "var comm_websocket_adapter = function (comm) {\n", - " // Create a \"websocket\"-like object which calls the given IPython comm\n", - " // object with the appropriate methods. Currently this is a non binary\n", - " // socket, so there is still some room for performance tuning.\n", - " var ws = {};\n", - "\n", - " ws.close = function () {\n", - " comm.close();\n", - " };\n", - " ws.send = function (m) {\n", - " //console.log('sending', m);\n", - " comm.send(m);\n", - " };\n", - " // Register the callback with on_msg.\n", - " comm.on_msg(function (msg) {\n", - " //console.log('receiving', msg['content']['data'], msg);\n", - " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", - " ws.onmessage(msg['content']['data']);\n", - " });\n", - " return ws;\n", - "};\n", - "\n", - "mpl.mpl_figure_comm = function (comm, msg) {\n", - " // This is the function which gets called when the mpl process\n", - " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", - "\n", - " var id = msg.content.data.id;\n", - " // Get hold of the div created by the display call when the Comm\n", - " // socket was opened in Python.\n", - " var element = document.getElementById(id);\n", - " var ws_proxy = comm_websocket_adapter(comm);\n", - "\n", - " function ondownload(figure, _format) {\n", - " window.open(figure.canvas.toDataURL());\n", - " }\n", - "\n", - " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", - "\n", - " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", - " // web socket which is closed, not our websocket->open comm proxy.\n", - " ws_proxy.onopen();\n", - "\n", - " fig.parent_element = element;\n", - " fig.cell_info = mpl.find_output_cell(\"
\");\n", - " if (!fig.cell_info) {\n", - " console.error('Failed to find cell for figure', id, fig);\n", - " return;\n", - " }\n", - " fig.cell_info[0].output_area.element.on(\n", - " 'cleared',\n", - " { fig: fig },\n", - " fig._remove_fig_handler\n", - " );\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_close = function (fig, msg) {\n", - " var width = fig.canvas.width / fig.ratio;\n", - " fig.cell_info[0].output_area.element.off(\n", - " 'cleared',\n", - " fig._remove_fig_handler\n", - " );\n", - " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", - "\n", - " // Update the output cell to use the data from the current canvas.\n", - " fig.push_to_output();\n", - " var dataURL = fig.canvas.toDataURL();\n", - " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", - " // the notebook keyboard shortcuts fail.\n", - " IPython.keyboard_manager.enable();\n", - " fig.parent_element.innerHTML =\n", - " '';\n", - " fig.close_ws(fig, msg);\n", - "};\n", - "\n", - "mpl.figure.prototype.close_ws = function (fig, msg) {\n", - " fig.send_message('closing', msg);\n", - " // fig.ws.close()\n", - "};\n", - "\n", - "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", - " // Turn the data on the canvas into data in the output cell.\n", - " var width = this.canvas.width / this.ratio;\n", - " var dataURL = this.canvas.toDataURL();\n", - " this.cell_info[1]['text/html'] =\n", - " '';\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Tell IPython that the notebook contents must change.\n", - " IPython.notebook.set_dirty(true);\n", - " this.send_message('ack', {});\n", - " var fig = this;\n", - " // Wait a second, then push the new image to the DOM so\n", - " // that it is saved nicely (might be nice to debounce this).\n", - " setTimeout(function () {\n", - " fig.push_to_output();\n", - " }, 1000);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'btn-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " var button;\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " continue;\n", - " }\n", - "\n", - " button = fig.buttons[name] = document.createElement('button');\n", - " button.classList = 'btn btn-default';\n", - " button.href = '#';\n", - " button.title = name;\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " // Add the status bar.\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message pull-right';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "\n", - " // Add the close button to the window.\n", - " var buttongrp = document.createElement('div');\n", - " buttongrp.classList = 'btn-group inline pull-right';\n", - " button = document.createElement('button');\n", - " button.classList = 'btn btn-mini btn-primary';\n", - " button.href = '#';\n", - " button.title = 'Stop Interaction';\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', function (_evt) {\n", - " fig.handle_close(fig, {});\n", - " });\n", - " button.addEventListener(\n", - " 'mouseover',\n", - " on_mouseover_closure('Stop Interaction')\n", - " );\n", - " buttongrp.appendChild(button);\n", - " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", - " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", - "};\n", - "\n", - "mpl.figure.prototype._remove_fig_handler = function (event) {\n", - " var fig = event.data.fig;\n", - " if (event.target !== this) {\n", - " // Ignore bubbled events from children.\n", - " return;\n", - " }\n", - " fig.close_ws(fig, {});\n", - "};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (el) {\n", - " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (el) {\n", - " // this is important to make the div 'focusable\n", - " el.setAttribute('tabindex', 0);\n", - " // reach out to IPython and tell the keyboard manager to turn it's self\n", - " // off when our div gets focus\n", - "\n", - " // location in version 3\n", - " if (IPython.notebook.keyboard_manager) {\n", - " IPython.notebook.keyboard_manager.register_events(el);\n", - " } else {\n", - " // location in version 2\n", - " IPython.keyboard_manager.register_events(el);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", - " var manager = IPython.notebook.keyboard_manager;\n", - " if (!manager) {\n", - " manager = IPython.keyboard_manager;\n", - " }\n", - "\n", - " // Check for shift+enter\n", - " if (event.shiftKey && event.which === 13) {\n", - " this.canvas_div.blur();\n", - " // select the cell after this one\n", - " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", - " IPython.notebook.select(index + 1);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " fig.ondownload(fig, null);\n", - "};\n", - "\n", - "mpl.find_output_cell = function (html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i = 0; i < ncells; i++) {\n", - " var cell = cells[i];\n", - " if (cell.cell_type === 'code') {\n", - " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", - " var data = cell.output_area.outputs[j];\n", - " if (data.data) {\n", - " // IPython >= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] === html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "};\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel !== null) {\n", - " IPython.notebook.kernel.comm_manager.register_target(\n", - " 'matplotlib',\n", - " mpl.mpl_figure_comm\n", - " );\n", - "}\n" - ], + "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n if (typeof WebSocket !== 'undefined') {\n return WebSocket;\n } else if (typeof MozWebSocket !== 'undefined') {\n return MozWebSocket;\n } else {\n alert(\n 'Your browser does not have WebSocket support. ' +\n 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n 'Firefox 4 and 5 are also supported but you ' +\n 'have to enable WebSockets in about:config.'\n );\n }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n this.id = figure_id;\n\n this.ws = websocket;\n\n this.supports_binary = this.ws.binaryType !== undefined;\n\n if (!this.supports_binary) {\n var warnings = document.getElementById('mpl-warnings');\n if (warnings) {\n warnings.style.display = 'block';\n warnings.textContent =\n 'This browser does not support binary websocket messages. ' +\n 'Performance may be slow.';\n }\n }\n\n this.imageObj = new Image();\n\n this.context = undefined;\n this.message = undefined;\n this.canvas = undefined;\n this.rubberband_canvas = undefined;\n this.rubberband_context = undefined;\n this.format_dropdown = undefined;\n\n this.image_mode = 'full';\n\n this.root = document.createElement('div');\n this.root.setAttribute('style', 'display: inline-block');\n this._root_extra_style(this.root);\n\n parent_element.appendChild(this.root);\n\n this._init_header(this);\n this._init_canvas(this);\n this._init_toolbar(this);\n\n var fig = this;\n\n this.waiting = false;\n\n this.ws.onopen = function () {\n fig.send_message('supports_binary', { value: fig.supports_binary });\n fig.send_message('send_image_mode', {});\n if (fig.ratio !== 1) {\n fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n }\n fig.send_message('refresh', {});\n };\n\n this.imageObj.onload = function () {\n if (fig.image_mode === 'full') {\n // Full images could contain transparency (where diff images\n // almost always do), so we need to clear the canvas so that\n // there is no ghosting.\n fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n }\n fig.context.drawImage(fig.imageObj, 0, 0);\n };\n\n this.imageObj.onunload = function () {\n fig.ws.close();\n };\n\n this.ws.onmessage = this._make_on_message_function(this);\n\n this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n var titlebar = document.createElement('div');\n titlebar.classList =\n 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n var titletext = document.createElement('div');\n titletext.classList = 'ui-dialog-title';\n titletext.setAttribute(\n 'style',\n 'width: 100%; text-align: center; padding: 3px;'\n );\n titlebar.appendChild(titletext);\n this.root.appendChild(titlebar);\n this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n var fig = this;\n\n var canvas_div = (this.canvas_div = document.createElement('div'));\n canvas_div.setAttribute(\n 'style',\n 'border: 1px solid #ddd;' +\n 'box-sizing: content-box;' +\n 'clear: both;' +\n 'min-height: 1px;' +\n 'min-width: 1px;' +\n 'outline: 0;' +\n 'overflow: hidden;' +\n 'position: relative;' +\n 'resize: both;'\n );\n\n function on_keyboard_event_closure(name) {\n return function (event) {\n return fig.key_event(event, name);\n };\n }\n\n canvas_div.addEventListener(\n 'keydown',\n on_keyboard_event_closure('key_press')\n );\n canvas_div.addEventListener(\n 'keyup',\n on_keyboard_event_closure('key_release')\n );\n\n this._canvas_extra_style(canvas_div);\n this.root.appendChild(canvas_div);\n\n var canvas = (this.canvas = document.createElement('canvas'));\n canvas.classList.add('mpl-canvas');\n canvas.setAttribute('style', 'box-sizing: content-box;');\n\n this.context = canvas.getContext('2d');\n\n var backingStore =\n this.context.backingStorePixelRatio ||\n this.context.webkitBackingStorePixelRatio ||\n this.context.mozBackingStorePixelRatio ||\n this.context.msBackingStorePixelRatio ||\n this.context.oBackingStorePixelRatio ||\n this.context.backingStorePixelRatio ||\n 1;\n\n this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n 'canvas'\n ));\n rubberband_canvas.setAttribute(\n 'style',\n 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n );\n\n // Apply a ponyfill if ResizeObserver is not implemented by browser.\n if (this.ResizeObserver === undefined) {\n if (window.ResizeObserver !== undefined) {\n this.ResizeObserver = window.ResizeObserver;\n } else {\n var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n this.ResizeObserver = obs.ResizeObserver;\n }\n }\n\n this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n var nentries = entries.length;\n for (var i = 0; i < nentries; i++) {\n var entry = entries[i];\n var width, height;\n if (entry.contentBoxSize) {\n if (entry.contentBoxSize instanceof Array) {\n // Chrome 84 implements new version of spec.\n width = entry.contentBoxSize[0].inlineSize;\n height = entry.contentBoxSize[0].blockSize;\n } else {\n // Firefox implements old version of spec.\n width = entry.contentBoxSize.inlineSize;\n height = entry.contentBoxSize.blockSize;\n }\n } else {\n // Chrome <84 implements even older version of spec.\n width = entry.contentRect.width;\n height = entry.contentRect.height;\n }\n\n // Keep the size of the canvas and rubber band canvas in sync with\n // the canvas container.\n if (entry.devicePixelContentBoxSize) {\n // Chrome 84 implements new version of spec.\n canvas.setAttribute(\n 'width',\n entry.devicePixelContentBoxSize[0].inlineSize\n );\n canvas.setAttribute(\n 'height',\n entry.devicePixelContentBoxSize[0].blockSize\n );\n } else {\n canvas.setAttribute('width', width * fig.ratio);\n canvas.setAttribute('height', height * fig.ratio);\n }\n canvas.setAttribute(\n 'style',\n 'width: ' + width + 'px; height: ' + height + 'px;'\n );\n\n rubberband_canvas.setAttribute('width', width);\n rubberband_canvas.setAttribute('height', height);\n\n // And update the size in Python. We ignore the initial 0/0 size\n // that occurs as the element is placed into the DOM, which should\n // otherwise not happen due to the minimum size styling.\n if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n fig.request_resize(width, height);\n }\n }\n });\n this.resizeObserverInstance.observe(canvas_div);\n\n function on_mouse_event_closure(name) {\n return function (event) {\n return fig.mouse_event(event, name);\n };\n }\n\n rubberband_canvas.addEventListener(\n 'mousedown',\n on_mouse_event_closure('button_press')\n );\n rubberband_canvas.addEventListener(\n 'mouseup',\n on_mouse_event_closure('button_release')\n );\n // Throttle sequential mouse events to 1 every 20ms.\n rubberband_canvas.addEventListener(\n 'mousemove',\n on_mouse_event_closure('motion_notify')\n );\n\n rubberband_canvas.addEventListener(\n 'mouseenter',\n on_mouse_event_closure('figure_enter')\n );\n rubberband_canvas.addEventListener(\n 'mouseleave',\n on_mouse_event_closure('figure_leave')\n );\n\n canvas_div.addEventListener('wheel', function (event) {\n if (event.deltaY < 0) {\n event.step = 1;\n } else {\n event.step = -1;\n }\n on_mouse_event_closure('scroll')(event);\n });\n\n canvas_div.appendChild(canvas);\n canvas_div.appendChild(rubberband_canvas);\n\n this.rubberband_context = rubberband_canvas.getContext('2d');\n this.rubberband_context.strokeStyle = '#000000';\n\n this._resize_canvas = function (width, height, forward) {\n if (forward) {\n canvas_div.style.width = width + 'px';\n canvas_div.style.height = height + 'px';\n }\n };\n\n // Disable right mouse context menu.\n this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n event.preventDefault();\n return false;\n });\n\n function set_focus() {\n canvas.focus();\n canvas_div.focus();\n }\n\n window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'mpl-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n continue;\n }\n\n var button = (fig.buttons[name] = document.createElement('button'));\n button.classList = 'mpl-widget';\n button.setAttribute('role', 'button');\n button.setAttribute('aria-disabled', 'false');\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n var icon_img = document.createElement('img');\n icon_img.src = '_images/' + image + '.png';\n icon_img.srcset = '_images/' + image + '_large.png 2x';\n icon_img.alt = tooltip;\n button.appendChild(icon_img);\n\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n var fmt_picker = document.createElement('select');\n fmt_picker.classList = 'mpl-widget';\n toolbar.appendChild(fmt_picker);\n this.format_dropdown = fmt_picker;\n\n for (var ind in mpl.extensions) {\n var fmt = mpl.extensions[ind];\n var option = document.createElement('option');\n option.selected = fmt === mpl.default_extension;\n option.innerHTML = fmt;\n fmt_picker.appendChild(option);\n }\n\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n // which will in turn request a refresh of the image.\n this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n properties['type'] = type;\n properties['figure_id'] = this.id;\n this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n if (!this.waiting) {\n this.waiting = true;\n this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n var format_dropdown = fig.format_dropdown;\n var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n var size = msg['size'];\n if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n fig._resize_canvas(size[0], size[1], msg['forward']);\n fig.send_message('refresh', {});\n }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n var x0 = msg['x0'] / fig.ratio;\n var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n var x1 = msg['x1'] / fig.ratio;\n var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n x0 = Math.floor(x0) + 0.5;\n y0 = Math.floor(y0) + 0.5;\n x1 = Math.floor(x1) + 0.5;\n y1 = Math.floor(y1) + 0.5;\n var min_x = Math.min(x0, x1);\n var min_y = Math.min(y0, y1);\n var width = Math.abs(x1 - x0);\n var height = Math.abs(y1 - y0);\n\n fig.rubberband_context.clearRect(\n 0,\n 0,\n fig.canvas.width / fig.ratio,\n fig.canvas.height / fig.ratio\n );\n\n fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n // Updates the figure title.\n fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n var cursor = msg['cursor'];\n switch (cursor) {\n case 0:\n cursor = 'pointer';\n break;\n case 1:\n cursor = 'default';\n break;\n case 2:\n cursor = 'crosshair';\n break;\n case 3:\n cursor = 'move';\n break;\n }\n fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n // Request the server to send over a new figure.\n fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n for (var key in msg) {\n if (!(key in fig.buttons)) {\n continue;\n }\n fig.buttons[key].disabled = !msg[key];\n fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n if (msg['mode'] === 'PAN') {\n fig.buttons['Pan'].classList.add('active');\n fig.buttons['Zoom'].classList.remove('active');\n } else if (msg['mode'] === 'ZOOM') {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.add('active');\n } else {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.remove('active');\n }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Called whenever the canvas gets updated.\n this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n return function socket_on_message(evt) {\n if (evt.data instanceof Blob) {\n /* FIXME: We get \"Resource interpreted as Image but\n * transferred with MIME type text/plain:\" errors on\n * Chrome. But how to set the MIME type? It doesn't seem\n * to be part of the websocket stream */\n evt.data.type = 'image/png';\n\n /* Free the memory for the previous frames */\n if (fig.imageObj.src) {\n (window.URL || window.webkitURL).revokeObjectURL(\n fig.imageObj.src\n );\n }\n\n fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n evt.data\n );\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n } else if (\n typeof evt.data === 'string' &&\n evt.data.slice(0, 21) === 'data:image/png;base64'\n ) {\n fig.imageObj.src = evt.data;\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n }\n\n var msg = JSON.parse(evt.data);\n var msg_type = msg['type'];\n\n // Call the \"handle_{type}\" callback, which takes\n // the figure and JSON message as its only arguments.\n try {\n var callback = fig['handle_' + msg_type];\n } catch (e) {\n console.log(\n \"No handler for the '\" + msg_type + \"' message type: \",\n msg\n );\n return;\n }\n\n if (callback) {\n try {\n // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n callback(fig, msg);\n } catch (e) {\n console.log(\n \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n e,\n e.stack,\n msg\n );\n }\n }\n };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n //this section is from http://www.quirksmode.org/js/events_properties.html\n var targ;\n if (!e) {\n e = window.event;\n }\n if (e.target) {\n targ = e.target;\n } else if (e.srcElement) {\n targ = e.srcElement;\n }\n if (targ.nodeType === 3) {\n // defeat Safari bug\n targ = targ.parentNode;\n }\n\n // pageX,Y are the mouse positions relative to the document\n var boundingRect = targ.getBoundingClientRect();\n var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n return Object.keys(original).reduce(function (obj, key) {\n if (typeof original[key] !== 'object') {\n obj[key] = original[key];\n }\n return obj;\n }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n var canvas_pos = mpl.findpos(event);\n\n if (name === 'button_press') {\n this.canvas.focus();\n this.canvas_div.focus();\n }\n\n var x = canvas_pos.x * this.ratio;\n var y = canvas_pos.y * this.ratio;\n\n this.send_message(name, {\n x: x,\n y: y,\n button: event.button,\n step: event.step,\n guiEvent: simpleKeys(event),\n });\n\n /* This prevents the web browser from automatically changing to\n * the text insertion cursor when the button is pressed. We want\n * to control all of the cursor setting manually through the\n * 'cursor' event from matplotlib */\n event.preventDefault();\n return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n // Prevent repeat events\n if (name === 'key_press') {\n if (event.which === this._key) {\n return;\n } else {\n this._key = event.which;\n }\n }\n if (name === 'key_release') {\n this._key = null;\n }\n\n var value = '';\n if (event.ctrlKey && event.which !== 17) {\n value += 'ctrl+';\n }\n if (event.altKey && event.which !== 18) {\n value += 'alt+';\n }\n if (event.shiftKey && event.which !== 16) {\n value += 'shift+';\n }\n\n value += 'k';\n value += event.which.toString();\n\n this._key_event_extra(event, name);\n\n this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n if (name === 'download') {\n this.handle_save(this, null);\n } else {\n this.send_message('toolbar_button', { name: name });\n }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\nmpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n\nmpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n // Create a \"websocket\"-like object which calls the given IPython comm\n // object with the appropriate methods. Currently this is a non binary\n // socket, so there is still some room for performance tuning.\n var ws = {};\n\n ws.close = function () {\n comm.close();\n };\n ws.send = function (m) {\n //console.log('sending', m);\n comm.send(m);\n };\n // Register the callback with on_msg.\n comm.on_msg(function (msg) {\n //console.log('receiving', msg['content']['data'], msg);\n // Pass the mpl event to the overridden (by mpl) onmessage function.\n ws.onmessage(msg['content']['data']);\n });\n return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n // This is the function which gets called when the mpl process\n // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n var id = msg.content.data.id;\n // Get hold of the div created by the display call when the Comm\n // socket was opened in Python.\n var element = document.getElementById(id);\n var ws_proxy = comm_websocket_adapter(comm);\n\n function ondownload(figure, _format) {\n window.open(figure.canvas.toDataURL());\n }\n\n var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n // web socket which is closed, not our websocket->open comm proxy.\n ws_proxy.onopen();\n\n fig.parent_element = element;\n fig.cell_info = mpl.find_output_cell(\"
\");\n if (!fig.cell_info) {\n console.error('Failed to find cell for figure', id, fig);\n return;\n }\n fig.cell_info[0].output_area.element.on(\n 'cleared',\n { fig: fig },\n fig._remove_fig_handler\n );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n var width = fig.canvas.width / fig.ratio;\n fig.cell_info[0].output_area.element.off(\n 'cleared',\n fig._remove_fig_handler\n );\n fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n // Update the output cell to use the data from the current canvas.\n fig.push_to_output();\n var dataURL = fig.canvas.toDataURL();\n // Re-enable the keyboard manager in IPython - without this line, in FF,\n // the notebook keyboard shortcuts fail.\n IPython.keyboard_manager.enable();\n fig.parent_element.innerHTML =\n '';\n fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n fig.send_message('closing', msg);\n // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n // Turn the data on the canvas into data in the output cell.\n var width = this.canvas.width / this.ratio;\n var dataURL = this.canvas.toDataURL();\n this.cell_info[1]['text/html'] =\n '';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Tell IPython that the notebook contents must change.\n IPython.notebook.set_dirty(true);\n this.send_message('ack', {});\n var fig = this;\n // Wait a second, then push the new image to the DOM so\n // that it is saved nicely (might be nice to debounce this).\n setTimeout(function () {\n fig.push_to_output();\n }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'btn-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n var button;\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n continue;\n }\n\n button = fig.buttons[name] = document.createElement('button');\n button.classList = 'btn btn-default';\n button.href = '#';\n button.title = name;\n button.innerHTML = '';\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n // Add the status bar.\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message pull-right';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n\n // Add the close button to the window.\n var buttongrp = document.createElement('div');\n buttongrp.classList = 'btn-group inline pull-right';\n button = document.createElement('button');\n button.classList = 'btn btn-mini btn-primary';\n button.href = '#';\n button.title = 'Stop Interaction';\n button.innerHTML = '';\n button.addEventListener('click', function (_evt) {\n fig.handle_close(fig, {});\n });\n button.addEventListener(\n 'mouseover',\n on_mouseover_closure('Stop Interaction')\n );\n buttongrp.appendChild(button);\n var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n var fig = event.data.fig;\n if (event.target !== this) {\n // Ignore bubbled events from children.\n return;\n }\n fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n // this is important to make the div 'focusable\n el.setAttribute('tabindex', 0);\n // reach out to IPython and tell the keyboard manager to turn it's self\n // off when our div gets focus\n\n // location in version 3\n if (IPython.notebook.keyboard_manager) {\n IPython.notebook.keyboard_manager.register_events(el);\n } else {\n // location in version 2\n IPython.keyboard_manager.register_events(el);\n }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n var manager = IPython.notebook.keyboard_manager;\n if (!manager) {\n manager = IPython.keyboard_manager;\n }\n\n // Check for shift+enter\n if (event.shiftKey && event.which === 13) {\n this.canvas_div.blur();\n // select the cell after this one\n var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n IPython.notebook.select(index + 1);\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n // Return the cell and output element which can be found *uniquely* in the notebook.\n // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n // IPython event is triggered only after the cells have been serialised, which for\n // our purposes (turning an active figure into a static one), is too late.\n var cells = IPython.notebook.get_cells();\n var ncells = cells.length;\n for (var i = 0; i < ncells; i++) {\n var cell = cells[i];\n if (cell.cell_type === 'code') {\n for (var j = 0; j < cell.output_area.outputs.length; j++) {\n var data = cell.output_area.outputs[j];\n if (data.data) {\n // IPython >= 3 moved mimebundle to data attribute of output\n data = data.data;\n }\n if (data['text/html'] === html_output) {\n return [cell, data, j];\n }\n }\n }\n }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n IPython.notebook.kernel.comm_manager.register_target(\n 'matplotlib',\n mpl.mpl_figure_comm\n );\n}\n", "text/plain": [ "" ] @@ -10540,955 +1060,7 @@ }, { "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "/* global mpl */\n", - "window.mpl = {};\n", - "\n", - "mpl.get_websocket_type = function () {\n", - " if (typeof WebSocket !== 'undefined') {\n", - " return WebSocket;\n", - " } else if (typeof MozWebSocket !== 'undefined') {\n", - " return MozWebSocket;\n", - " } else {\n", - " alert(\n", - " 'Your browser does not have WebSocket support. ' +\n", - " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", - " 'Firefox 4 and 5 are also supported but you ' +\n", - " 'have to enable WebSockets in about:config.'\n", - " );\n", - " }\n", - "};\n", - "\n", - "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", - " this.id = figure_id;\n", - "\n", - " this.ws = websocket;\n", - "\n", - " this.supports_binary = this.ws.binaryType !== undefined;\n", - "\n", - " if (!this.supports_binary) {\n", - " var warnings = document.getElementById('mpl-warnings');\n", - " if (warnings) {\n", - " warnings.style.display = 'block';\n", - " warnings.textContent =\n", - " 'This browser does not support binary websocket messages. ' +\n", - " 'Performance may be slow.';\n", - " }\n", - " }\n", - "\n", - " this.imageObj = new Image();\n", - "\n", - " this.context = undefined;\n", - " this.message = undefined;\n", - " this.canvas = undefined;\n", - " this.rubberband_canvas = undefined;\n", - " this.rubberband_context = undefined;\n", - " this.format_dropdown = undefined;\n", - "\n", - " this.image_mode = 'full';\n", - "\n", - " this.root = document.createElement('div');\n", - " this.root.setAttribute('style', 'display: inline-block');\n", - " this._root_extra_style(this.root);\n", - "\n", - " parent_element.appendChild(this.root);\n", - "\n", - " this._init_header(this);\n", - " this._init_canvas(this);\n", - " this._init_toolbar(this);\n", - "\n", - " var fig = this;\n", - "\n", - " this.waiting = false;\n", - "\n", - " this.ws.onopen = function () {\n", - " fig.send_message('supports_binary', { value: fig.supports_binary });\n", - " fig.send_message('send_image_mode', {});\n", - " if (fig.ratio !== 1) {\n", - " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", - " }\n", - " fig.send_message('refresh', {});\n", - " };\n", - "\n", - " this.imageObj.onload = function () {\n", - " if (fig.image_mode === 'full') {\n", - " // Full images could contain transparency (where diff images\n", - " // almost always do), so we need to clear the canvas so that\n", - " // there is no ghosting.\n", - " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", - " }\n", - " fig.context.drawImage(fig.imageObj, 0, 0);\n", - " };\n", - "\n", - " this.imageObj.onunload = function () {\n", - " fig.ws.close();\n", - " };\n", - "\n", - " this.ws.onmessage = this._make_on_message_function(this);\n", - "\n", - " this.ondownload = ondownload;\n", - "};\n", - "\n", - "mpl.figure.prototype._init_header = function () {\n", - " var titlebar = document.createElement('div');\n", - " titlebar.classList =\n", - " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", - " var titletext = document.createElement('div');\n", - " titletext.classList = 'ui-dialog-title';\n", - " titletext.setAttribute(\n", - " 'style',\n", - " 'width: 100%; text-align: center; padding: 3px;'\n", - " );\n", - " titlebar.appendChild(titletext);\n", - " this.root.appendChild(titlebar);\n", - " this.header = titletext;\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._init_canvas = function () {\n", - " var fig = this;\n", - "\n", - " var canvas_div = (this.canvas_div = document.createElement('div'));\n", - " canvas_div.setAttribute(\n", - " 'style',\n", - " 'border: 1px solid #ddd;' +\n", - " 'box-sizing: content-box;' +\n", - " 'clear: both;' +\n", - " 'min-height: 1px;' +\n", - " 'min-width: 1px;' +\n", - " 'outline: 0;' +\n", - " 'overflow: hidden;' +\n", - " 'position: relative;' +\n", - " 'resize: both;'\n", - " );\n", - "\n", - " function on_keyboard_event_closure(name) {\n", - " return function (event) {\n", - " return fig.key_event(event, name);\n", - " };\n", - " }\n", - "\n", - " canvas_div.addEventListener(\n", - " 'keydown',\n", - " on_keyboard_event_closure('key_press')\n", - " );\n", - " canvas_div.addEventListener(\n", - " 'keyup',\n", - " on_keyboard_event_closure('key_release')\n", - " );\n", - "\n", - " this._canvas_extra_style(canvas_div);\n", - " this.root.appendChild(canvas_div);\n", - "\n", - " var canvas = (this.canvas = document.createElement('canvas'));\n", - " canvas.classList.add('mpl-canvas');\n", - " canvas.setAttribute('style', 'box-sizing: content-box;');\n", - "\n", - " this.context = canvas.getContext('2d');\n", - "\n", - " var backingStore =\n", - " this.context.backingStorePixelRatio ||\n", - " this.context.webkitBackingStorePixelRatio ||\n", - " this.context.mozBackingStorePixelRatio ||\n", - " this.context.msBackingStorePixelRatio ||\n", - " this.context.oBackingStorePixelRatio ||\n", - " this.context.backingStorePixelRatio ||\n", - " 1;\n", - "\n", - " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", - "\n", - " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", - " 'canvas'\n", - " ));\n", - " rubberband_canvas.setAttribute(\n", - " 'style',\n", - " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", - " );\n", - "\n", - " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", - " if (this.ResizeObserver === undefined) {\n", - " if (window.ResizeObserver !== undefined) {\n", - " this.ResizeObserver = window.ResizeObserver;\n", - " } else {\n", - " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", - " this.ResizeObserver = obs.ResizeObserver;\n", - " }\n", - " }\n", - "\n", - " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", - " var nentries = entries.length;\n", - " for (var i = 0; i < nentries; i++) {\n", - " var entry = entries[i];\n", - " var width, height;\n", - " if (entry.contentBoxSize) {\n", - " if (entry.contentBoxSize instanceof Array) {\n", - " // Chrome 84 implements new version of spec.\n", - " width = entry.contentBoxSize[0].inlineSize;\n", - " height = entry.contentBoxSize[0].blockSize;\n", - " } else {\n", - " // Firefox implements old version of spec.\n", - " width = entry.contentBoxSize.inlineSize;\n", - " height = entry.contentBoxSize.blockSize;\n", - " }\n", - " } else {\n", - " // Chrome <84 implements even older version of spec.\n", - " width = entry.contentRect.width;\n", - " height = entry.contentRect.height;\n", - " }\n", - "\n", - " // Keep the size of the canvas and rubber band canvas in sync with\n", - " // the canvas container.\n", - " if (entry.devicePixelContentBoxSize) {\n", - " // Chrome 84 implements new version of spec.\n", - " canvas.setAttribute(\n", - " 'width',\n", - " entry.devicePixelContentBoxSize[0].inlineSize\n", - " );\n", - " canvas.setAttribute(\n", - " 'height',\n", - " entry.devicePixelContentBoxSize[0].blockSize\n", - " );\n", - " } else {\n", - " canvas.setAttribute('width', width * fig.ratio);\n", - " canvas.setAttribute('height', height * fig.ratio);\n", - " }\n", - " canvas.setAttribute(\n", - " 'style',\n", - " 'width: ' + width + 'px; height: ' + height + 'px;'\n", - " );\n", - "\n", - " rubberband_canvas.setAttribute('width', width);\n", - " rubberband_canvas.setAttribute('height', height);\n", - "\n", - " // And update the size in Python. We ignore the initial 0/0 size\n", - " // that occurs as the element is placed into the DOM, which should\n", - " // otherwise not happen due to the minimum size styling.\n", - " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", - " fig.request_resize(width, height);\n", - " }\n", - " }\n", - " });\n", - " this.resizeObserverInstance.observe(canvas_div);\n", - "\n", - " function on_mouse_event_closure(name) {\n", - " return function (event) {\n", - " return fig.mouse_event(event, name);\n", - " };\n", - " }\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mousedown',\n", - " on_mouse_event_closure('button_press')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseup',\n", - " on_mouse_event_closure('button_release')\n", - " );\n", - " // Throttle sequential mouse events to 1 every 20ms.\n", - " rubberband_canvas.addEventListener(\n", - " 'mousemove',\n", - " on_mouse_event_closure('motion_notify')\n", - " );\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseenter',\n", - " on_mouse_event_closure('figure_enter')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseleave',\n", - " on_mouse_event_closure('figure_leave')\n", - " );\n", - "\n", - " canvas_div.addEventListener('wheel', function (event) {\n", - " if (event.deltaY < 0) {\n", - " event.step = 1;\n", - " } else {\n", - " event.step = -1;\n", - " }\n", - " on_mouse_event_closure('scroll')(event);\n", - " });\n", - "\n", - " canvas_div.appendChild(canvas);\n", - " canvas_div.appendChild(rubberband_canvas);\n", - "\n", - " this.rubberband_context = rubberband_canvas.getContext('2d');\n", - " this.rubberband_context.strokeStyle = '#000000';\n", - "\n", - " this._resize_canvas = function (width, height, forward) {\n", - " if (forward) {\n", - " canvas_div.style.width = width + 'px';\n", - " canvas_div.style.height = height + 'px';\n", - " }\n", - " };\n", - "\n", - " // Disable right mouse context menu.\n", - " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", - " event.preventDefault();\n", - " return false;\n", - " });\n", - "\n", - " function set_focus() {\n", - " canvas.focus();\n", - " canvas_div.focus();\n", - " }\n", - "\n", - " window.setTimeout(set_focus, 100);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'mpl-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " continue;\n", - " }\n", - "\n", - " var button = (fig.buttons[name] = document.createElement('button'));\n", - " button.classList = 'mpl-widget';\n", - " button.setAttribute('role', 'button');\n", - " button.setAttribute('aria-disabled', 'false');\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - "\n", - " var icon_img = document.createElement('img');\n", - " icon_img.src = '_images/' + image + '.png';\n", - " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", - " icon_img.alt = tooltip;\n", - " button.appendChild(icon_img);\n", - "\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " var fmt_picker = document.createElement('select');\n", - " fmt_picker.classList = 'mpl-widget';\n", - " toolbar.appendChild(fmt_picker);\n", - " this.format_dropdown = fmt_picker;\n", - "\n", - " for (var ind in mpl.extensions) {\n", - " var fmt = mpl.extensions[ind];\n", - " var option = document.createElement('option');\n", - " option.selected = fmt === mpl.default_extension;\n", - " option.innerHTML = fmt;\n", - " fmt_picker.appendChild(option);\n", - " }\n", - "\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "};\n", - "\n", - "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", - " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", - " // which will in turn request a refresh of the image.\n", - " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", - "};\n", - "\n", - "mpl.figure.prototype.send_message = function (type, properties) {\n", - " properties['type'] = type;\n", - " properties['figure_id'] = this.id;\n", - " this.ws.send(JSON.stringify(properties));\n", - "};\n", - "\n", - "mpl.figure.prototype.send_draw_message = function () {\n", - " if (!this.waiting) {\n", - " this.waiting = true;\n", - " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " var format_dropdown = fig.format_dropdown;\n", - " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", - " fig.ondownload(fig, format);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", - " var size = msg['size'];\n", - " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", - " fig._resize_canvas(size[0], size[1], msg['forward']);\n", - " fig.send_message('refresh', {});\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", - " var x0 = msg['x0'] / fig.ratio;\n", - " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", - " var x1 = msg['x1'] / fig.ratio;\n", - " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", - " x0 = Math.floor(x0) + 0.5;\n", - " y0 = Math.floor(y0) + 0.5;\n", - " x1 = Math.floor(x1) + 0.5;\n", - " y1 = Math.floor(y1) + 0.5;\n", - " var min_x = Math.min(x0, x1);\n", - " var min_y = Math.min(y0, y1);\n", - " var width = Math.abs(x1 - x0);\n", - " var height = Math.abs(y1 - y0);\n", - "\n", - " fig.rubberband_context.clearRect(\n", - " 0,\n", - " 0,\n", - " fig.canvas.width / fig.ratio,\n", - " fig.canvas.height / fig.ratio\n", - " );\n", - "\n", - " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", - " // Updates the figure title.\n", - " fig.header.textContent = msg['label'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", - " var cursor = msg['cursor'];\n", - " switch (cursor) {\n", - " case 0:\n", - " cursor = 'pointer';\n", - " break;\n", - " case 1:\n", - " cursor = 'default';\n", - " break;\n", - " case 2:\n", - " cursor = 'crosshair';\n", - " break;\n", - " case 3:\n", - " cursor = 'move';\n", - " break;\n", - " }\n", - " fig.rubberband_canvas.style.cursor = cursor;\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_message = function (fig, msg) {\n", - " fig.message.textContent = msg['message'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", - " // Request the server to send over a new figure.\n", - " fig.send_draw_message();\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", - " fig.image_mode = msg['mode'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", - " for (var key in msg) {\n", - " if (!(key in fig.buttons)) {\n", - " continue;\n", - " }\n", - " fig.buttons[key].disabled = !msg[key];\n", - " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", - " if (msg['mode'] === 'PAN') {\n", - " fig.buttons['Pan'].classList.add('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " } else if (msg['mode'] === 'ZOOM') {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.add('active');\n", - " } else {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Called whenever the canvas gets updated.\n", - " this.send_message('ack', {});\n", - "};\n", - "\n", - "// A function to construct a web socket function for onmessage handling.\n", - "// Called in the figure constructor.\n", - "mpl.figure.prototype._make_on_message_function = function (fig) {\n", - " return function socket_on_message(evt) {\n", - " if (evt.data instanceof Blob) {\n", - " /* FIXME: We get \"Resource interpreted as Image but\n", - " * transferred with MIME type text/plain:\" errors on\n", - " * Chrome. But how to set the MIME type? It doesn't seem\n", - " * to be part of the websocket stream */\n", - " evt.data.type = 'image/png';\n", - "\n", - " /* Free the memory for the previous frames */\n", - " if (fig.imageObj.src) {\n", - " (window.URL || window.webkitURL).revokeObjectURL(\n", - " fig.imageObj.src\n", - " );\n", - " }\n", - "\n", - " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", - " evt.data\n", - " );\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " } else if (\n", - " typeof evt.data === 'string' &&\n", - " evt.data.slice(0, 21) === 'data:image/png;base64'\n", - " ) {\n", - " fig.imageObj.src = evt.data;\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " }\n", - "\n", - " var msg = JSON.parse(evt.data);\n", - " var msg_type = msg['type'];\n", - "\n", - " // Call the \"handle_{type}\" callback, which takes\n", - " // the figure and JSON message as its only arguments.\n", - " try {\n", - " var callback = fig['handle_' + msg_type];\n", - " } catch (e) {\n", - " console.log(\n", - " \"No handler for the '\" + msg_type + \"' message type: \",\n", - " msg\n", - " );\n", - " return;\n", - " }\n", - "\n", - " if (callback) {\n", - " try {\n", - " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", - " callback(fig, msg);\n", - " } catch (e) {\n", - " console.log(\n", - " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", - " e,\n", - " e.stack,\n", - " msg\n", - " );\n", - " }\n", - " }\n", - " };\n", - "};\n", - "\n", - "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", - "mpl.findpos = function (e) {\n", - " //this section is from http://www.quirksmode.org/js/events_properties.html\n", - " var targ;\n", - " if (!e) {\n", - " e = window.event;\n", - " }\n", - " if (e.target) {\n", - " targ = e.target;\n", - " } else if (e.srcElement) {\n", - " targ = e.srcElement;\n", - " }\n", - " if (targ.nodeType === 3) {\n", - " // defeat Safari bug\n", - " targ = targ.parentNode;\n", - " }\n", - "\n", - " // pageX,Y are the mouse positions relative to the document\n", - " var boundingRect = targ.getBoundingClientRect();\n", - " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", - " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", - "\n", - " return { x: x, y: y };\n", - "};\n", - "\n", - "/*\n", - " * return a copy of an object with only non-object keys\n", - " * we need this to avoid circular references\n", - " * http://stackoverflow.com/a/24161582/3208463\n", - " */\n", - "function simpleKeys(original) {\n", - " return Object.keys(original).reduce(function (obj, key) {\n", - " if (typeof original[key] !== 'object') {\n", - " obj[key] = original[key];\n", - " }\n", - " return obj;\n", - " }, {});\n", - "}\n", - "\n", - "mpl.figure.prototype.mouse_event = function (event, name) {\n", - " var canvas_pos = mpl.findpos(event);\n", - "\n", - " if (name === 'button_press') {\n", - " this.canvas.focus();\n", - " this.canvas_div.focus();\n", - " }\n", - "\n", - " var x = canvas_pos.x * this.ratio;\n", - " var y = canvas_pos.y * this.ratio;\n", - "\n", - " this.send_message(name, {\n", - " x: x,\n", - " y: y,\n", - " button: event.button,\n", - " step: event.step,\n", - " guiEvent: simpleKeys(event),\n", - " });\n", - "\n", - " /* This prevents the web browser from automatically changing to\n", - " * the text insertion cursor when the button is pressed. We want\n", - " * to control all of the cursor setting manually through the\n", - " * 'cursor' event from matplotlib */\n", - " event.preventDefault();\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", - " // Handle any extra behaviour associated with a key event\n", - "};\n", - "\n", - "mpl.figure.prototype.key_event = function (event, name) {\n", - " // Prevent repeat events\n", - " if (name === 'key_press') {\n", - " if (event.which === this._key) {\n", - " return;\n", - " } else {\n", - " this._key = event.which;\n", - " }\n", - " }\n", - " if (name === 'key_release') {\n", - " this._key = null;\n", - " }\n", - "\n", - " var value = '';\n", - " if (event.ctrlKey && event.which !== 17) {\n", - " value += 'ctrl+';\n", - " }\n", - " if (event.altKey && event.which !== 18) {\n", - " value += 'alt+';\n", - " }\n", - " if (event.shiftKey && event.which !== 16) {\n", - " value += 'shift+';\n", - " }\n", - "\n", - " value += 'k';\n", - " value += event.which.toString();\n", - "\n", - " this._key_event_extra(event, name);\n", - "\n", - " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", - " if (name === 'download') {\n", - " this.handle_save(this, null);\n", - " } else {\n", - " this.send_message('toolbar_button', { name: name });\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", - " this.message.textContent = tooltip;\n", - "};\n", - "\n", - "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", - "// prettier-ignore\n", - "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", - "\n", - "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", - "\n", - "mpl.default_extension = \"png\";/* global mpl */\n", - "\n", - "var comm_websocket_adapter = function (comm) {\n", - " // Create a \"websocket\"-like object which calls the given IPython comm\n", - " // object with the appropriate methods. Currently this is a non binary\n", - " // socket, so there is still some room for performance tuning.\n", - " var ws = {};\n", - "\n", - " ws.close = function () {\n", - " comm.close();\n", - " };\n", - " ws.send = function (m) {\n", - " //console.log('sending', m);\n", - " comm.send(m);\n", - " };\n", - " // Register the callback with on_msg.\n", - " comm.on_msg(function (msg) {\n", - " //console.log('receiving', msg['content']['data'], msg);\n", - " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", - " ws.onmessage(msg['content']['data']);\n", - " });\n", - " return ws;\n", - "};\n", - "\n", - "mpl.mpl_figure_comm = function (comm, msg) {\n", - " // This is the function which gets called when the mpl process\n", - " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", - "\n", - " var id = msg.content.data.id;\n", - " // Get hold of the div created by the display call when the Comm\n", - " // socket was opened in Python.\n", - " var element = document.getElementById(id);\n", - " var ws_proxy = comm_websocket_adapter(comm);\n", - "\n", - " function ondownload(figure, _format) {\n", - " window.open(figure.canvas.toDataURL());\n", - " }\n", - "\n", - " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", - "\n", - " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", - " // web socket which is closed, not our websocket->open comm proxy.\n", - " ws_proxy.onopen();\n", - "\n", - " fig.parent_element = element;\n", - " fig.cell_info = mpl.find_output_cell(\"
\");\n", - " if (!fig.cell_info) {\n", - " console.error('Failed to find cell for figure', id, fig);\n", - " return;\n", - " }\n", - " fig.cell_info[0].output_area.element.on(\n", - " 'cleared',\n", - " { fig: fig },\n", - " fig._remove_fig_handler\n", - " );\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_close = function (fig, msg) {\n", - " var width = fig.canvas.width / fig.ratio;\n", - " fig.cell_info[0].output_area.element.off(\n", - " 'cleared',\n", - " fig._remove_fig_handler\n", - " );\n", - " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", - "\n", - " // Update the output cell to use the data from the current canvas.\n", - " fig.push_to_output();\n", - " var dataURL = fig.canvas.toDataURL();\n", - " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", - " // the notebook keyboard shortcuts fail.\n", - " IPython.keyboard_manager.enable();\n", - " fig.parent_element.innerHTML =\n", - " '';\n", - " fig.close_ws(fig, msg);\n", - "};\n", - "\n", - "mpl.figure.prototype.close_ws = function (fig, msg) {\n", - " fig.send_message('closing', msg);\n", - " // fig.ws.close()\n", - "};\n", - "\n", - "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", - " // Turn the data on the canvas into data in the output cell.\n", - " var width = this.canvas.width / this.ratio;\n", - " var dataURL = this.canvas.toDataURL();\n", - " this.cell_info[1]['text/html'] =\n", - " '';\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Tell IPython that the notebook contents must change.\n", - " IPython.notebook.set_dirty(true);\n", - " this.send_message('ack', {});\n", - " var fig = this;\n", - " // Wait a second, then push the new image to the DOM so\n", - " // that it is saved nicely (might be nice to debounce this).\n", - " setTimeout(function () {\n", - " fig.push_to_output();\n", - " }, 1000);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'btn-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " var button;\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " continue;\n", - " }\n", - "\n", - " button = fig.buttons[name] = document.createElement('button');\n", - " button.classList = 'btn btn-default';\n", - " button.href = '#';\n", - " button.title = name;\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " // Add the status bar.\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message pull-right';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "\n", - " // Add the close button to the window.\n", - " var buttongrp = document.createElement('div');\n", - " buttongrp.classList = 'btn-group inline pull-right';\n", - " button = document.createElement('button');\n", - " button.classList = 'btn btn-mini btn-primary';\n", - " button.href = '#';\n", - " button.title = 'Stop Interaction';\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', function (_evt) {\n", - " fig.handle_close(fig, {});\n", - " });\n", - " button.addEventListener(\n", - " 'mouseover',\n", - " on_mouseover_closure('Stop Interaction')\n", - " );\n", - " buttongrp.appendChild(button);\n", - " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", - " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", - "};\n", - "\n", - "mpl.figure.prototype._remove_fig_handler = function (event) {\n", - " var fig = event.data.fig;\n", - " if (event.target !== this) {\n", - " // Ignore bubbled events from children.\n", - " return;\n", - " }\n", - " fig.close_ws(fig, {});\n", - "};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (el) {\n", - " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (el) {\n", - " // this is important to make the div 'focusable\n", - " el.setAttribute('tabindex', 0);\n", - " // reach out to IPython and tell the keyboard manager to turn it's self\n", - " // off when our div gets focus\n", - "\n", - " // location in version 3\n", - " if (IPython.notebook.keyboard_manager) {\n", - " IPython.notebook.keyboard_manager.register_events(el);\n", - " } else {\n", - " // location in version 2\n", - " IPython.keyboard_manager.register_events(el);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", - " var manager = IPython.notebook.keyboard_manager;\n", - " if (!manager) {\n", - " manager = IPython.keyboard_manager;\n", - " }\n", - "\n", - " // Check for shift+enter\n", - " if (event.shiftKey && event.which === 13) {\n", - " this.canvas_div.blur();\n", - " // select the cell after this one\n", - " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", - " IPython.notebook.select(index + 1);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " fig.ondownload(fig, null);\n", - "};\n", - "\n", - "mpl.find_output_cell = function (html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i = 0; i < ncells; i++) {\n", - " var cell = cells[i];\n", - " if (cell.cell_type === 'code') {\n", - " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", - " var data = cell.output_area.outputs[j];\n", - " if (data.data) {\n", - " // IPython >= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] === html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "};\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel !== null) {\n", - " IPython.notebook.kernel.comm_manager.register_target(\n", - " 'matplotlib',\n", - " mpl.mpl_figure_comm\n", - " );\n", - "}\n" - ], + "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n if (typeof WebSocket !== 'undefined') {\n return WebSocket;\n } else if (typeof MozWebSocket !== 'undefined') {\n return MozWebSocket;\n } else {\n alert(\n 'Your browser does not have WebSocket support. ' +\n 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n 'Firefox 4 and 5 are also supported but you ' +\n 'have to enable WebSockets in about:config.'\n );\n }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n this.id = figure_id;\n\n this.ws = websocket;\n\n this.supports_binary = this.ws.binaryType !== undefined;\n\n if (!this.supports_binary) {\n var warnings = document.getElementById('mpl-warnings');\n if (warnings) {\n warnings.style.display = 'block';\n warnings.textContent =\n 'This browser does not support binary websocket messages. ' +\n 'Performance may be slow.';\n }\n }\n\n this.imageObj = new Image();\n\n this.context = undefined;\n this.message = undefined;\n this.canvas = undefined;\n this.rubberband_canvas = undefined;\n this.rubberband_context = undefined;\n this.format_dropdown = undefined;\n\n this.image_mode = 'full';\n\n this.root = document.createElement('div');\n this.root.setAttribute('style', 'display: inline-block');\n this._root_extra_style(this.root);\n\n parent_element.appendChild(this.root);\n\n this._init_header(this);\n this._init_canvas(this);\n this._init_toolbar(this);\n\n var fig = this;\n\n this.waiting = false;\n\n this.ws.onopen = function () {\n fig.send_message('supports_binary', { value: fig.supports_binary });\n fig.send_message('send_image_mode', {});\n if (fig.ratio !== 1) {\n fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n }\n fig.send_message('refresh', {});\n };\n\n this.imageObj.onload = function () {\n if (fig.image_mode === 'full') {\n // Full images could contain transparency (where diff images\n // almost always do), so we need to clear the canvas so that\n // there is no ghosting.\n fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n }\n fig.context.drawImage(fig.imageObj, 0, 0);\n };\n\n this.imageObj.onunload = function () {\n fig.ws.close();\n };\n\n this.ws.onmessage = this._make_on_message_function(this);\n\n this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n var titlebar = document.createElement('div');\n titlebar.classList =\n 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n var titletext = document.createElement('div');\n titletext.classList = 'ui-dialog-title';\n titletext.setAttribute(\n 'style',\n 'width: 100%; text-align: center; padding: 3px;'\n );\n titlebar.appendChild(titletext);\n this.root.appendChild(titlebar);\n this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n var fig = this;\n\n var canvas_div = (this.canvas_div = document.createElement('div'));\n canvas_div.setAttribute(\n 'style',\n 'border: 1px solid #ddd;' +\n 'box-sizing: content-box;' +\n 'clear: both;' +\n 'min-height: 1px;' +\n 'min-width: 1px;' +\n 'outline: 0;' +\n 'overflow: hidden;' +\n 'position: relative;' +\n 'resize: both;'\n );\n\n function on_keyboard_event_closure(name) {\n return function (event) {\n return fig.key_event(event, name);\n };\n }\n\n canvas_div.addEventListener(\n 'keydown',\n on_keyboard_event_closure('key_press')\n );\n canvas_div.addEventListener(\n 'keyup',\n on_keyboard_event_closure('key_release')\n );\n\n this._canvas_extra_style(canvas_div);\n this.root.appendChild(canvas_div);\n\n var canvas = (this.canvas = document.createElement('canvas'));\n canvas.classList.add('mpl-canvas');\n canvas.setAttribute('style', 'box-sizing: content-box;');\n\n this.context = canvas.getContext('2d');\n\n var backingStore =\n this.context.backingStorePixelRatio ||\n this.context.webkitBackingStorePixelRatio ||\n this.context.mozBackingStorePixelRatio ||\n this.context.msBackingStorePixelRatio ||\n this.context.oBackingStorePixelRatio ||\n this.context.backingStorePixelRatio ||\n 1;\n\n this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n 'canvas'\n ));\n rubberband_canvas.setAttribute(\n 'style',\n 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n );\n\n // Apply a ponyfill if ResizeObserver is not implemented by browser.\n if (this.ResizeObserver === undefined) {\n if (window.ResizeObserver !== undefined) {\n this.ResizeObserver = window.ResizeObserver;\n } else {\n var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n this.ResizeObserver = obs.ResizeObserver;\n }\n }\n\n this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n var nentries = entries.length;\n for (var i = 0; i < nentries; i++) {\n var entry = entries[i];\n var width, height;\n if (entry.contentBoxSize) {\n if (entry.contentBoxSize instanceof Array) {\n // Chrome 84 implements new version of spec.\n width = entry.contentBoxSize[0].inlineSize;\n height = entry.contentBoxSize[0].blockSize;\n } else {\n // Firefox implements old version of spec.\n width = entry.contentBoxSize.inlineSize;\n height = entry.contentBoxSize.blockSize;\n }\n } else {\n // Chrome <84 implements even older version of spec.\n width = entry.contentRect.width;\n height = entry.contentRect.height;\n }\n\n // Keep the size of the canvas and rubber band canvas in sync with\n // the canvas container.\n if (entry.devicePixelContentBoxSize) {\n // Chrome 84 implements new version of spec.\n canvas.setAttribute(\n 'width',\n entry.devicePixelContentBoxSize[0].inlineSize\n );\n canvas.setAttribute(\n 'height',\n entry.devicePixelContentBoxSize[0].blockSize\n );\n } else {\n canvas.setAttribute('width', width * fig.ratio);\n canvas.setAttribute('height', height * fig.ratio);\n }\n canvas.setAttribute(\n 'style',\n 'width: ' + width + 'px; height: ' + height + 'px;'\n );\n\n rubberband_canvas.setAttribute('width', width);\n rubberband_canvas.setAttribute('height', height);\n\n // And update the size in Python. We ignore the initial 0/0 size\n // that occurs as the element is placed into the DOM, which should\n // otherwise not happen due to the minimum size styling.\n if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n fig.request_resize(width, height);\n }\n }\n });\n this.resizeObserverInstance.observe(canvas_div);\n\n function on_mouse_event_closure(name) {\n return function (event) {\n return fig.mouse_event(event, name);\n };\n }\n\n rubberband_canvas.addEventListener(\n 'mousedown',\n on_mouse_event_closure('button_press')\n );\n rubberband_canvas.addEventListener(\n 'mouseup',\n on_mouse_event_closure('button_release')\n );\n // Throttle sequential mouse events to 1 every 20ms.\n rubberband_canvas.addEventListener(\n 'mousemove',\n on_mouse_event_closure('motion_notify')\n );\n\n rubberband_canvas.addEventListener(\n 'mouseenter',\n on_mouse_event_closure('figure_enter')\n );\n rubberband_canvas.addEventListener(\n 'mouseleave',\n on_mouse_event_closure('figure_leave')\n );\n\n canvas_div.addEventListener('wheel', function (event) {\n if (event.deltaY < 0) {\n event.step = 1;\n } else {\n event.step = -1;\n }\n on_mouse_event_closure('scroll')(event);\n });\n\n canvas_div.appendChild(canvas);\n canvas_div.appendChild(rubberband_canvas);\n\n this.rubberband_context = rubberband_canvas.getContext('2d');\n this.rubberband_context.strokeStyle = '#000000';\n\n this._resize_canvas = function (width, height, forward) {\n if (forward) {\n canvas_div.style.width = width + 'px';\n canvas_div.style.height = height + 'px';\n }\n };\n\n // Disable right mouse context menu.\n this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n event.preventDefault();\n return false;\n });\n\n function set_focus() {\n canvas.focus();\n canvas_div.focus();\n }\n\n window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'mpl-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n continue;\n }\n\n var button = (fig.buttons[name] = document.createElement('button'));\n button.classList = 'mpl-widget';\n button.setAttribute('role', 'button');\n button.setAttribute('aria-disabled', 'false');\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n var icon_img = document.createElement('img');\n icon_img.src = '_images/' + image + '.png';\n icon_img.srcset = '_images/' + image + '_large.png 2x';\n icon_img.alt = tooltip;\n button.appendChild(icon_img);\n\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n var fmt_picker = document.createElement('select');\n fmt_picker.classList = 'mpl-widget';\n toolbar.appendChild(fmt_picker);\n this.format_dropdown = fmt_picker;\n\n for (var ind in mpl.extensions) {\n var fmt = mpl.extensions[ind];\n var option = document.createElement('option');\n option.selected = fmt === mpl.default_extension;\n option.innerHTML = fmt;\n fmt_picker.appendChild(option);\n }\n\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n // which will in turn request a refresh of the image.\n this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n properties['type'] = type;\n properties['figure_id'] = this.id;\n this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n if (!this.waiting) {\n this.waiting = true;\n this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n var format_dropdown = fig.format_dropdown;\n var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n var size = msg['size'];\n if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n fig._resize_canvas(size[0], size[1], msg['forward']);\n fig.send_message('refresh', {});\n }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n var x0 = msg['x0'] / fig.ratio;\n var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n var x1 = msg['x1'] / fig.ratio;\n var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n x0 = Math.floor(x0) + 0.5;\n y0 = Math.floor(y0) + 0.5;\n x1 = Math.floor(x1) + 0.5;\n y1 = Math.floor(y1) + 0.5;\n var min_x = Math.min(x0, x1);\n var min_y = Math.min(y0, y1);\n var width = Math.abs(x1 - x0);\n var height = Math.abs(y1 - y0);\n\n fig.rubberband_context.clearRect(\n 0,\n 0,\n fig.canvas.width / fig.ratio,\n fig.canvas.height / fig.ratio\n );\n\n fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n // Updates the figure title.\n fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n var cursor = msg['cursor'];\n switch (cursor) {\n case 0:\n cursor = 'pointer';\n break;\n case 1:\n cursor = 'default';\n break;\n case 2:\n cursor = 'crosshair';\n break;\n case 3:\n cursor = 'move';\n break;\n }\n fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n // Request the server to send over a new figure.\n fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n for (var key in msg) {\n if (!(key in fig.buttons)) {\n continue;\n }\n fig.buttons[key].disabled = !msg[key];\n fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n if (msg['mode'] === 'PAN') {\n fig.buttons['Pan'].classList.add('active');\n fig.buttons['Zoom'].classList.remove('active');\n } else if (msg['mode'] === 'ZOOM') {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.add('active');\n } else {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.remove('active');\n }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Called whenever the canvas gets updated.\n this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n return function socket_on_message(evt) {\n if (evt.data instanceof Blob) {\n /* FIXME: We get \"Resource interpreted as Image but\n * transferred with MIME type text/plain:\" errors on\n * Chrome. But how to set the MIME type? It doesn't seem\n * to be part of the websocket stream */\n evt.data.type = 'image/png';\n\n /* Free the memory for the previous frames */\n if (fig.imageObj.src) {\n (window.URL || window.webkitURL).revokeObjectURL(\n fig.imageObj.src\n );\n }\n\n fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n evt.data\n );\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n } else if (\n typeof evt.data === 'string' &&\n evt.data.slice(0, 21) === 'data:image/png;base64'\n ) {\n fig.imageObj.src = evt.data;\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n }\n\n var msg = JSON.parse(evt.data);\n var msg_type = msg['type'];\n\n // Call the \"handle_{type}\" callback, which takes\n // the figure and JSON message as its only arguments.\n try {\n var callback = fig['handle_' + msg_type];\n } catch (e) {\n console.log(\n \"No handler for the '\" + msg_type + \"' message type: \",\n msg\n );\n return;\n }\n\n if (callback) {\n try {\n // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n callback(fig, msg);\n } catch (e) {\n console.log(\n \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n e,\n e.stack,\n msg\n );\n }\n }\n };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n //this section is from http://www.quirksmode.org/js/events_properties.html\n var targ;\n if (!e) {\n e = window.event;\n }\n if (e.target) {\n targ = e.target;\n } else if (e.srcElement) {\n targ = e.srcElement;\n }\n if (targ.nodeType === 3) {\n // defeat Safari bug\n targ = targ.parentNode;\n }\n\n // pageX,Y are the mouse positions relative to the document\n var boundingRect = targ.getBoundingClientRect();\n var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n return Object.keys(original).reduce(function (obj, key) {\n if (typeof original[key] !== 'object') {\n obj[key] = original[key];\n }\n return obj;\n }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n var canvas_pos = mpl.findpos(event);\n\n if (name === 'button_press') {\n this.canvas.focus();\n this.canvas_div.focus();\n }\n\n var x = canvas_pos.x * this.ratio;\n var y = canvas_pos.y * this.ratio;\n\n this.send_message(name, {\n x: x,\n y: y,\n button: event.button,\n step: event.step,\n guiEvent: simpleKeys(event),\n });\n\n /* This prevents the web browser from automatically changing to\n * the text insertion cursor when the button is pressed. We want\n * to control all of the cursor setting manually through the\n * 'cursor' event from matplotlib */\n event.preventDefault();\n return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n // Prevent repeat events\n if (name === 'key_press') {\n if (event.which === this._key) {\n return;\n } else {\n this._key = event.which;\n }\n }\n if (name === 'key_release') {\n this._key = null;\n }\n\n var value = '';\n if (event.ctrlKey && event.which !== 17) {\n value += 'ctrl+';\n }\n if (event.altKey && event.which !== 18) {\n value += 'alt+';\n }\n if (event.shiftKey && event.which !== 16) {\n value += 'shift+';\n }\n\n value += 'k';\n value += event.which.toString();\n\n this._key_event_extra(event, name);\n\n this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n if (name === 'download') {\n this.handle_save(this, null);\n } else {\n this.send_message('toolbar_button', { name: name });\n }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\nmpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n\nmpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n // Create a \"websocket\"-like object which calls the given IPython comm\n // object with the appropriate methods. Currently this is a non binary\n // socket, so there is still some room for performance tuning.\n var ws = {};\n\n ws.close = function () {\n comm.close();\n };\n ws.send = function (m) {\n //console.log('sending', m);\n comm.send(m);\n };\n // Register the callback with on_msg.\n comm.on_msg(function (msg) {\n //console.log('receiving', msg['content']['data'], msg);\n // Pass the mpl event to the overridden (by mpl) onmessage function.\n ws.onmessage(msg['content']['data']);\n });\n return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n // This is the function which gets called when the mpl process\n // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n var id = msg.content.data.id;\n // Get hold of the div created by the display call when the Comm\n // socket was opened in Python.\n var element = document.getElementById(id);\n var ws_proxy = comm_websocket_adapter(comm);\n\n function ondownload(figure, _format) {\n window.open(figure.canvas.toDataURL());\n }\n\n var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n // web socket which is closed, not our websocket->open comm proxy.\n ws_proxy.onopen();\n\n fig.parent_element = element;\n fig.cell_info = mpl.find_output_cell(\"
\");\n if (!fig.cell_info) {\n console.error('Failed to find cell for figure', id, fig);\n return;\n }\n fig.cell_info[0].output_area.element.on(\n 'cleared',\n { fig: fig },\n fig._remove_fig_handler\n );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n var width = fig.canvas.width / fig.ratio;\n fig.cell_info[0].output_area.element.off(\n 'cleared',\n fig._remove_fig_handler\n );\n fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n // Update the output cell to use the data from the current canvas.\n fig.push_to_output();\n var dataURL = fig.canvas.toDataURL();\n // Re-enable the keyboard manager in IPython - without this line, in FF,\n // the notebook keyboard shortcuts fail.\n IPython.keyboard_manager.enable();\n fig.parent_element.innerHTML =\n '';\n fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n fig.send_message('closing', msg);\n // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n // Turn the data on the canvas into data in the output cell.\n var width = this.canvas.width / this.ratio;\n var dataURL = this.canvas.toDataURL();\n this.cell_info[1]['text/html'] =\n '';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Tell IPython that the notebook contents must change.\n IPython.notebook.set_dirty(true);\n this.send_message('ack', {});\n var fig = this;\n // Wait a second, then push the new image to the DOM so\n // that it is saved nicely (might be nice to debounce this).\n setTimeout(function () {\n fig.push_to_output();\n }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'btn-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n var button;\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n continue;\n }\n\n button = fig.buttons[name] = document.createElement('button');\n button.classList = 'btn btn-default';\n button.href = '#';\n button.title = name;\n button.innerHTML = '';\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n // Add the status bar.\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message pull-right';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n\n // Add the close button to the window.\n var buttongrp = document.createElement('div');\n buttongrp.classList = 'btn-group inline pull-right';\n button = document.createElement('button');\n button.classList = 'btn btn-mini btn-primary';\n button.href = '#';\n button.title = 'Stop Interaction';\n button.innerHTML = '';\n button.addEventListener('click', function (_evt) {\n fig.handle_close(fig, {});\n });\n button.addEventListener(\n 'mouseover',\n on_mouseover_closure('Stop Interaction')\n );\n buttongrp.appendChild(button);\n var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n var fig = event.data.fig;\n if (event.target !== this) {\n // Ignore bubbled events from children.\n return;\n }\n fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n // this is important to make the div 'focusable\n el.setAttribute('tabindex', 0);\n // reach out to IPython and tell the keyboard manager to turn it's self\n // off when our div gets focus\n\n // location in version 3\n if (IPython.notebook.keyboard_manager) {\n IPython.notebook.keyboard_manager.register_events(el);\n } else {\n // location in version 2\n IPython.keyboard_manager.register_events(el);\n }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n var manager = IPython.notebook.keyboard_manager;\n if (!manager) {\n manager = IPython.keyboard_manager;\n }\n\n // Check for shift+enter\n if (event.shiftKey && event.which === 13) {\n this.canvas_div.blur();\n // select the cell after this one\n var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n IPython.notebook.select(index + 1);\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n // Return the cell and output element which can be found *uniquely* in the notebook.\n // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n // IPython event is triggered only after the cells have been serialised, which for\n // our purposes (turning an active figure into a static one), is too late.\n var cells = IPython.notebook.get_cells();\n var ncells = cells.length;\n for (var i = 0; i < ncells; i++) {\n var cell = cells[i];\n if (cell.cell_type === 'code') {\n for (var j = 0; j < cell.output_area.outputs.length; j++) {\n var data = cell.output_area.outputs[j];\n if (data.data) {\n // IPython >= 3 moved mimebundle to data attribute of output\n data = data.data;\n }\n if (data['text/html'] === html_output) {\n return [cell, data, j];\n }\n }\n }\n }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n IPython.notebook.kernel.comm_manager.register_target(\n 'matplotlib',\n mpl.mpl_figure_comm\n );\n}\n", "text/plain": [ "" ] @@ -11510,955 +1082,7 @@ }, { "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "/* global mpl */\n", - "window.mpl = {};\n", - "\n", - "mpl.get_websocket_type = function () {\n", - " if (typeof WebSocket !== 'undefined') {\n", - " return WebSocket;\n", - " } else if (typeof MozWebSocket !== 'undefined') {\n", - " return MozWebSocket;\n", - " } else {\n", - " alert(\n", - " 'Your browser does not have WebSocket support. ' +\n", - " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", - " 'Firefox 4 and 5 are also supported but you ' +\n", - " 'have to enable WebSockets in about:config.'\n", - " );\n", - " }\n", - "};\n", - "\n", - "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", - " this.id = figure_id;\n", - "\n", - " this.ws = websocket;\n", - "\n", - " this.supports_binary = this.ws.binaryType !== undefined;\n", - "\n", - " if (!this.supports_binary) {\n", - " var warnings = document.getElementById('mpl-warnings');\n", - " if (warnings) {\n", - " warnings.style.display = 'block';\n", - " warnings.textContent =\n", - " 'This browser does not support binary websocket messages. ' +\n", - " 'Performance may be slow.';\n", - " }\n", - " }\n", - "\n", - " this.imageObj = new Image();\n", - "\n", - " this.context = undefined;\n", - " this.message = undefined;\n", - " this.canvas = undefined;\n", - " this.rubberband_canvas = undefined;\n", - " this.rubberband_context = undefined;\n", - " this.format_dropdown = undefined;\n", - "\n", - " this.image_mode = 'full';\n", - "\n", - " this.root = document.createElement('div');\n", - " this.root.setAttribute('style', 'display: inline-block');\n", - " this._root_extra_style(this.root);\n", - "\n", - " parent_element.appendChild(this.root);\n", - "\n", - " this._init_header(this);\n", - " this._init_canvas(this);\n", - " this._init_toolbar(this);\n", - "\n", - " var fig = this;\n", - "\n", - " this.waiting = false;\n", - "\n", - " this.ws.onopen = function () {\n", - " fig.send_message('supports_binary', { value: fig.supports_binary });\n", - " fig.send_message('send_image_mode', {});\n", - " if (fig.ratio !== 1) {\n", - " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", - " }\n", - " fig.send_message('refresh', {});\n", - " };\n", - "\n", - " this.imageObj.onload = function () {\n", - " if (fig.image_mode === 'full') {\n", - " // Full images could contain transparency (where diff images\n", - " // almost always do), so we need to clear the canvas so that\n", - " // there is no ghosting.\n", - " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", - " }\n", - " fig.context.drawImage(fig.imageObj, 0, 0);\n", - " };\n", - "\n", - " this.imageObj.onunload = function () {\n", - " fig.ws.close();\n", - " };\n", - "\n", - " this.ws.onmessage = this._make_on_message_function(this);\n", - "\n", - " this.ondownload = ondownload;\n", - "};\n", - "\n", - "mpl.figure.prototype._init_header = function () {\n", - " var titlebar = document.createElement('div');\n", - " titlebar.classList =\n", - " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", - " var titletext = document.createElement('div');\n", - " titletext.classList = 'ui-dialog-title';\n", - " titletext.setAttribute(\n", - " 'style',\n", - " 'width: 100%; text-align: center; padding: 3px;'\n", - " );\n", - " titlebar.appendChild(titletext);\n", - " this.root.appendChild(titlebar);\n", - " this.header = titletext;\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._init_canvas = function () {\n", - " var fig = this;\n", - "\n", - " var canvas_div = (this.canvas_div = document.createElement('div'));\n", - " canvas_div.setAttribute(\n", - " 'style',\n", - " 'border: 1px solid #ddd;' +\n", - " 'box-sizing: content-box;' +\n", - " 'clear: both;' +\n", - " 'min-height: 1px;' +\n", - " 'min-width: 1px;' +\n", - " 'outline: 0;' +\n", - " 'overflow: hidden;' +\n", - " 'position: relative;' +\n", - " 'resize: both;'\n", - " );\n", - "\n", - " function on_keyboard_event_closure(name) {\n", - " return function (event) {\n", - " return fig.key_event(event, name);\n", - " };\n", - " }\n", - "\n", - " canvas_div.addEventListener(\n", - " 'keydown',\n", - " on_keyboard_event_closure('key_press')\n", - " );\n", - " canvas_div.addEventListener(\n", - " 'keyup',\n", - " on_keyboard_event_closure('key_release')\n", - " );\n", - "\n", - " this._canvas_extra_style(canvas_div);\n", - " this.root.appendChild(canvas_div);\n", - "\n", - " var canvas = (this.canvas = document.createElement('canvas'));\n", - " canvas.classList.add('mpl-canvas');\n", - " canvas.setAttribute('style', 'box-sizing: content-box;');\n", - "\n", - " this.context = canvas.getContext('2d');\n", - "\n", - " var backingStore =\n", - " this.context.backingStorePixelRatio ||\n", - " this.context.webkitBackingStorePixelRatio ||\n", - " this.context.mozBackingStorePixelRatio ||\n", - " this.context.msBackingStorePixelRatio ||\n", - " this.context.oBackingStorePixelRatio ||\n", - " this.context.backingStorePixelRatio ||\n", - " 1;\n", - "\n", - " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", - "\n", - " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", - " 'canvas'\n", - " ));\n", - " rubberband_canvas.setAttribute(\n", - " 'style',\n", - " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", - " );\n", - "\n", - " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", - " if (this.ResizeObserver === undefined) {\n", - " if (window.ResizeObserver !== undefined) {\n", - " this.ResizeObserver = window.ResizeObserver;\n", - " } else {\n", - " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", - " this.ResizeObserver = obs.ResizeObserver;\n", - " }\n", - " }\n", - "\n", - " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", - " var nentries = entries.length;\n", - " for (var i = 0; i < nentries; i++) {\n", - " var entry = entries[i];\n", - " var width, height;\n", - " if (entry.contentBoxSize) {\n", - " if (entry.contentBoxSize instanceof Array) {\n", - " // Chrome 84 implements new version of spec.\n", - " width = entry.contentBoxSize[0].inlineSize;\n", - " height = entry.contentBoxSize[0].blockSize;\n", - " } else {\n", - " // Firefox implements old version of spec.\n", - " width = entry.contentBoxSize.inlineSize;\n", - " height = entry.contentBoxSize.blockSize;\n", - " }\n", - " } else {\n", - " // Chrome <84 implements even older version of spec.\n", - " width = entry.contentRect.width;\n", - " height = entry.contentRect.height;\n", - " }\n", - "\n", - " // Keep the size of the canvas and rubber band canvas in sync with\n", - " // the canvas container.\n", - " if (entry.devicePixelContentBoxSize) {\n", - " // Chrome 84 implements new version of spec.\n", - " canvas.setAttribute(\n", - " 'width',\n", - " entry.devicePixelContentBoxSize[0].inlineSize\n", - " );\n", - " canvas.setAttribute(\n", - " 'height',\n", - " entry.devicePixelContentBoxSize[0].blockSize\n", - " );\n", - " } else {\n", - " canvas.setAttribute('width', width * fig.ratio);\n", - " canvas.setAttribute('height', height * fig.ratio);\n", - " }\n", - " canvas.setAttribute(\n", - " 'style',\n", - " 'width: ' + width + 'px; height: ' + height + 'px;'\n", - " );\n", - "\n", - " rubberband_canvas.setAttribute('width', width);\n", - " rubberband_canvas.setAttribute('height', height);\n", - "\n", - " // And update the size in Python. We ignore the initial 0/0 size\n", - " // that occurs as the element is placed into the DOM, which should\n", - " // otherwise not happen due to the minimum size styling.\n", - " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", - " fig.request_resize(width, height);\n", - " }\n", - " }\n", - " });\n", - " this.resizeObserverInstance.observe(canvas_div);\n", - "\n", - " function on_mouse_event_closure(name) {\n", - " return function (event) {\n", - " return fig.mouse_event(event, name);\n", - " };\n", - " }\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mousedown',\n", - " on_mouse_event_closure('button_press')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseup',\n", - " on_mouse_event_closure('button_release')\n", - " );\n", - " // Throttle sequential mouse events to 1 every 20ms.\n", - " rubberband_canvas.addEventListener(\n", - " 'mousemove',\n", - " on_mouse_event_closure('motion_notify')\n", - " );\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseenter',\n", - " on_mouse_event_closure('figure_enter')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseleave',\n", - " on_mouse_event_closure('figure_leave')\n", - " );\n", - "\n", - " canvas_div.addEventListener('wheel', function (event) {\n", - " if (event.deltaY < 0) {\n", - " event.step = 1;\n", - " } else {\n", - " event.step = -1;\n", - " }\n", - " on_mouse_event_closure('scroll')(event);\n", - " });\n", - "\n", - " canvas_div.appendChild(canvas);\n", - " canvas_div.appendChild(rubberband_canvas);\n", - "\n", - " this.rubberband_context = rubberband_canvas.getContext('2d');\n", - " this.rubberband_context.strokeStyle = '#000000';\n", - "\n", - " this._resize_canvas = function (width, height, forward) {\n", - " if (forward) {\n", - " canvas_div.style.width = width + 'px';\n", - " canvas_div.style.height = height + 'px';\n", - " }\n", - " };\n", - "\n", - " // Disable right mouse context menu.\n", - " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", - " event.preventDefault();\n", - " return false;\n", - " });\n", - "\n", - " function set_focus() {\n", - " canvas.focus();\n", - " canvas_div.focus();\n", - " }\n", - "\n", - " window.setTimeout(set_focus, 100);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'mpl-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " continue;\n", - " }\n", - "\n", - " var button = (fig.buttons[name] = document.createElement('button'));\n", - " button.classList = 'mpl-widget';\n", - " button.setAttribute('role', 'button');\n", - " button.setAttribute('aria-disabled', 'false');\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - "\n", - " var icon_img = document.createElement('img');\n", - " icon_img.src = '_images/' + image + '.png';\n", - " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", - " icon_img.alt = tooltip;\n", - " button.appendChild(icon_img);\n", - "\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " var fmt_picker = document.createElement('select');\n", - " fmt_picker.classList = 'mpl-widget';\n", - " toolbar.appendChild(fmt_picker);\n", - " this.format_dropdown = fmt_picker;\n", - "\n", - " for (var ind in mpl.extensions) {\n", - " var fmt = mpl.extensions[ind];\n", - " var option = document.createElement('option');\n", - " option.selected = fmt === mpl.default_extension;\n", - " option.innerHTML = fmt;\n", - " fmt_picker.appendChild(option);\n", - " }\n", - "\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "};\n", - "\n", - "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", - " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", - " // which will in turn request a refresh of the image.\n", - " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", - "};\n", - "\n", - "mpl.figure.prototype.send_message = function (type, properties) {\n", - " properties['type'] = type;\n", - " properties['figure_id'] = this.id;\n", - " this.ws.send(JSON.stringify(properties));\n", - "};\n", - "\n", - "mpl.figure.prototype.send_draw_message = function () {\n", - " if (!this.waiting) {\n", - " this.waiting = true;\n", - " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " var format_dropdown = fig.format_dropdown;\n", - " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", - " fig.ondownload(fig, format);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", - " var size = msg['size'];\n", - " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", - " fig._resize_canvas(size[0], size[1], msg['forward']);\n", - " fig.send_message('refresh', {});\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", - " var x0 = msg['x0'] / fig.ratio;\n", - " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", - " var x1 = msg['x1'] / fig.ratio;\n", - " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", - " x0 = Math.floor(x0) + 0.5;\n", - " y0 = Math.floor(y0) + 0.5;\n", - " x1 = Math.floor(x1) + 0.5;\n", - " y1 = Math.floor(y1) + 0.5;\n", - " var min_x = Math.min(x0, x1);\n", - " var min_y = Math.min(y0, y1);\n", - " var width = Math.abs(x1 - x0);\n", - " var height = Math.abs(y1 - y0);\n", - "\n", - " fig.rubberband_context.clearRect(\n", - " 0,\n", - " 0,\n", - " fig.canvas.width / fig.ratio,\n", - " fig.canvas.height / fig.ratio\n", - " );\n", - "\n", - " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", - " // Updates the figure title.\n", - " fig.header.textContent = msg['label'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", - " var cursor = msg['cursor'];\n", - " switch (cursor) {\n", - " case 0:\n", - " cursor = 'pointer';\n", - " break;\n", - " case 1:\n", - " cursor = 'default';\n", - " break;\n", - " case 2:\n", - " cursor = 'crosshair';\n", - " break;\n", - " case 3:\n", - " cursor = 'move';\n", - " break;\n", - " }\n", - " fig.rubberband_canvas.style.cursor = cursor;\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_message = function (fig, msg) {\n", - " fig.message.textContent = msg['message'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", - " // Request the server to send over a new figure.\n", - " fig.send_draw_message();\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", - " fig.image_mode = msg['mode'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", - " for (var key in msg) {\n", - " if (!(key in fig.buttons)) {\n", - " continue;\n", - " }\n", - " fig.buttons[key].disabled = !msg[key];\n", - " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", - " if (msg['mode'] === 'PAN') {\n", - " fig.buttons['Pan'].classList.add('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " } else if (msg['mode'] === 'ZOOM') {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.add('active');\n", - " } else {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Called whenever the canvas gets updated.\n", - " this.send_message('ack', {});\n", - "};\n", - "\n", - "// A function to construct a web socket function for onmessage handling.\n", - "// Called in the figure constructor.\n", - "mpl.figure.prototype._make_on_message_function = function (fig) {\n", - " return function socket_on_message(evt) {\n", - " if (evt.data instanceof Blob) {\n", - " /* FIXME: We get \"Resource interpreted as Image but\n", - " * transferred with MIME type text/plain:\" errors on\n", - " * Chrome. But how to set the MIME type? It doesn't seem\n", - " * to be part of the websocket stream */\n", - " evt.data.type = 'image/png';\n", - "\n", - " /* Free the memory for the previous frames */\n", - " if (fig.imageObj.src) {\n", - " (window.URL || window.webkitURL).revokeObjectURL(\n", - " fig.imageObj.src\n", - " );\n", - " }\n", - "\n", - " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", - " evt.data\n", - " );\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " } else if (\n", - " typeof evt.data === 'string' &&\n", - " evt.data.slice(0, 21) === 'data:image/png;base64'\n", - " ) {\n", - " fig.imageObj.src = evt.data;\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " }\n", - "\n", - " var msg = JSON.parse(evt.data);\n", - " var msg_type = msg['type'];\n", - "\n", - " // Call the \"handle_{type}\" callback, which takes\n", - " // the figure and JSON message as its only arguments.\n", - " try {\n", - " var callback = fig['handle_' + msg_type];\n", - " } catch (e) {\n", - " console.log(\n", - " \"No handler for the '\" + msg_type + \"' message type: \",\n", - " msg\n", - " );\n", - " return;\n", - " }\n", - "\n", - " if (callback) {\n", - " try {\n", - " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", - " callback(fig, msg);\n", - " } catch (e) {\n", - " console.log(\n", - " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", - " e,\n", - " e.stack,\n", - " msg\n", - " );\n", - " }\n", - " }\n", - " };\n", - "};\n", - "\n", - "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", - "mpl.findpos = function (e) {\n", - " //this section is from http://www.quirksmode.org/js/events_properties.html\n", - " var targ;\n", - " if (!e) {\n", - " e = window.event;\n", - " }\n", - " if (e.target) {\n", - " targ = e.target;\n", - " } else if (e.srcElement) {\n", - " targ = e.srcElement;\n", - " }\n", - " if (targ.nodeType === 3) {\n", - " // defeat Safari bug\n", - " targ = targ.parentNode;\n", - " }\n", - "\n", - " // pageX,Y are the mouse positions relative to the document\n", - " var boundingRect = targ.getBoundingClientRect();\n", - " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", - " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", - "\n", - " return { x: x, y: y };\n", - "};\n", - "\n", - "/*\n", - " * return a copy of an object with only non-object keys\n", - " * we need this to avoid circular references\n", - " * http://stackoverflow.com/a/24161582/3208463\n", - " */\n", - "function simpleKeys(original) {\n", - " return Object.keys(original).reduce(function (obj, key) {\n", - " if (typeof original[key] !== 'object') {\n", - " obj[key] = original[key];\n", - " }\n", - " return obj;\n", - " }, {});\n", - "}\n", - "\n", - "mpl.figure.prototype.mouse_event = function (event, name) {\n", - " var canvas_pos = mpl.findpos(event);\n", - "\n", - " if (name === 'button_press') {\n", - " this.canvas.focus();\n", - " this.canvas_div.focus();\n", - " }\n", - "\n", - " var x = canvas_pos.x * this.ratio;\n", - " var y = canvas_pos.y * this.ratio;\n", - "\n", - " this.send_message(name, {\n", - " x: x,\n", - " y: y,\n", - " button: event.button,\n", - " step: event.step,\n", - " guiEvent: simpleKeys(event),\n", - " });\n", - "\n", - " /* This prevents the web browser from automatically changing to\n", - " * the text insertion cursor when the button is pressed. We want\n", - " * to control all of the cursor setting manually through the\n", - " * 'cursor' event from matplotlib */\n", - " event.preventDefault();\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", - " // Handle any extra behaviour associated with a key event\n", - "};\n", - "\n", - "mpl.figure.prototype.key_event = function (event, name) {\n", - " // Prevent repeat events\n", - " if (name === 'key_press') {\n", - " if (event.which === this._key) {\n", - " return;\n", - " } else {\n", - " this._key = event.which;\n", - " }\n", - " }\n", - " if (name === 'key_release') {\n", - " this._key = null;\n", - " }\n", - "\n", - " var value = '';\n", - " if (event.ctrlKey && event.which !== 17) {\n", - " value += 'ctrl+';\n", - " }\n", - " if (event.altKey && event.which !== 18) {\n", - " value += 'alt+';\n", - " }\n", - " if (event.shiftKey && event.which !== 16) {\n", - " value += 'shift+';\n", - " }\n", - "\n", - " value += 'k';\n", - " value += event.which.toString();\n", - "\n", - " this._key_event_extra(event, name);\n", - "\n", - " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", - " if (name === 'download') {\n", - " this.handle_save(this, null);\n", - " } else {\n", - " this.send_message('toolbar_button', { name: name });\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", - " this.message.textContent = tooltip;\n", - "};\n", - "\n", - "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", - "// prettier-ignore\n", - "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", - "\n", - "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", - "\n", - "mpl.default_extension = \"png\";/* global mpl */\n", - "\n", - "var comm_websocket_adapter = function (comm) {\n", - " // Create a \"websocket\"-like object which calls the given IPython comm\n", - " // object with the appropriate methods. Currently this is a non binary\n", - " // socket, so there is still some room for performance tuning.\n", - " var ws = {};\n", - "\n", - " ws.close = function () {\n", - " comm.close();\n", - " };\n", - " ws.send = function (m) {\n", - " //console.log('sending', m);\n", - " comm.send(m);\n", - " };\n", - " // Register the callback with on_msg.\n", - " comm.on_msg(function (msg) {\n", - " //console.log('receiving', msg['content']['data'], msg);\n", - " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", - " ws.onmessage(msg['content']['data']);\n", - " });\n", - " return ws;\n", - "};\n", - "\n", - "mpl.mpl_figure_comm = function (comm, msg) {\n", - " // This is the function which gets called when the mpl process\n", - " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", - "\n", - " var id = msg.content.data.id;\n", - " // Get hold of the div created by the display call when the Comm\n", - " // socket was opened in Python.\n", - " var element = document.getElementById(id);\n", - " var ws_proxy = comm_websocket_adapter(comm);\n", - "\n", - " function ondownload(figure, _format) {\n", - " window.open(figure.canvas.toDataURL());\n", - " }\n", - "\n", - " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", - "\n", - " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", - " // web socket which is closed, not our websocket->open comm proxy.\n", - " ws_proxy.onopen();\n", - "\n", - " fig.parent_element = element;\n", - " fig.cell_info = mpl.find_output_cell(\"
\");\n", - " if (!fig.cell_info) {\n", - " console.error('Failed to find cell for figure', id, fig);\n", - " return;\n", - " }\n", - " fig.cell_info[0].output_area.element.on(\n", - " 'cleared',\n", - " { fig: fig },\n", - " fig._remove_fig_handler\n", - " );\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_close = function (fig, msg) {\n", - " var width = fig.canvas.width / fig.ratio;\n", - " fig.cell_info[0].output_area.element.off(\n", - " 'cleared',\n", - " fig._remove_fig_handler\n", - " );\n", - " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", - "\n", - " // Update the output cell to use the data from the current canvas.\n", - " fig.push_to_output();\n", - " var dataURL = fig.canvas.toDataURL();\n", - " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", - " // the notebook keyboard shortcuts fail.\n", - " IPython.keyboard_manager.enable();\n", - " fig.parent_element.innerHTML =\n", - " '';\n", - " fig.close_ws(fig, msg);\n", - "};\n", - "\n", - "mpl.figure.prototype.close_ws = function (fig, msg) {\n", - " fig.send_message('closing', msg);\n", - " // fig.ws.close()\n", - "};\n", - "\n", - "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", - " // Turn the data on the canvas into data in the output cell.\n", - " var width = this.canvas.width / this.ratio;\n", - " var dataURL = this.canvas.toDataURL();\n", - " this.cell_info[1]['text/html'] =\n", - " '';\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Tell IPython that the notebook contents must change.\n", - " IPython.notebook.set_dirty(true);\n", - " this.send_message('ack', {});\n", - " var fig = this;\n", - " // Wait a second, then push the new image to the DOM so\n", - " // that it is saved nicely (might be nice to debounce this).\n", - " setTimeout(function () {\n", - " fig.push_to_output();\n", - " }, 1000);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'btn-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " var button;\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " continue;\n", - " }\n", - "\n", - " button = fig.buttons[name] = document.createElement('button');\n", - " button.classList = 'btn btn-default';\n", - " button.href = '#';\n", - " button.title = name;\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " // Add the status bar.\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message pull-right';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "\n", - " // Add the close button to the window.\n", - " var buttongrp = document.createElement('div');\n", - " buttongrp.classList = 'btn-group inline pull-right';\n", - " button = document.createElement('button');\n", - " button.classList = 'btn btn-mini btn-primary';\n", - " button.href = '#';\n", - " button.title = 'Stop Interaction';\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', function (_evt) {\n", - " fig.handle_close(fig, {});\n", - " });\n", - " button.addEventListener(\n", - " 'mouseover',\n", - " on_mouseover_closure('Stop Interaction')\n", - " );\n", - " buttongrp.appendChild(button);\n", - " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", - " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", - "};\n", - "\n", - "mpl.figure.prototype._remove_fig_handler = function (event) {\n", - " var fig = event.data.fig;\n", - " if (event.target !== this) {\n", - " // Ignore bubbled events from children.\n", - " return;\n", - " }\n", - " fig.close_ws(fig, {});\n", - "};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (el) {\n", - " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (el) {\n", - " // this is important to make the div 'focusable\n", - " el.setAttribute('tabindex', 0);\n", - " // reach out to IPython and tell the keyboard manager to turn it's self\n", - " // off when our div gets focus\n", - "\n", - " // location in version 3\n", - " if (IPython.notebook.keyboard_manager) {\n", - " IPython.notebook.keyboard_manager.register_events(el);\n", - " } else {\n", - " // location in version 2\n", - " IPython.keyboard_manager.register_events(el);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", - " var manager = IPython.notebook.keyboard_manager;\n", - " if (!manager) {\n", - " manager = IPython.keyboard_manager;\n", - " }\n", - "\n", - " // Check for shift+enter\n", - " if (event.shiftKey && event.which === 13) {\n", - " this.canvas_div.blur();\n", - " // select the cell after this one\n", - " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", - " IPython.notebook.select(index + 1);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " fig.ondownload(fig, null);\n", - "};\n", - "\n", - "mpl.find_output_cell = function (html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i = 0; i < ncells; i++) {\n", - " var cell = cells[i];\n", - " if (cell.cell_type === 'code') {\n", - " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", - " var data = cell.output_area.outputs[j];\n", - " if (data.data) {\n", - " // IPython >= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] === html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "};\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel !== null) {\n", - " IPython.notebook.kernel.comm_manager.register_target(\n", - " 'matplotlib',\n", - " mpl.mpl_figure_comm\n", - " );\n", - "}\n" - ], + "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n if (typeof WebSocket !== 'undefined') {\n return WebSocket;\n } else if (typeof MozWebSocket !== 'undefined') {\n return MozWebSocket;\n } else {\n alert(\n 'Your browser does not have WebSocket support. ' +\n 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n 'Firefox 4 and 5 are also supported but you ' +\n 'have to enable WebSockets in about:config.'\n );\n }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n this.id = figure_id;\n\n this.ws = websocket;\n\n this.supports_binary = this.ws.binaryType !== undefined;\n\n if (!this.supports_binary) {\n var warnings = document.getElementById('mpl-warnings');\n if (warnings) {\n warnings.style.display = 'block';\n warnings.textContent =\n 'This browser does not support binary websocket messages. ' +\n 'Performance may be slow.';\n }\n }\n\n this.imageObj = new Image();\n\n this.context = undefined;\n this.message = undefined;\n this.canvas = undefined;\n this.rubberband_canvas = undefined;\n this.rubberband_context = undefined;\n this.format_dropdown = undefined;\n\n this.image_mode = 'full';\n\n this.root = document.createElement('div');\n this.root.setAttribute('style', 'display: inline-block');\n this._root_extra_style(this.root);\n\n parent_element.appendChild(this.root);\n\n this._init_header(this);\n this._init_canvas(this);\n this._init_toolbar(this);\n\n var fig = this;\n\n this.waiting = false;\n\n this.ws.onopen = function () {\n fig.send_message('supports_binary', { value: fig.supports_binary });\n fig.send_message('send_image_mode', {});\n if (fig.ratio !== 1) {\n fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n }\n fig.send_message('refresh', {});\n };\n\n this.imageObj.onload = function () {\n if (fig.image_mode === 'full') {\n // Full images could contain transparency (where diff images\n // almost always do), so we need to clear the canvas so that\n // there is no ghosting.\n fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n }\n fig.context.drawImage(fig.imageObj, 0, 0);\n };\n\n this.imageObj.onunload = function () {\n fig.ws.close();\n };\n\n this.ws.onmessage = this._make_on_message_function(this);\n\n this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n var titlebar = document.createElement('div');\n titlebar.classList =\n 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n var titletext = document.createElement('div');\n titletext.classList = 'ui-dialog-title';\n titletext.setAttribute(\n 'style',\n 'width: 100%; text-align: center; padding: 3px;'\n );\n titlebar.appendChild(titletext);\n this.root.appendChild(titlebar);\n this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n var fig = this;\n\n var canvas_div = (this.canvas_div = document.createElement('div'));\n canvas_div.setAttribute(\n 'style',\n 'border: 1px solid #ddd;' +\n 'box-sizing: content-box;' +\n 'clear: both;' +\n 'min-height: 1px;' +\n 'min-width: 1px;' +\n 'outline: 0;' +\n 'overflow: hidden;' +\n 'position: relative;' +\n 'resize: both;'\n );\n\n function on_keyboard_event_closure(name) {\n return function (event) {\n return fig.key_event(event, name);\n };\n }\n\n canvas_div.addEventListener(\n 'keydown',\n on_keyboard_event_closure('key_press')\n );\n canvas_div.addEventListener(\n 'keyup',\n on_keyboard_event_closure('key_release')\n );\n\n this._canvas_extra_style(canvas_div);\n this.root.appendChild(canvas_div);\n\n var canvas = (this.canvas = document.createElement('canvas'));\n canvas.classList.add('mpl-canvas');\n canvas.setAttribute('style', 'box-sizing: content-box;');\n\n this.context = canvas.getContext('2d');\n\n var backingStore =\n this.context.backingStorePixelRatio ||\n this.context.webkitBackingStorePixelRatio ||\n this.context.mozBackingStorePixelRatio ||\n this.context.msBackingStorePixelRatio ||\n this.context.oBackingStorePixelRatio ||\n this.context.backingStorePixelRatio ||\n 1;\n\n this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n 'canvas'\n ));\n rubberband_canvas.setAttribute(\n 'style',\n 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n );\n\n // Apply a ponyfill if ResizeObserver is not implemented by browser.\n if (this.ResizeObserver === undefined) {\n if (window.ResizeObserver !== undefined) {\n this.ResizeObserver = window.ResizeObserver;\n } else {\n var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n this.ResizeObserver = obs.ResizeObserver;\n }\n }\n\n this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n var nentries = entries.length;\n for (var i = 0; i < nentries; i++) {\n var entry = entries[i];\n var width, height;\n if (entry.contentBoxSize) {\n if (entry.contentBoxSize instanceof Array) {\n // Chrome 84 implements new version of spec.\n width = entry.contentBoxSize[0].inlineSize;\n height = entry.contentBoxSize[0].blockSize;\n } else {\n // Firefox implements old version of spec.\n width = entry.contentBoxSize.inlineSize;\n height = entry.contentBoxSize.blockSize;\n }\n } else {\n // Chrome <84 implements even older version of spec.\n width = entry.contentRect.width;\n height = entry.contentRect.height;\n }\n\n // Keep the size of the canvas and rubber band canvas in sync with\n // the canvas container.\n if (entry.devicePixelContentBoxSize) {\n // Chrome 84 implements new version of spec.\n canvas.setAttribute(\n 'width',\n entry.devicePixelContentBoxSize[0].inlineSize\n );\n canvas.setAttribute(\n 'height',\n entry.devicePixelContentBoxSize[0].blockSize\n );\n } else {\n canvas.setAttribute('width', width * fig.ratio);\n canvas.setAttribute('height', height * fig.ratio);\n }\n canvas.setAttribute(\n 'style',\n 'width: ' + width + 'px; height: ' + height + 'px;'\n );\n\n rubberband_canvas.setAttribute('width', width);\n rubberband_canvas.setAttribute('height', height);\n\n // And update the size in Python. We ignore the initial 0/0 size\n // that occurs as the element is placed into the DOM, which should\n // otherwise not happen due to the minimum size styling.\n if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n fig.request_resize(width, height);\n }\n }\n });\n this.resizeObserverInstance.observe(canvas_div);\n\n function on_mouse_event_closure(name) {\n return function (event) {\n return fig.mouse_event(event, name);\n };\n }\n\n rubberband_canvas.addEventListener(\n 'mousedown',\n on_mouse_event_closure('button_press')\n );\n rubberband_canvas.addEventListener(\n 'mouseup',\n on_mouse_event_closure('button_release')\n );\n // Throttle sequential mouse events to 1 every 20ms.\n rubberband_canvas.addEventListener(\n 'mousemove',\n on_mouse_event_closure('motion_notify')\n );\n\n rubberband_canvas.addEventListener(\n 'mouseenter',\n on_mouse_event_closure('figure_enter')\n );\n rubberband_canvas.addEventListener(\n 'mouseleave',\n on_mouse_event_closure('figure_leave')\n );\n\n canvas_div.addEventListener('wheel', function (event) {\n if (event.deltaY < 0) {\n event.step = 1;\n } else {\n event.step = -1;\n }\n on_mouse_event_closure('scroll')(event);\n });\n\n canvas_div.appendChild(canvas);\n canvas_div.appendChild(rubberband_canvas);\n\n this.rubberband_context = rubberband_canvas.getContext('2d');\n this.rubberband_context.strokeStyle = '#000000';\n\n this._resize_canvas = function (width, height, forward) {\n if (forward) {\n canvas_div.style.width = width + 'px';\n canvas_div.style.height = height + 'px';\n }\n };\n\n // Disable right mouse context menu.\n this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n event.preventDefault();\n return false;\n });\n\n function set_focus() {\n canvas.focus();\n canvas_div.focus();\n }\n\n window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'mpl-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n continue;\n }\n\n var button = (fig.buttons[name] = document.createElement('button'));\n button.classList = 'mpl-widget';\n button.setAttribute('role', 'button');\n button.setAttribute('aria-disabled', 'false');\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n var icon_img = document.createElement('img');\n icon_img.src = '_images/' + image + '.png';\n icon_img.srcset = '_images/' + image + '_large.png 2x';\n icon_img.alt = tooltip;\n button.appendChild(icon_img);\n\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n var fmt_picker = document.createElement('select');\n fmt_picker.classList = 'mpl-widget';\n toolbar.appendChild(fmt_picker);\n this.format_dropdown = fmt_picker;\n\n for (var ind in mpl.extensions) {\n var fmt = mpl.extensions[ind];\n var option = document.createElement('option');\n option.selected = fmt === mpl.default_extension;\n option.innerHTML = fmt;\n fmt_picker.appendChild(option);\n }\n\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n // which will in turn request a refresh of the image.\n this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n properties['type'] = type;\n properties['figure_id'] = this.id;\n this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n if (!this.waiting) {\n this.waiting = true;\n this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n var format_dropdown = fig.format_dropdown;\n var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n var size = msg['size'];\n if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n fig._resize_canvas(size[0], size[1], msg['forward']);\n fig.send_message('refresh', {});\n }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n var x0 = msg['x0'] / fig.ratio;\n var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n var x1 = msg['x1'] / fig.ratio;\n var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n x0 = Math.floor(x0) + 0.5;\n y0 = Math.floor(y0) + 0.5;\n x1 = Math.floor(x1) + 0.5;\n y1 = Math.floor(y1) + 0.5;\n var min_x = Math.min(x0, x1);\n var min_y = Math.min(y0, y1);\n var width = Math.abs(x1 - x0);\n var height = Math.abs(y1 - y0);\n\n fig.rubberband_context.clearRect(\n 0,\n 0,\n fig.canvas.width / fig.ratio,\n fig.canvas.height / fig.ratio\n );\n\n fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n // Updates the figure title.\n fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n var cursor = msg['cursor'];\n switch (cursor) {\n case 0:\n cursor = 'pointer';\n break;\n case 1:\n cursor = 'default';\n break;\n case 2:\n cursor = 'crosshair';\n break;\n case 3:\n cursor = 'move';\n break;\n }\n fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n // Request the server to send over a new figure.\n fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n for (var key in msg) {\n if (!(key in fig.buttons)) {\n continue;\n }\n fig.buttons[key].disabled = !msg[key];\n fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n if (msg['mode'] === 'PAN') {\n fig.buttons['Pan'].classList.add('active');\n fig.buttons['Zoom'].classList.remove('active');\n } else if (msg['mode'] === 'ZOOM') {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.add('active');\n } else {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.remove('active');\n }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Called whenever the canvas gets updated.\n this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n return function socket_on_message(evt) {\n if (evt.data instanceof Blob) {\n /* FIXME: We get \"Resource interpreted as Image but\n * transferred with MIME type text/plain:\" errors on\n * Chrome. But how to set the MIME type? It doesn't seem\n * to be part of the websocket stream */\n evt.data.type = 'image/png';\n\n /* Free the memory for the previous frames */\n if (fig.imageObj.src) {\n (window.URL || window.webkitURL).revokeObjectURL(\n fig.imageObj.src\n );\n }\n\n fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n evt.data\n );\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n } else if (\n typeof evt.data === 'string' &&\n evt.data.slice(0, 21) === 'data:image/png;base64'\n ) {\n fig.imageObj.src = evt.data;\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n }\n\n var msg = JSON.parse(evt.data);\n var msg_type = msg['type'];\n\n // Call the \"handle_{type}\" callback, which takes\n // the figure and JSON message as its only arguments.\n try {\n var callback = fig['handle_' + msg_type];\n } catch (e) {\n console.log(\n \"No handler for the '\" + msg_type + \"' message type: \",\n msg\n );\n return;\n }\n\n if (callback) {\n try {\n // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n callback(fig, msg);\n } catch (e) {\n console.log(\n \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n e,\n e.stack,\n msg\n );\n }\n }\n };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n //this section is from http://www.quirksmode.org/js/events_properties.html\n var targ;\n if (!e) {\n e = window.event;\n }\n if (e.target) {\n targ = e.target;\n } else if (e.srcElement) {\n targ = e.srcElement;\n }\n if (targ.nodeType === 3) {\n // defeat Safari bug\n targ = targ.parentNode;\n }\n\n // pageX,Y are the mouse positions relative to the document\n var boundingRect = targ.getBoundingClientRect();\n var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n return Object.keys(original).reduce(function (obj, key) {\n if (typeof original[key] !== 'object') {\n obj[key] = original[key];\n }\n return obj;\n }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n var canvas_pos = mpl.findpos(event);\n\n if (name === 'button_press') {\n this.canvas.focus();\n this.canvas_div.focus();\n }\n\n var x = canvas_pos.x * this.ratio;\n var y = canvas_pos.y * this.ratio;\n\n this.send_message(name, {\n x: x,\n y: y,\n button: event.button,\n step: event.step,\n guiEvent: simpleKeys(event),\n });\n\n /* This prevents the web browser from automatically changing to\n * the text insertion cursor when the button is pressed. We want\n * to control all of the cursor setting manually through the\n * 'cursor' event from matplotlib */\n event.preventDefault();\n return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n // Prevent repeat events\n if (name === 'key_press') {\n if (event.which === this._key) {\n return;\n } else {\n this._key = event.which;\n }\n }\n if (name === 'key_release') {\n this._key = null;\n }\n\n var value = '';\n if (event.ctrlKey && event.which !== 17) {\n value += 'ctrl+';\n }\n if (event.altKey && event.which !== 18) {\n value += 'alt+';\n }\n if (event.shiftKey && event.which !== 16) {\n value += 'shift+';\n }\n\n value += 'k';\n value += event.which.toString();\n\n this._key_event_extra(event, name);\n\n this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n if (name === 'download') {\n this.handle_save(this, null);\n } else {\n this.send_message('toolbar_button', { name: name });\n }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\nmpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n\nmpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n // Create a \"websocket\"-like object which calls the given IPython comm\n // object with the appropriate methods. Currently this is a non binary\n // socket, so there is still some room for performance tuning.\n var ws = {};\n\n ws.close = function () {\n comm.close();\n };\n ws.send = function (m) {\n //console.log('sending', m);\n comm.send(m);\n };\n // Register the callback with on_msg.\n comm.on_msg(function (msg) {\n //console.log('receiving', msg['content']['data'], msg);\n // Pass the mpl event to the overridden (by mpl) onmessage function.\n ws.onmessage(msg['content']['data']);\n });\n return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n // This is the function which gets called when the mpl process\n // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n var id = msg.content.data.id;\n // Get hold of the div created by the display call when the Comm\n // socket was opened in Python.\n var element = document.getElementById(id);\n var ws_proxy = comm_websocket_adapter(comm);\n\n function ondownload(figure, _format) {\n window.open(figure.canvas.toDataURL());\n }\n\n var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n // web socket which is closed, not our websocket->open comm proxy.\n ws_proxy.onopen();\n\n fig.parent_element = element;\n fig.cell_info = mpl.find_output_cell(\"
\");\n if (!fig.cell_info) {\n console.error('Failed to find cell for figure', id, fig);\n return;\n }\n fig.cell_info[0].output_area.element.on(\n 'cleared',\n { fig: fig },\n fig._remove_fig_handler\n );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n var width = fig.canvas.width / fig.ratio;\n fig.cell_info[0].output_area.element.off(\n 'cleared',\n fig._remove_fig_handler\n );\n fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n // Update the output cell to use the data from the current canvas.\n fig.push_to_output();\n var dataURL = fig.canvas.toDataURL();\n // Re-enable the keyboard manager in IPython - without this line, in FF,\n // the notebook keyboard shortcuts fail.\n IPython.keyboard_manager.enable();\n fig.parent_element.innerHTML =\n '';\n fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n fig.send_message('closing', msg);\n // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n // Turn the data on the canvas into data in the output cell.\n var width = this.canvas.width / this.ratio;\n var dataURL = this.canvas.toDataURL();\n this.cell_info[1]['text/html'] =\n '';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Tell IPython that the notebook contents must change.\n IPython.notebook.set_dirty(true);\n this.send_message('ack', {});\n var fig = this;\n // Wait a second, then push the new image to the DOM so\n // that it is saved nicely (might be nice to debounce this).\n setTimeout(function () {\n fig.push_to_output();\n }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'btn-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n var button;\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n continue;\n }\n\n button = fig.buttons[name] = document.createElement('button');\n button.classList = 'btn btn-default';\n button.href = '#';\n button.title = name;\n button.innerHTML = '';\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n // Add the status bar.\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message pull-right';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n\n // Add the close button to the window.\n var buttongrp = document.createElement('div');\n buttongrp.classList = 'btn-group inline pull-right';\n button = document.createElement('button');\n button.classList = 'btn btn-mini btn-primary';\n button.href = '#';\n button.title = 'Stop Interaction';\n button.innerHTML = '';\n button.addEventListener('click', function (_evt) {\n fig.handle_close(fig, {});\n });\n button.addEventListener(\n 'mouseover',\n on_mouseover_closure('Stop Interaction')\n );\n buttongrp.appendChild(button);\n var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n var fig = event.data.fig;\n if (event.target !== this) {\n // Ignore bubbled events from children.\n return;\n }\n fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n // this is important to make the div 'focusable\n el.setAttribute('tabindex', 0);\n // reach out to IPython and tell the keyboard manager to turn it's self\n // off when our div gets focus\n\n // location in version 3\n if (IPython.notebook.keyboard_manager) {\n IPython.notebook.keyboard_manager.register_events(el);\n } else {\n // location in version 2\n IPython.keyboard_manager.register_events(el);\n }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n var manager = IPython.notebook.keyboard_manager;\n if (!manager) {\n manager = IPython.keyboard_manager;\n }\n\n // Check for shift+enter\n if (event.shiftKey && event.which === 13) {\n this.canvas_div.blur();\n // select the cell after this one\n var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n IPython.notebook.select(index + 1);\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n // Return the cell and output element which can be found *uniquely* in the notebook.\n // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n // IPython event is triggered only after the cells have been serialised, which for\n // our purposes (turning an active figure into a static one), is too late.\n var cells = IPython.notebook.get_cells();\n var ncells = cells.length;\n for (var i = 0; i < ncells; i++) {\n var cell = cells[i];\n if (cell.cell_type === 'code') {\n for (var j = 0; j < cell.output_area.outputs.length; j++) {\n var data = cell.output_area.outputs[j];\n if (data.data) {\n // IPython >= 3 moved mimebundle to data attribute of output\n data = data.data;\n }\n if (data['text/html'] === html_output) {\n return [cell, data, j];\n }\n }\n }\n }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n IPython.notebook.kernel.comm_manager.register_target(\n 'matplotlib',\n mpl.mpl_figure_comm\n );\n}\n", "text/plain": [ "" ] @@ -12531,13 +1155,13 @@ "metadata": {}, "source": [ "The workflow of this simulation is the following:\n", - "- Pyleecan checks simu.var_simu => VarParam.run\n", - "- VarParam defines its reference simulation with simu.var_simu = simu.var_simu.var_simu\n", - "- VarParam run its referencece simulation, check simu.var_simu => VarLoadCurrent.run\n", - "- The reference simulation of VarParam is a VarLoadCurrent simulation that defines its own reference simulation with simu.var_simu = simu.var_simu.var_simu (which is None)\n", + "- Pyleecan checks simu.var_simu => VarParamSweep.run\n", + "- VarParamSweep defines its reference simulation with simu.var_simu = simu.var_simu.var_simu\n", + "- VarParamSweep run its referencece simulation, check simu.var_simu => VarLoadCurrent.run\n", + "- The reference simulation of VarParamSweep is a VarLoadCurrent simulation that defines its own reference simulation with simu.var_simu = simu.var_simu.var_simu (which is None)\n", "- When running the reference simulation of VarLoadCurrent, simu.var_simu is None so we run the models (this simulation is then exaclty simu_ref defined previously)\n", "- Pyleecan run the N_speed simulations of the VarLoadCurrent\n", - "- Pyleecan generates the N_sweep simulations of the VarParam which are VarLoadCurrent and run them all\n", + "- Pyleecan generates the N_sweep simulations of the VarParamSweep which are VarLoadCurrent and run them all\n", "- For each VarLoadCurrent simulation, a reference simulation is defined then the N_speed simulations\n", "\n", "So this simulation will run (1+N_sweep) * (1+N_speed) simulations. This is why it is important to make sure that the reference simulation is part of the N simulations to skip one computation on both sides.\n", @@ -12551,7 +1175,7 @@ "metadata": {}, "outputs": [], "source": [ - "# VarParam => All machine are different\n", + "# VarParamSweep => All machine are different\n", "multi_simu.var_simu.is_reuse_femm_file = False\n", "# VarLoadCurrent => All machines are the same\n", "multi_simu.var_simu.var_simu.is_reuse_femm_file = True" @@ -12587,7 +1211,7 @@ } ], "source": [ - "# VarParam\n", + "# VarParamSweep\n", "multi_simu.var_simu.is_keep_all_output = True\n", "multi_simu.var_simu.datakeeper_list = list() # reset datakeeper list\n", "multi_simu.var_simu.paramexplorer_list[0].N = 4\n", @@ -12814,7 +1438,7 @@ "The datakeeper of the VarLoadCurrent are the same as previously:\n", "**Variable Load Results: N0=2000 [rpm], Id=-135.4 [Arms], Iq=113.6 [Arms], I0=176.8 [A], Phi0=2.443 [], Tem_av_ref=353 [N.m], Tem_av=353.3 [N.m], Tem_rip_pp=73.53 [N.m], Tem_rip_norm=0.2081 [-]**\n", "\n", - "But the VarParam Datakeeper are now:\n", + "But the VarParamSweep Datakeeper are now:\n", "\n", "**Parameter Sweep Results: Max_Tem_av=345 [N.m], Max_Tem_rip_pp=90.72 [N.m], Max_Tem_rip_norm=0.3105 [-]**\n", "\n", @@ -12843,955 +1467,7 @@ }, { "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "/* global mpl */\n", - "window.mpl = {};\n", - "\n", - "mpl.get_websocket_type = function () {\n", - " if (typeof WebSocket !== 'undefined') {\n", - " return WebSocket;\n", - " } else if (typeof MozWebSocket !== 'undefined') {\n", - " return MozWebSocket;\n", - " } else {\n", - " alert(\n", - " 'Your browser does not have WebSocket support. ' +\n", - " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", - " 'Firefox 4 and 5 are also supported but you ' +\n", - " 'have to enable WebSockets in about:config.'\n", - " );\n", - " }\n", - "};\n", - "\n", - "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", - " this.id = figure_id;\n", - "\n", - " this.ws = websocket;\n", - "\n", - " this.supports_binary = this.ws.binaryType !== undefined;\n", - "\n", - " if (!this.supports_binary) {\n", - " var warnings = document.getElementById('mpl-warnings');\n", - " if (warnings) {\n", - " warnings.style.display = 'block';\n", - " warnings.textContent =\n", - " 'This browser does not support binary websocket messages. ' +\n", - " 'Performance may be slow.';\n", - " }\n", - " }\n", - "\n", - " this.imageObj = new Image();\n", - "\n", - " this.context = undefined;\n", - " this.message = undefined;\n", - " this.canvas = undefined;\n", - " this.rubberband_canvas = undefined;\n", - " this.rubberband_context = undefined;\n", - " this.format_dropdown = undefined;\n", - "\n", - " this.image_mode = 'full';\n", - "\n", - " this.root = document.createElement('div');\n", - " this.root.setAttribute('style', 'display: inline-block');\n", - " this._root_extra_style(this.root);\n", - "\n", - " parent_element.appendChild(this.root);\n", - "\n", - " this._init_header(this);\n", - " this._init_canvas(this);\n", - " this._init_toolbar(this);\n", - "\n", - " var fig = this;\n", - "\n", - " this.waiting = false;\n", - "\n", - " this.ws.onopen = function () {\n", - " fig.send_message('supports_binary', { value: fig.supports_binary });\n", - " fig.send_message('send_image_mode', {});\n", - " if (fig.ratio !== 1) {\n", - " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", - " }\n", - " fig.send_message('refresh', {});\n", - " };\n", - "\n", - " this.imageObj.onload = function () {\n", - " if (fig.image_mode === 'full') {\n", - " // Full images could contain transparency (where diff images\n", - " // almost always do), so we need to clear the canvas so that\n", - " // there is no ghosting.\n", - " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", - " }\n", - " fig.context.drawImage(fig.imageObj, 0, 0);\n", - " };\n", - "\n", - " this.imageObj.onunload = function () {\n", - " fig.ws.close();\n", - " };\n", - "\n", - " this.ws.onmessage = this._make_on_message_function(this);\n", - "\n", - " this.ondownload = ondownload;\n", - "};\n", - "\n", - "mpl.figure.prototype._init_header = function () {\n", - " var titlebar = document.createElement('div');\n", - " titlebar.classList =\n", - " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", - " var titletext = document.createElement('div');\n", - " titletext.classList = 'ui-dialog-title';\n", - " titletext.setAttribute(\n", - " 'style',\n", - " 'width: 100%; text-align: center; padding: 3px;'\n", - " );\n", - " titlebar.appendChild(titletext);\n", - " this.root.appendChild(titlebar);\n", - " this.header = titletext;\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._init_canvas = function () {\n", - " var fig = this;\n", - "\n", - " var canvas_div = (this.canvas_div = document.createElement('div'));\n", - " canvas_div.setAttribute(\n", - " 'style',\n", - " 'border: 1px solid #ddd;' +\n", - " 'box-sizing: content-box;' +\n", - " 'clear: both;' +\n", - " 'min-height: 1px;' +\n", - " 'min-width: 1px;' +\n", - " 'outline: 0;' +\n", - " 'overflow: hidden;' +\n", - " 'position: relative;' +\n", - " 'resize: both;'\n", - " );\n", - "\n", - " function on_keyboard_event_closure(name) {\n", - " return function (event) {\n", - " return fig.key_event(event, name);\n", - " };\n", - " }\n", - "\n", - " canvas_div.addEventListener(\n", - " 'keydown',\n", - " on_keyboard_event_closure('key_press')\n", - " );\n", - " canvas_div.addEventListener(\n", - " 'keyup',\n", - " on_keyboard_event_closure('key_release')\n", - " );\n", - "\n", - " this._canvas_extra_style(canvas_div);\n", - " this.root.appendChild(canvas_div);\n", - "\n", - " var canvas = (this.canvas = document.createElement('canvas'));\n", - " canvas.classList.add('mpl-canvas');\n", - " canvas.setAttribute('style', 'box-sizing: content-box;');\n", - "\n", - " this.context = canvas.getContext('2d');\n", - "\n", - " var backingStore =\n", - " this.context.backingStorePixelRatio ||\n", - " this.context.webkitBackingStorePixelRatio ||\n", - " this.context.mozBackingStorePixelRatio ||\n", - " this.context.msBackingStorePixelRatio ||\n", - " this.context.oBackingStorePixelRatio ||\n", - " this.context.backingStorePixelRatio ||\n", - " 1;\n", - "\n", - " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", - "\n", - " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", - " 'canvas'\n", - " ));\n", - " rubberband_canvas.setAttribute(\n", - " 'style',\n", - " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", - " );\n", - "\n", - " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", - " if (this.ResizeObserver === undefined) {\n", - " if (window.ResizeObserver !== undefined) {\n", - " this.ResizeObserver = window.ResizeObserver;\n", - " } else {\n", - " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", - " this.ResizeObserver = obs.ResizeObserver;\n", - " }\n", - " }\n", - "\n", - " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", - " var nentries = entries.length;\n", - " for (var i = 0; i < nentries; i++) {\n", - " var entry = entries[i];\n", - " var width, height;\n", - " if (entry.contentBoxSize) {\n", - " if (entry.contentBoxSize instanceof Array) {\n", - " // Chrome 84 implements new version of spec.\n", - " width = entry.contentBoxSize[0].inlineSize;\n", - " height = entry.contentBoxSize[0].blockSize;\n", - " } else {\n", - " // Firefox implements old version of spec.\n", - " width = entry.contentBoxSize.inlineSize;\n", - " height = entry.contentBoxSize.blockSize;\n", - " }\n", - " } else {\n", - " // Chrome <84 implements even older version of spec.\n", - " width = entry.contentRect.width;\n", - " height = entry.contentRect.height;\n", - " }\n", - "\n", - " // Keep the size of the canvas and rubber band canvas in sync with\n", - " // the canvas container.\n", - " if (entry.devicePixelContentBoxSize) {\n", - " // Chrome 84 implements new version of spec.\n", - " canvas.setAttribute(\n", - " 'width',\n", - " entry.devicePixelContentBoxSize[0].inlineSize\n", - " );\n", - " canvas.setAttribute(\n", - " 'height',\n", - " entry.devicePixelContentBoxSize[0].blockSize\n", - " );\n", - " } else {\n", - " canvas.setAttribute('width', width * fig.ratio);\n", - " canvas.setAttribute('height', height * fig.ratio);\n", - " }\n", - " canvas.setAttribute(\n", - " 'style',\n", - " 'width: ' + width + 'px; height: ' + height + 'px;'\n", - " );\n", - "\n", - " rubberband_canvas.setAttribute('width', width);\n", - " rubberband_canvas.setAttribute('height', height);\n", - "\n", - " // And update the size in Python. We ignore the initial 0/0 size\n", - " // that occurs as the element is placed into the DOM, which should\n", - " // otherwise not happen due to the minimum size styling.\n", - " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", - " fig.request_resize(width, height);\n", - " }\n", - " }\n", - " });\n", - " this.resizeObserverInstance.observe(canvas_div);\n", - "\n", - " function on_mouse_event_closure(name) {\n", - " return function (event) {\n", - " return fig.mouse_event(event, name);\n", - " };\n", - " }\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mousedown',\n", - " on_mouse_event_closure('button_press')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseup',\n", - " on_mouse_event_closure('button_release')\n", - " );\n", - " // Throttle sequential mouse events to 1 every 20ms.\n", - " rubberband_canvas.addEventListener(\n", - " 'mousemove',\n", - " on_mouse_event_closure('motion_notify')\n", - " );\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseenter',\n", - " on_mouse_event_closure('figure_enter')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseleave',\n", - " on_mouse_event_closure('figure_leave')\n", - " );\n", - "\n", - " canvas_div.addEventListener('wheel', function (event) {\n", - " if (event.deltaY < 0) {\n", - " event.step = 1;\n", - " } else {\n", - " event.step = -1;\n", - " }\n", - " on_mouse_event_closure('scroll')(event);\n", - " });\n", - "\n", - " canvas_div.appendChild(canvas);\n", - " canvas_div.appendChild(rubberband_canvas);\n", - "\n", - " this.rubberband_context = rubberband_canvas.getContext('2d');\n", - " this.rubberband_context.strokeStyle = '#000000';\n", - "\n", - " this._resize_canvas = function (width, height, forward) {\n", - " if (forward) {\n", - " canvas_div.style.width = width + 'px';\n", - " canvas_div.style.height = height + 'px';\n", - " }\n", - " };\n", - "\n", - " // Disable right mouse context menu.\n", - " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", - " event.preventDefault();\n", - " return false;\n", - " });\n", - "\n", - " function set_focus() {\n", - " canvas.focus();\n", - " canvas_div.focus();\n", - " }\n", - "\n", - " window.setTimeout(set_focus, 100);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'mpl-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " continue;\n", - " }\n", - "\n", - " var button = (fig.buttons[name] = document.createElement('button'));\n", - " button.classList = 'mpl-widget';\n", - " button.setAttribute('role', 'button');\n", - " button.setAttribute('aria-disabled', 'false');\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - "\n", - " var icon_img = document.createElement('img');\n", - " icon_img.src = '_images/' + image + '.png';\n", - " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", - " icon_img.alt = tooltip;\n", - " button.appendChild(icon_img);\n", - "\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " var fmt_picker = document.createElement('select');\n", - " fmt_picker.classList = 'mpl-widget';\n", - " toolbar.appendChild(fmt_picker);\n", - " this.format_dropdown = fmt_picker;\n", - "\n", - " for (var ind in mpl.extensions) {\n", - " var fmt = mpl.extensions[ind];\n", - " var option = document.createElement('option');\n", - " option.selected = fmt === mpl.default_extension;\n", - " option.innerHTML = fmt;\n", - " fmt_picker.appendChild(option);\n", - " }\n", - "\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "};\n", - "\n", - "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", - " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", - " // which will in turn request a refresh of the image.\n", - " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", - "};\n", - "\n", - "mpl.figure.prototype.send_message = function (type, properties) {\n", - " properties['type'] = type;\n", - " properties['figure_id'] = this.id;\n", - " this.ws.send(JSON.stringify(properties));\n", - "};\n", - "\n", - "mpl.figure.prototype.send_draw_message = function () {\n", - " if (!this.waiting) {\n", - " this.waiting = true;\n", - " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " var format_dropdown = fig.format_dropdown;\n", - " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", - " fig.ondownload(fig, format);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", - " var size = msg['size'];\n", - " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", - " fig._resize_canvas(size[0], size[1], msg['forward']);\n", - " fig.send_message('refresh', {});\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", - " var x0 = msg['x0'] / fig.ratio;\n", - " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", - " var x1 = msg['x1'] / fig.ratio;\n", - " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", - " x0 = Math.floor(x0) + 0.5;\n", - " y0 = Math.floor(y0) + 0.5;\n", - " x1 = Math.floor(x1) + 0.5;\n", - " y1 = Math.floor(y1) + 0.5;\n", - " var min_x = Math.min(x0, x1);\n", - " var min_y = Math.min(y0, y1);\n", - " var width = Math.abs(x1 - x0);\n", - " var height = Math.abs(y1 - y0);\n", - "\n", - " fig.rubberband_context.clearRect(\n", - " 0,\n", - " 0,\n", - " fig.canvas.width / fig.ratio,\n", - " fig.canvas.height / fig.ratio\n", - " );\n", - "\n", - " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", - " // Updates the figure title.\n", - " fig.header.textContent = msg['label'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", - " var cursor = msg['cursor'];\n", - " switch (cursor) {\n", - " case 0:\n", - " cursor = 'pointer';\n", - " break;\n", - " case 1:\n", - " cursor = 'default';\n", - " break;\n", - " case 2:\n", - " cursor = 'crosshair';\n", - " break;\n", - " case 3:\n", - " cursor = 'move';\n", - " break;\n", - " }\n", - " fig.rubberband_canvas.style.cursor = cursor;\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_message = function (fig, msg) {\n", - " fig.message.textContent = msg['message'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", - " // Request the server to send over a new figure.\n", - " fig.send_draw_message();\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", - " fig.image_mode = msg['mode'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", - " for (var key in msg) {\n", - " if (!(key in fig.buttons)) {\n", - " continue;\n", - " }\n", - " fig.buttons[key].disabled = !msg[key];\n", - " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", - " if (msg['mode'] === 'PAN') {\n", - " fig.buttons['Pan'].classList.add('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " } else if (msg['mode'] === 'ZOOM') {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.add('active');\n", - " } else {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Called whenever the canvas gets updated.\n", - " this.send_message('ack', {});\n", - "};\n", - "\n", - "// A function to construct a web socket function for onmessage handling.\n", - "// Called in the figure constructor.\n", - "mpl.figure.prototype._make_on_message_function = function (fig) {\n", - " return function socket_on_message(evt) {\n", - " if (evt.data instanceof Blob) {\n", - " /* FIXME: We get \"Resource interpreted as Image but\n", - " * transferred with MIME type text/plain:\" errors on\n", - " * Chrome. But how to set the MIME type? It doesn't seem\n", - " * to be part of the websocket stream */\n", - " evt.data.type = 'image/png';\n", - "\n", - " /* Free the memory for the previous frames */\n", - " if (fig.imageObj.src) {\n", - " (window.URL || window.webkitURL).revokeObjectURL(\n", - " fig.imageObj.src\n", - " );\n", - " }\n", - "\n", - " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", - " evt.data\n", - " );\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " } else if (\n", - " typeof evt.data === 'string' &&\n", - " evt.data.slice(0, 21) === 'data:image/png;base64'\n", - " ) {\n", - " fig.imageObj.src = evt.data;\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " }\n", - "\n", - " var msg = JSON.parse(evt.data);\n", - " var msg_type = msg['type'];\n", - "\n", - " // Call the \"handle_{type}\" callback, which takes\n", - " // the figure and JSON message as its only arguments.\n", - " try {\n", - " var callback = fig['handle_' + msg_type];\n", - " } catch (e) {\n", - " console.log(\n", - " \"No handler for the '\" + msg_type + \"' message type: \",\n", - " msg\n", - " );\n", - " return;\n", - " }\n", - "\n", - " if (callback) {\n", - " try {\n", - " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", - " callback(fig, msg);\n", - " } catch (e) {\n", - " console.log(\n", - " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", - " e,\n", - " e.stack,\n", - " msg\n", - " );\n", - " }\n", - " }\n", - " };\n", - "};\n", - "\n", - "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", - "mpl.findpos = function (e) {\n", - " //this section is from http://www.quirksmode.org/js/events_properties.html\n", - " var targ;\n", - " if (!e) {\n", - " e = window.event;\n", - " }\n", - " if (e.target) {\n", - " targ = e.target;\n", - " } else if (e.srcElement) {\n", - " targ = e.srcElement;\n", - " }\n", - " if (targ.nodeType === 3) {\n", - " // defeat Safari bug\n", - " targ = targ.parentNode;\n", - " }\n", - "\n", - " // pageX,Y are the mouse positions relative to the document\n", - " var boundingRect = targ.getBoundingClientRect();\n", - " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", - " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", - "\n", - " return { x: x, y: y };\n", - "};\n", - "\n", - "/*\n", - " * return a copy of an object with only non-object keys\n", - " * we need this to avoid circular references\n", - " * http://stackoverflow.com/a/24161582/3208463\n", - " */\n", - "function simpleKeys(original) {\n", - " return Object.keys(original).reduce(function (obj, key) {\n", - " if (typeof original[key] !== 'object') {\n", - " obj[key] = original[key];\n", - " }\n", - " return obj;\n", - " }, {});\n", - "}\n", - "\n", - "mpl.figure.prototype.mouse_event = function (event, name) {\n", - " var canvas_pos = mpl.findpos(event);\n", - "\n", - " if (name === 'button_press') {\n", - " this.canvas.focus();\n", - " this.canvas_div.focus();\n", - " }\n", - "\n", - " var x = canvas_pos.x * this.ratio;\n", - " var y = canvas_pos.y * this.ratio;\n", - "\n", - " this.send_message(name, {\n", - " x: x,\n", - " y: y,\n", - " button: event.button,\n", - " step: event.step,\n", - " guiEvent: simpleKeys(event),\n", - " });\n", - "\n", - " /* This prevents the web browser from automatically changing to\n", - " * the text insertion cursor when the button is pressed. We want\n", - " * to control all of the cursor setting manually through the\n", - " * 'cursor' event from matplotlib */\n", - " event.preventDefault();\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", - " // Handle any extra behaviour associated with a key event\n", - "};\n", - "\n", - "mpl.figure.prototype.key_event = function (event, name) {\n", - " // Prevent repeat events\n", - " if (name === 'key_press') {\n", - " if (event.which === this._key) {\n", - " return;\n", - " } else {\n", - " this._key = event.which;\n", - " }\n", - " }\n", - " if (name === 'key_release') {\n", - " this._key = null;\n", - " }\n", - "\n", - " var value = '';\n", - " if (event.ctrlKey && event.which !== 17) {\n", - " value += 'ctrl+';\n", - " }\n", - " if (event.altKey && event.which !== 18) {\n", - " value += 'alt+';\n", - " }\n", - " if (event.shiftKey && event.which !== 16) {\n", - " value += 'shift+';\n", - " }\n", - "\n", - " value += 'k';\n", - " value += event.which.toString();\n", - "\n", - " this._key_event_extra(event, name);\n", - "\n", - " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", - " if (name === 'download') {\n", - " this.handle_save(this, null);\n", - " } else {\n", - " this.send_message('toolbar_button', { name: name });\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", - " this.message.textContent = tooltip;\n", - "};\n", - "\n", - "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", - "// prettier-ignore\n", - "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", - "\n", - "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", - "\n", - "mpl.default_extension = \"png\";/* global mpl */\n", - "\n", - "var comm_websocket_adapter = function (comm) {\n", - " // Create a \"websocket\"-like object which calls the given IPython comm\n", - " // object with the appropriate methods. Currently this is a non binary\n", - " // socket, so there is still some room for performance tuning.\n", - " var ws = {};\n", - "\n", - " ws.close = function () {\n", - " comm.close();\n", - " };\n", - " ws.send = function (m) {\n", - " //console.log('sending', m);\n", - " comm.send(m);\n", - " };\n", - " // Register the callback with on_msg.\n", - " comm.on_msg(function (msg) {\n", - " //console.log('receiving', msg['content']['data'], msg);\n", - " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", - " ws.onmessage(msg['content']['data']);\n", - " });\n", - " return ws;\n", - "};\n", - "\n", - "mpl.mpl_figure_comm = function (comm, msg) {\n", - " // This is the function which gets called when the mpl process\n", - " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", - "\n", - " var id = msg.content.data.id;\n", - " // Get hold of the div created by the display call when the Comm\n", - " // socket was opened in Python.\n", - " var element = document.getElementById(id);\n", - " var ws_proxy = comm_websocket_adapter(comm);\n", - "\n", - " function ondownload(figure, _format) {\n", - " window.open(figure.canvas.toDataURL());\n", - " }\n", - "\n", - " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", - "\n", - " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", - " // web socket which is closed, not our websocket->open comm proxy.\n", - " ws_proxy.onopen();\n", - "\n", - " fig.parent_element = element;\n", - " fig.cell_info = mpl.find_output_cell(\"
\");\n", - " if (!fig.cell_info) {\n", - " console.error('Failed to find cell for figure', id, fig);\n", - " return;\n", - " }\n", - " fig.cell_info[0].output_area.element.on(\n", - " 'cleared',\n", - " { fig: fig },\n", - " fig._remove_fig_handler\n", - " );\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_close = function (fig, msg) {\n", - " var width = fig.canvas.width / fig.ratio;\n", - " fig.cell_info[0].output_area.element.off(\n", - " 'cleared',\n", - " fig._remove_fig_handler\n", - " );\n", - " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", - "\n", - " // Update the output cell to use the data from the current canvas.\n", - " fig.push_to_output();\n", - " var dataURL = fig.canvas.toDataURL();\n", - " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", - " // the notebook keyboard shortcuts fail.\n", - " IPython.keyboard_manager.enable();\n", - " fig.parent_element.innerHTML =\n", - " '';\n", - " fig.close_ws(fig, msg);\n", - "};\n", - "\n", - "mpl.figure.prototype.close_ws = function (fig, msg) {\n", - " fig.send_message('closing', msg);\n", - " // fig.ws.close()\n", - "};\n", - "\n", - "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", - " // Turn the data on the canvas into data in the output cell.\n", - " var width = this.canvas.width / this.ratio;\n", - " var dataURL = this.canvas.toDataURL();\n", - " this.cell_info[1]['text/html'] =\n", - " '';\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Tell IPython that the notebook contents must change.\n", - " IPython.notebook.set_dirty(true);\n", - " this.send_message('ack', {});\n", - " var fig = this;\n", - " // Wait a second, then push the new image to the DOM so\n", - " // that it is saved nicely (might be nice to debounce this).\n", - " setTimeout(function () {\n", - " fig.push_to_output();\n", - " }, 1000);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'btn-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " var button;\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " continue;\n", - " }\n", - "\n", - " button = fig.buttons[name] = document.createElement('button');\n", - " button.classList = 'btn btn-default';\n", - " button.href = '#';\n", - " button.title = name;\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " // Add the status bar.\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message pull-right';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "\n", - " // Add the close button to the window.\n", - " var buttongrp = document.createElement('div');\n", - " buttongrp.classList = 'btn-group inline pull-right';\n", - " button = document.createElement('button');\n", - " button.classList = 'btn btn-mini btn-primary';\n", - " button.href = '#';\n", - " button.title = 'Stop Interaction';\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', function (_evt) {\n", - " fig.handle_close(fig, {});\n", - " });\n", - " button.addEventListener(\n", - " 'mouseover',\n", - " on_mouseover_closure('Stop Interaction')\n", - " );\n", - " buttongrp.appendChild(button);\n", - " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", - " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", - "};\n", - "\n", - "mpl.figure.prototype._remove_fig_handler = function (event) {\n", - " var fig = event.data.fig;\n", - " if (event.target !== this) {\n", - " // Ignore bubbled events from children.\n", - " return;\n", - " }\n", - " fig.close_ws(fig, {});\n", - "};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (el) {\n", - " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (el) {\n", - " // this is important to make the div 'focusable\n", - " el.setAttribute('tabindex', 0);\n", - " // reach out to IPython and tell the keyboard manager to turn it's self\n", - " // off when our div gets focus\n", - "\n", - " // location in version 3\n", - " if (IPython.notebook.keyboard_manager) {\n", - " IPython.notebook.keyboard_manager.register_events(el);\n", - " } else {\n", - " // location in version 2\n", - " IPython.keyboard_manager.register_events(el);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", - " var manager = IPython.notebook.keyboard_manager;\n", - " if (!manager) {\n", - " manager = IPython.keyboard_manager;\n", - " }\n", - "\n", - " // Check for shift+enter\n", - " if (event.shiftKey && event.which === 13) {\n", - " this.canvas_div.blur();\n", - " // select the cell after this one\n", - " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", - " IPython.notebook.select(index + 1);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " fig.ondownload(fig, null);\n", - "};\n", - "\n", - "mpl.find_output_cell = function (html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i = 0; i < ncells; i++) {\n", - " var cell = cells[i];\n", - " if (cell.cell_type === 'code') {\n", - " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", - " var data = cell.output_area.outputs[j];\n", - " if (data.data) {\n", - " // IPython >= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] === html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "};\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel !== null) {\n", - " IPython.notebook.kernel.comm_manager.register_target(\n", - " 'matplotlib',\n", - " mpl.mpl_figure_comm\n", - " );\n", - "}\n" - ], + "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n if (typeof WebSocket !== 'undefined') {\n return WebSocket;\n } else if (typeof MozWebSocket !== 'undefined') {\n return MozWebSocket;\n } else {\n alert(\n 'Your browser does not have WebSocket support. ' +\n 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n 'Firefox 4 and 5 are also supported but you ' +\n 'have to enable WebSockets in about:config.'\n );\n }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n this.id = figure_id;\n\n this.ws = websocket;\n\n this.supports_binary = this.ws.binaryType !== undefined;\n\n if (!this.supports_binary) {\n var warnings = document.getElementById('mpl-warnings');\n if (warnings) {\n warnings.style.display = 'block';\n warnings.textContent =\n 'This browser does not support binary websocket messages. ' +\n 'Performance may be slow.';\n }\n }\n\n this.imageObj = new Image();\n\n this.context = undefined;\n this.message = undefined;\n this.canvas = undefined;\n this.rubberband_canvas = undefined;\n this.rubberband_context = undefined;\n this.format_dropdown = undefined;\n\n this.image_mode = 'full';\n\n this.root = document.createElement('div');\n this.root.setAttribute('style', 'display: inline-block');\n this._root_extra_style(this.root);\n\n parent_element.appendChild(this.root);\n\n this._init_header(this);\n this._init_canvas(this);\n this._init_toolbar(this);\n\n var fig = this;\n\n this.waiting = false;\n\n this.ws.onopen = function () {\n fig.send_message('supports_binary', { value: fig.supports_binary });\n fig.send_message('send_image_mode', {});\n if (fig.ratio !== 1) {\n fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n }\n fig.send_message('refresh', {});\n };\n\n this.imageObj.onload = function () {\n if (fig.image_mode === 'full') {\n // Full images could contain transparency (where diff images\n // almost always do), so we need to clear the canvas so that\n // there is no ghosting.\n fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n }\n fig.context.drawImage(fig.imageObj, 0, 0);\n };\n\n this.imageObj.onunload = function () {\n fig.ws.close();\n };\n\n this.ws.onmessage = this._make_on_message_function(this);\n\n this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n var titlebar = document.createElement('div');\n titlebar.classList =\n 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n var titletext = document.createElement('div');\n titletext.classList = 'ui-dialog-title';\n titletext.setAttribute(\n 'style',\n 'width: 100%; text-align: center; padding: 3px;'\n );\n titlebar.appendChild(titletext);\n this.root.appendChild(titlebar);\n this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n var fig = this;\n\n var canvas_div = (this.canvas_div = document.createElement('div'));\n canvas_div.setAttribute(\n 'style',\n 'border: 1px solid #ddd;' +\n 'box-sizing: content-box;' +\n 'clear: both;' +\n 'min-height: 1px;' +\n 'min-width: 1px;' +\n 'outline: 0;' +\n 'overflow: hidden;' +\n 'position: relative;' +\n 'resize: both;'\n );\n\n function on_keyboard_event_closure(name) {\n return function (event) {\n return fig.key_event(event, name);\n };\n }\n\n canvas_div.addEventListener(\n 'keydown',\n on_keyboard_event_closure('key_press')\n );\n canvas_div.addEventListener(\n 'keyup',\n on_keyboard_event_closure('key_release')\n );\n\n this._canvas_extra_style(canvas_div);\n this.root.appendChild(canvas_div);\n\n var canvas = (this.canvas = document.createElement('canvas'));\n canvas.classList.add('mpl-canvas');\n canvas.setAttribute('style', 'box-sizing: content-box;');\n\n this.context = canvas.getContext('2d');\n\n var backingStore =\n this.context.backingStorePixelRatio ||\n this.context.webkitBackingStorePixelRatio ||\n this.context.mozBackingStorePixelRatio ||\n this.context.msBackingStorePixelRatio ||\n this.context.oBackingStorePixelRatio ||\n this.context.backingStorePixelRatio ||\n 1;\n\n this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n 'canvas'\n ));\n rubberband_canvas.setAttribute(\n 'style',\n 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n );\n\n // Apply a ponyfill if ResizeObserver is not implemented by browser.\n if (this.ResizeObserver === undefined) {\n if (window.ResizeObserver !== undefined) {\n this.ResizeObserver = window.ResizeObserver;\n } else {\n var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n this.ResizeObserver = obs.ResizeObserver;\n }\n }\n\n this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n var nentries = entries.length;\n for (var i = 0; i < nentries; i++) {\n var entry = entries[i];\n var width, height;\n if (entry.contentBoxSize) {\n if (entry.contentBoxSize instanceof Array) {\n // Chrome 84 implements new version of spec.\n width = entry.contentBoxSize[0].inlineSize;\n height = entry.contentBoxSize[0].blockSize;\n } else {\n // Firefox implements old version of spec.\n width = entry.contentBoxSize.inlineSize;\n height = entry.contentBoxSize.blockSize;\n }\n } else {\n // Chrome <84 implements even older version of spec.\n width = entry.contentRect.width;\n height = entry.contentRect.height;\n }\n\n // Keep the size of the canvas and rubber band canvas in sync with\n // the canvas container.\n if (entry.devicePixelContentBoxSize) {\n // Chrome 84 implements new version of spec.\n canvas.setAttribute(\n 'width',\n entry.devicePixelContentBoxSize[0].inlineSize\n );\n canvas.setAttribute(\n 'height',\n entry.devicePixelContentBoxSize[0].blockSize\n );\n } else {\n canvas.setAttribute('width', width * fig.ratio);\n canvas.setAttribute('height', height * fig.ratio);\n }\n canvas.setAttribute(\n 'style',\n 'width: ' + width + 'px; height: ' + height + 'px;'\n );\n\n rubberband_canvas.setAttribute('width', width);\n rubberband_canvas.setAttribute('height', height);\n\n // And update the size in Python. We ignore the initial 0/0 size\n // that occurs as the element is placed into the DOM, which should\n // otherwise not happen due to the minimum size styling.\n if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n fig.request_resize(width, height);\n }\n }\n });\n this.resizeObserverInstance.observe(canvas_div);\n\n function on_mouse_event_closure(name) {\n return function (event) {\n return fig.mouse_event(event, name);\n };\n }\n\n rubberband_canvas.addEventListener(\n 'mousedown',\n on_mouse_event_closure('button_press')\n );\n rubberband_canvas.addEventListener(\n 'mouseup',\n on_mouse_event_closure('button_release')\n );\n // Throttle sequential mouse events to 1 every 20ms.\n rubberband_canvas.addEventListener(\n 'mousemove',\n on_mouse_event_closure('motion_notify')\n );\n\n rubberband_canvas.addEventListener(\n 'mouseenter',\n on_mouse_event_closure('figure_enter')\n );\n rubberband_canvas.addEventListener(\n 'mouseleave',\n on_mouse_event_closure('figure_leave')\n );\n\n canvas_div.addEventListener('wheel', function (event) {\n if (event.deltaY < 0) {\n event.step = 1;\n } else {\n event.step = -1;\n }\n on_mouse_event_closure('scroll')(event);\n });\n\n canvas_div.appendChild(canvas);\n canvas_div.appendChild(rubberband_canvas);\n\n this.rubberband_context = rubberband_canvas.getContext('2d');\n this.rubberband_context.strokeStyle = '#000000';\n\n this._resize_canvas = function (width, height, forward) {\n if (forward) {\n canvas_div.style.width = width + 'px';\n canvas_div.style.height = height + 'px';\n }\n };\n\n // Disable right mouse context menu.\n this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n event.preventDefault();\n return false;\n });\n\n function set_focus() {\n canvas.focus();\n canvas_div.focus();\n }\n\n window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'mpl-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n continue;\n }\n\n var button = (fig.buttons[name] = document.createElement('button'));\n button.classList = 'mpl-widget';\n button.setAttribute('role', 'button');\n button.setAttribute('aria-disabled', 'false');\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n var icon_img = document.createElement('img');\n icon_img.src = '_images/' + image + '.png';\n icon_img.srcset = '_images/' + image + '_large.png 2x';\n icon_img.alt = tooltip;\n button.appendChild(icon_img);\n\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n var fmt_picker = document.createElement('select');\n fmt_picker.classList = 'mpl-widget';\n toolbar.appendChild(fmt_picker);\n this.format_dropdown = fmt_picker;\n\n for (var ind in mpl.extensions) {\n var fmt = mpl.extensions[ind];\n var option = document.createElement('option');\n option.selected = fmt === mpl.default_extension;\n option.innerHTML = fmt;\n fmt_picker.appendChild(option);\n }\n\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n // which will in turn request a refresh of the image.\n this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n properties['type'] = type;\n properties['figure_id'] = this.id;\n this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n if (!this.waiting) {\n this.waiting = true;\n this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n var format_dropdown = fig.format_dropdown;\n var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n var size = msg['size'];\n if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n fig._resize_canvas(size[0], size[1], msg['forward']);\n fig.send_message('refresh', {});\n }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n var x0 = msg['x0'] / fig.ratio;\n var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n var x1 = msg['x1'] / fig.ratio;\n var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n x0 = Math.floor(x0) + 0.5;\n y0 = Math.floor(y0) + 0.5;\n x1 = Math.floor(x1) + 0.5;\n y1 = Math.floor(y1) + 0.5;\n var min_x = Math.min(x0, x1);\n var min_y = Math.min(y0, y1);\n var width = Math.abs(x1 - x0);\n var height = Math.abs(y1 - y0);\n\n fig.rubberband_context.clearRect(\n 0,\n 0,\n fig.canvas.width / fig.ratio,\n fig.canvas.height / fig.ratio\n );\n\n fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n // Updates the figure title.\n fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n var cursor = msg['cursor'];\n switch (cursor) {\n case 0:\n cursor = 'pointer';\n break;\n case 1:\n cursor = 'default';\n break;\n case 2:\n cursor = 'crosshair';\n break;\n case 3:\n cursor = 'move';\n break;\n }\n fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n // Request the server to send over a new figure.\n fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n for (var key in msg) {\n if (!(key in fig.buttons)) {\n continue;\n }\n fig.buttons[key].disabled = !msg[key];\n fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n if (msg['mode'] === 'PAN') {\n fig.buttons['Pan'].classList.add('active');\n fig.buttons['Zoom'].classList.remove('active');\n } else if (msg['mode'] === 'ZOOM') {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.add('active');\n } else {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.remove('active');\n }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Called whenever the canvas gets updated.\n this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n return function socket_on_message(evt) {\n if (evt.data instanceof Blob) {\n /* FIXME: We get \"Resource interpreted as Image but\n * transferred with MIME type text/plain:\" errors on\n * Chrome. But how to set the MIME type? It doesn't seem\n * to be part of the websocket stream */\n evt.data.type = 'image/png';\n\n /* Free the memory for the previous frames */\n if (fig.imageObj.src) {\n (window.URL || window.webkitURL).revokeObjectURL(\n fig.imageObj.src\n );\n }\n\n fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n evt.data\n );\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n } else if (\n typeof evt.data === 'string' &&\n evt.data.slice(0, 21) === 'data:image/png;base64'\n ) {\n fig.imageObj.src = evt.data;\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n }\n\n var msg = JSON.parse(evt.data);\n var msg_type = msg['type'];\n\n // Call the \"handle_{type}\" callback, which takes\n // the figure and JSON message as its only arguments.\n try {\n var callback = fig['handle_' + msg_type];\n } catch (e) {\n console.log(\n \"No handler for the '\" + msg_type + \"' message type: \",\n msg\n );\n return;\n }\n\n if (callback) {\n try {\n // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n callback(fig, msg);\n } catch (e) {\n console.log(\n \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n e,\n e.stack,\n msg\n );\n }\n }\n };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n //this section is from http://www.quirksmode.org/js/events_properties.html\n var targ;\n if (!e) {\n e = window.event;\n }\n if (e.target) {\n targ = e.target;\n } else if (e.srcElement) {\n targ = e.srcElement;\n }\n if (targ.nodeType === 3) {\n // defeat Safari bug\n targ = targ.parentNode;\n }\n\n // pageX,Y are the mouse positions relative to the document\n var boundingRect = targ.getBoundingClientRect();\n var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n return Object.keys(original).reduce(function (obj, key) {\n if (typeof original[key] !== 'object') {\n obj[key] = original[key];\n }\n return obj;\n }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n var canvas_pos = mpl.findpos(event);\n\n if (name === 'button_press') {\n this.canvas.focus();\n this.canvas_div.focus();\n }\n\n var x = canvas_pos.x * this.ratio;\n var y = canvas_pos.y * this.ratio;\n\n this.send_message(name, {\n x: x,\n y: y,\n button: event.button,\n step: event.step,\n guiEvent: simpleKeys(event),\n });\n\n /* This prevents the web browser from automatically changing to\n * the text insertion cursor when the button is pressed. We want\n * to control all of the cursor setting manually through the\n * 'cursor' event from matplotlib */\n event.preventDefault();\n return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n // Prevent repeat events\n if (name === 'key_press') {\n if (event.which === this._key) {\n return;\n } else {\n this._key = event.which;\n }\n }\n if (name === 'key_release') {\n this._key = null;\n }\n\n var value = '';\n if (event.ctrlKey && event.which !== 17) {\n value += 'ctrl+';\n }\n if (event.altKey && event.which !== 18) {\n value += 'alt+';\n }\n if (event.shiftKey && event.which !== 16) {\n value += 'shift+';\n }\n\n value += 'k';\n value += event.which.toString();\n\n this._key_event_extra(event, name);\n\n this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n if (name === 'download') {\n this.handle_save(this, null);\n } else {\n this.send_message('toolbar_button', { name: name });\n }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\nmpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n\nmpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n // Create a \"websocket\"-like object which calls the given IPython comm\n // object with the appropriate methods. Currently this is a non binary\n // socket, so there is still some room for performance tuning.\n var ws = {};\n\n ws.close = function () {\n comm.close();\n };\n ws.send = function (m) {\n //console.log('sending', m);\n comm.send(m);\n };\n // Register the callback with on_msg.\n comm.on_msg(function (msg) {\n //console.log('receiving', msg['content']['data'], msg);\n // Pass the mpl event to the overridden (by mpl) onmessage function.\n ws.onmessage(msg['content']['data']);\n });\n return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n // This is the function which gets called when the mpl process\n // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n var id = msg.content.data.id;\n // Get hold of the div created by the display call when the Comm\n // socket was opened in Python.\n var element = document.getElementById(id);\n var ws_proxy = comm_websocket_adapter(comm);\n\n function ondownload(figure, _format) {\n window.open(figure.canvas.toDataURL());\n }\n\n var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n // web socket which is closed, not our websocket->open comm proxy.\n ws_proxy.onopen();\n\n fig.parent_element = element;\n fig.cell_info = mpl.find_output_cell(\"
\");\n if (!fig.cell_info) {\n console.error('Failed to find cell for figure', id, fig);\n return;\n }\n fig.cell_info[0].output_area.element.on(\n 'cleared',\n { fig: fig },\n fig._remove_fig_handler\n );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n var width = fig.canvas.width / fig.ratio;\n fig.cell_info[0].output_area.element.off(\n 'cleared',\n fig._remove_fig_handler\n );\n fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n // Update the output cell to use the data from the current canvas.\n fig.push_to_output();\n var dataURL = fig.canvas.toDataURL();\n // Re-enable the keyboard manager in IPython - without this line, in FF,\n // the notebook keyboard shortcuts fail.\n IPython.keyboard_manager.enable();\n fig.parent_element.innerHTML =\n '';\n fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n fig.send_message('closing', msg);\n // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n // Turn the data on the canvas into data in the output cell.\n var width = this.canvas.width / this.ratio;\n var dataURL = this.canvas.toDataURL();\n this.cell_info[1]['text/html'] =\n '';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Tell IPython that the notebook contents must change.\n IPython.notebook.set_dirty(true);\n this.send_message('ack', {});\n var fig = this;\n // Wait a second, then push the new image to the DOM so\n // that it is saved nicely (might be nice to debounce this).\n setTimeout(function () {\n fig.push_to_output();\n }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'btn-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n var button;\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n continue;\n }\n\n button = fig.buttons[name] = document.createElement('button');\n button.classList = 'btn btn-default';\n button.href = '#';\n button.title = name;\n button.innerHTML = '';\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n // Add the status bar.\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message pull-right';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n\n // Add the close button to the window.\n var buttongrp = document.createElement('div');\n buttongrp.classList = 'btn-group inline pull-right';\n button = document.createElement('button');\n button.classList = 'btn btn-mini btn-primary';\n button.href = '#';\n button.title = 'Stop Interaction';\n button.innerHTML = '';\n button.addEventListener('click', function (_evt) {\n fig.handle_close(fig, {});\n });\n button.addEventListener(\n 'mouseover',\n on_mouseover_closure('Stop Interaction')\n );\n buttongrp.appendChild(button);\n var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n var fig = event.data.fig;\n if (event.target !== this) {\n // Ignore bubbled events from children.\n return;\n }\n fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n // this is important to make the div 'focusable\n el.setAttribute('tabindex', 0);\n // reach out to IPython and tell the keyboard manager to turn it's self\n // off when our div gets focus\n\n // location in version 3\n if (IPython.notebook.keyboard_manager) {\n IPython.notebook.keyboard_manager.register_events(el);\n } else {\n // location in version 2\n IPython.keyboard_manager.register_events(el);\n }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n var manager = IPython.notebook.keyboard_manager;\n if (!manager) {\n manager = IPython.keyboard_manager;\n }\n\n // Check for shift+enter\n if (event.shiftKey && event.which === 13) {\n this.canvas_div.blur();\n // select the cell after this one\n var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n IPython.notebook.select(index + 1);\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n // Return the cell and output element which can be found *uniquely* in the notebook.\n // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n // IPython event is triggered only after the cells have been serialised, which for\n // our purposes (turning an active figure into a static one), is too late.\n var cells = IPython.notebook.get_cells();\n var ncells = cells.length;\n for (var i = 0; i < ncells; i++) {\n var cell = cells[i];\n if (cell.cell_type === 'code') {\n for (var j = 0; j < cell.output_area.outputs.length; j++) {\n var data = cell.output_area.outputs[j];\n if (data.data) {\n // IPython >= 3 moved mimebundle to data attribute of output\n data = data.data;\n }\n if (data['text/html'] === html_output) {\n return [cell, data, j];\n }\n }\n }\n }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n IPython.notebook.kernel.comm_manager.register_target(\n 'matplotlib',\n mpl.mpl_figure_comm\n );\n}\n", "text/plain": [ "" ] @@ -13912,955 +1588,7 @@ "outputs": [ { "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "/* global mpl */\n", - "window.mpl = {};\n", - "\n", - "mpl.get_websocket_type = function () {\n", - " if (typeof WebSocket !== 'undefined') {\n", - " return WebSocket;\n", - " } else if (typeof MozWebSocket !== 'undefined') {\n", - " return MozWebSocket;\n", - " } else {\n", - " alert(\n", - " 'Your browser does not have WebSocket support. ' +\n", - " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", - " 'Firefox 4 and 5 are also supported but you ' +\n", - " 'have to enable WebSockets in about:config.'\n", - " );\n", - " }\n", - "};\n", - "\n", - "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", - " this.id = figure_id;\n", - "\n", - " this.ws = websocket;\n", - "\n", - " this.supports_binary = this.ws.binaryType !== undefined;\n", - "\n", - " if (!this.supports_binary) {\n", - " var warnings = document.getElementById('mpl-warnings');\n", - " if (warnings) {\n", - " warnings.style.display = 'block';\n", - " warnings.textContent =\n", - " 'This browser does not support binary websocket messages. ' +\n", - " 'Performance may be slow.';\n", - " }\n", - " }\n", - "\n", - " this.imageObj = new Image();\n", - "\n", - " this.context = undefined;\n", - " this.message = undefined;\n", - " this.canvas = undefined;\n", - " this.rubberband_canvas = undefined;\n", - " this.rubberband_context = undefined;\n", - " this.format_dropdown = undefined;\n", - "\n", - " this.image_mode = 'full';\n", - "\n", - " this.root = document.createElement('div');\n", - " this.root.setAttribute('style', 'display: inline-block');\n", - " this._root_extra_style(this.root);\n", - "\n", - " parent_element.appendChild(this.root);\n", - "\n", - " this._init_header(this);\n", - " this._init_canvas(this);\n", - " this._init_toolbar(this);\n", - "\n", - " var fig = this;\n", - "\n", - " this.waiting = false;\n", - "\n", - " this.ws.onopen = function () {\n", - " fig.send_message('supports_binary', { value: fig.supports_binary });\n", - " fig.send_message('send_image_mode', {});\n", - " if (fig.ratio !== 1) {\n", - " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", - " }\n", - " fig.send_message('refresh', {});\n", - " };\n", - "\n", - " this.imageObj.onload = function () {\n", - " if (fig.image_mode === 'full') {\n", - " // Full images could contain transparency (where diff images\n", - " // almost always do), so we need to clear the canvas so that\n", - " // there is no ghosting.\n", - " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", - " }\n", - " fig.context.drawImage(fig.imageObj, 0, 0);\n", - " };\n", - "\n", - " this.imageObj.onunload = function () {\n", - " fig.ws.close();\n", - " };\n", - "\n", - " this.ws.onmessage = this._make_on_message_function(this);\n", - "\n", - " this.ondownload = ondownload;\n", - "};\n", - "\n", - "mpl.figure.prototype._init_header = function () {\n", - " var titlebar = document.createElement('div');\n", - " titlebar.classList =\n", - " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", - " var titletext = document.createElement('div');\n", - " titletext.classList = 'ui-dialog-title';\n", - " titletext.setAttribute(\n", - " 'style',\n", - " 'width: 100%; text-align: center; padding: 3px;'\n", - " );\n", - " titlebar.appendChild(titletext);\n", - " this.root.appendChild(titlebar);\n", - " this.header = titletext;\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._init_canvas = function () {\n", - " var fig = this;\n", - "\n", - " var canvas_div = (this.canvas_div = document.createElement('div'));\n", - " canvas_div.setAttribute(\n", - " 'style',\n", - " 'border: 1px solid #ddd;' +\n", - " 'box-sizing: content-box;' +\n", - " 'clear: both;' +\n", - " 'min-height: 1px;' +\n", - " 'min-width: 1px;' +\n", - " 'outline: 0;' +\n", - " 'overflow: hidden;' +\n", - " 'position: relative;' +\n", - " 'resize: both;'\n", - " );\n", - "\n", - " function on_keyboard_event_closure(name) {\n", - " return function (event) {\n", - " return fig.key_event(event, name);\n", - " };\n", - " }\n", - "\n", - " canvas_div.addEventListener(\n", - " 'keydown',\n", - " on_keyboard_event_closure('key_press')\n", - " );\n", - " canvas_div.addEventListener(\n", - " 'keyup',\n", - " on_keyboard_event_closure('key_release')\n", - " );\n", - "\n", - " this._canvas_extra_style(canvas_div);\n", - " this.root.appendChild(canvas_div);\n", - "\n", - " var canvas = (this.canvas = document.createElement('canvas'));\n", - " canvas.classList.add('mpl-canvas');\n", - " canvas.setAttribute('style', 'box-sizing: content-box;');\n", - "\n", - " this.context = canvas.getContext('2d');\n", - "\n", - " var backingStore =\n", - " this.context.backingStorePixelRatio ||\n", - " this.context.webkitBackingStorePixelRatio ||\n", - " this.context.mozBackingStorePixelRatio ||\n", - " this.context.msBackingStorePixelRatio ||\n", - " this.context.oBackingStorePixelRatio ||\n", - " this.context.backingStorePixelRatio ||\n", - " 1;\n", - "\n", - " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", - "\n", - " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", - " 'canvas'\n", - " ));\n", - " rubberband_canvas.setAttribute(\n", - " 'style',\n", - " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", - " );\n", - "\n", - " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", - " if (this.ResizeObserver === undefined) {\n", - " if (window.ResizeObserver !== undefined) {\n", - " this.ResizeObserver = window.ResizeObserver;\n", - " } else {\n", - " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", - " this.ResizeObserver = obs.ResizeObserver;\n", - " }\n", - " }\n", - "\n", - " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", - " var nentries = entries.length;\n", - " for (var i = 0; i < nentries; i++) {\n", - " var entry = entries[i];\n", - " var width, height;\n", - " if (entry.contentBoxSize) {\n", - " if (entry.contentBoxSize instanceof Array) {\n", - " // Chrome 84 implements new version of spec.\n", - " width = entry.contentBoxSize[0].inlineSize;\n", - " height = entry.contentBoxSize[0].blockSize;\n", - " } else {\n", - " // Firefox implements old version of spec.\n", - " width = entry.contentBoxSize.inlineSize;\n", - " height = entry.contentBoxSize.blockSize;\n", - " }\n", - " } else {\n", - " // Chrome <84 implements even older version of spec.\n", - " width = entry.contentRect.width;\n", - " height = entry.contentRect.height;\n", - " }\n", - "\n", - " // Keep the size of the canvas and rubber band canvas in sync with\n", - " // the canvas container.\n", - " if (entry.devicePixelContentBoxSize) {\n", - " // Chrome 84 implements new version of spec.\n", - " canvas.setAttribute(\n", - " 'width',\n", - " entry.devicePixelContentBoxSize[0].inlineSize\n", - " );\n", - " canvas.setAttribute(\n", - " 'height',\n", - " entry.devicePixelContentBoxSize[0].blockSize\n", - " );\n", - " } else {\n", - " canvas.setAttribute('width', width * fig.ratio);\n", - " canvas.setAttribute('height', height * fig.ratio);\n", - " }\n", - " canvas.setAttribute(\n", - " 'style',\n", - " 'width: ' + width + 'px; height: ' + height + 'px;'\n", - " );\n", - "\n", - " rubberband_canvas.setAttribute('width', width);\n", - " rubberband_canvas.setAttribute('height', height);\n", - "\n", - " // And update the size in Python. We ignore the initial 0/0 size\n", - " // that occurs as the element is placed into the DOM, which should\n", - " // otherwise not happen due to the minimum size styling.\n", - " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", - " fig.request_resize(width, height);\n", - " }\n", - " }\n", - " });\n", - " this.resizeObserverInstance.observe(canvas_div);\n", - "\n", - " function on_mouse_event_closure(name) {\n", - " return function (event) {\n", - " return fig.mouse_event(event, name);\n", - " };\n", - " }\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mousedown',\n", - " on_mouse_event_closure('button_press')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseup',\n", - " on_mouse_event_closure('button_release')\n", - " );\n", - " // Throttle sequential mouse events to 1 every 20ms.\n", - " rubberband_canvas.addEventListener(\n", - " 'mousemove',\n", - " on_mouse_event_closure('motion_notify')\n", - " );\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseenter',\n", - " on_mouse_event_closure('figure_enter')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseleave',\n", - " on_mouse_event_closure('figure_leave')\n", - " );\n", - "\n", - " canvas_div.addEventListener('wheel', function (event) {\n", - " if (event.deltaY < 0) {\n", - " event.step = 1;\n", - " } else {\n", - " event.step = -1;\n", - " }\n", - " on_mouse_event_closure('scroll')(event);\n", - " });\n", - "\n", - " canvas_div.appendChild(canvas);\n", - " canvas_div.appendChild(rubberband_canvas);\n", - "\n", - " this.rubberband_context = rubberband_canvas.getContext('2d');\n", - " this.rubberband_context.strokeStyle = '#000000';\n", - "\n", - " this._resize_canvas = function (width, height, forward) {\n", - " if (forward) {\n", - " canvas_div.style.width = width + 'px';\n", - " canvas_div.style.height = height + 'px';\n", - " }\n", - " };\n", - "\n", - " // Disable right mouse context menu.\n", - " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", - " event.preventDefault();\n", - " return false;\n", - " });\n", - "\n", - " function set_focus() {\n", - " canvas.focus();\n", - " canvas_div.focus();\n", - " }\n", - "\n", - " window.setTimeout(set_focus, 100);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'mpl-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " continue;\n", - " }\n", - "\n", - " var button = (fig.buttons[name] = document.createElement('button'));\n", - " button.classList = 'mpl-widget';\n", - " button.setAttribute('role', 'button');\n", - " button.setAttribute('aria-disabled', 'false');\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - "\n", - " var icon_img = document.createElement('img');\n", - " icon_img.src = '_images/' + image + '.png';\n", - " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", - " icon_img.alt = tooltip;\n", - " button.appendChild(icon_img);\n", - "\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " var fmt_picker = document.createElement('select');\n", - " fmt_picker.classList = 'mpl-widget';\n", - " toolbar.appendChild(fmt_picker);\n", - " this.format_dropdown = fmt_picker;\n", - "\n", - " for (var ind in mpl.extensions) {\n", - " var fmt = mpl.extensions[ind];\n", - " var option = document.createElement('option');\n", - " option.selected = fmt === mpl.default_extension;\n", - " option.innerHTML = fmt;\n", - " fmt_picker.appendChild(option);\n", - " }\n", - "\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "};\n", - "\n", - "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", - " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", - " // which will in turn request a refresh of the image.\n", - " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", - "};\n", - "\n", - "mpl.figure.prototype.send_message = function (type, properties) {\n", - " properties['type'] = type;\n", - " properties['figure_id'] = this.id;\n", - " this.ws.send(JSON.stringify(properties));\n", - "};\n", - "\n", - "mpl.figure.prototype.send_draw_message = function () {\n", - " if (!this.waiting) {\n", - " this.waiting = true;\n", - " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " var format_dropdown = fig.format_dropdown;\n", - " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", - " fig.ondownload(fig, format);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", - " var size = msg['size'];\n", - " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", - " fig._resize_canvas(size[0], size[1], msg['forward']);\n", - " fig.send_message('refresh', {});\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", - " var x0 = msg['x0'] / fig.ratio;\n", - " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", - " var x1 = msg['x1'] / fig.ratio;\n", - " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", - " x0 = Math.floor(x0) + 0.5;\n", - " y0 = Math.floor(y0) + 0.5;\n", - " x1 = Math.floor(x1) + 0.5;\n", - " y1 = Math.floor(y1) + 0.5;\n", - " var min_x = Math.min(x0, x1);\n", - " var min_y = Math.min(y0, y1);\n", - " var width = Math.abs(x1 - x0);\n", - " var height = Math.abs(y1 - y0);\n", - "\n", - " fig.rubberband_context.clearRect(\n", - " 0,\n", - " 0,\n", - " fig.canvas.width / fig.ratio,\n", - " fig.canvas.height / fig.ratio\n", - " );\n", - "\n", - " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", - " // Updates the figure title.\n", - " fig.header.textContent = msg['label'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", - " var cursor = msg['cursor'];\n", - " switch (cursor) {\n", - " case 0:\n", - " cursor = 'pointer';\n", - " break;\n", - " case 1:\n", - " cursor = 'default';\n", - " break;\n", - " case 2:\n", - " cursor = 'crosshair';\n", - " break;\n", - " case 3:\n", - " cursor = 'move';\n", - " break;\n", - " }\n", - " fig.rubberband_canvas.style.cursor = cursor;\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_message = function (fig, msg) {\n", - " fig.message.textContent = msg['message'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", - " // Request the server to send over a new figure.\n", - " fig.send_draw_message();\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", - " fig.image_mode = msg['mode'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", - " for (var key in msg) {\n", - " if (!(key in fig.buttons)) {\n", - " continue;\n", - " }\n", - " fig.buttons[key].disabled = !msg[key];\n", - " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", - " if (msg['mode'] === 'PAN') {\n", - " fig.buttons['Pan'].classList.add('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " } else if (msg['mode'] === 'ZOOM') {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.add('active');\n", - " } else {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Called whenever the canvas gets updated.\n", - " this.send_message('ack', {});\n", - "};\n", - "\n", - "// A function to construct a web socket function for onmessage handling.\n", - "// Called in the figure constructor.\n", - "mpl.figure.prototype._make_on_message_function = function (fig) {\n", - " return function socket_on_message(evt) {\n", - " if (evt.data instanceof Blob) {\n", - " /* FIXME: We get \"Resource interpreted as Image but\n", - " * transferred with MIME type text/plain:\" errors on\n", - " * Chrome. But how to set the MIME type? It doesn't seem\n", - " * to be part of the websocket stream */\n", - " evt.data.type = 'image/png';\n", - "\n", - " /* Free the memory for the previous frames */\n", - " if (fig.imageObj.src) {\n", - " (window.URL || window.webkitURL).revokeObjectURL(\n", - " fig.imageObj.src\n", - " );\n", - " }\n", - "\n", - " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", - " evt.data\n", - " );\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " } else if (\n", - " typeof evt.data === 'string' &&\n", - " evt.data.slice(0, 21) === 'data:image/png;base64'\n", - " ) {\n", - " fig.imageObj.src = evt.data;\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " }\n", - "\n", - " var msg = JSON.parse(evt.data);\n", - " var msg_type = msg['type'];\n", - "\n", - " // Call the \"handle_{type}\" callback, which takes\n", - " // the figure and JSON message as its only arguments.\n", - " try {\n", - " var callback = fig['handle_' + msg_type];\n", - " } catch (e) {\n", - " console.log(\n", - " \"No handler for the '\" + msg_type + \"' message type: \",\n", - " msg\n", - " );\n", - " return;\n", - " }\n", - "\n", - " if (callback) {\n", - " try {\n", - " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", - " callback(fig, msg);\n", - " } catch (e) {\n", - " console.log(\n", - " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", - " e,\n", - " e.stack,\n", - " msg\n", - " );\n", - " }\n", - " }\n", - " };\n", - "};\n", - "\n", - "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", - "mpl.findpos = function (e) {\n", - " //this section is from http://www.quirksmode.org/js/events_properties.html\n", - " var targ;\n", - " if (!e) {\n", - " e = window.event;\n", - " }\n", - " if (e.target) {\n", - " targ = e.target;\n", - " } else if (e.srcElement) {\n", - " targ = e.srcElement;\n", - " }\n", - " if (targ.nodeType === 3) {\n", - " // defeat Safari bug\n", - " targ = targ.parentNode;\n", - " }\n", - "\n", - " // pageX,Y are the mouse positions relative to the document\n", - " var boundingRect = targ.getBoundingClientRect();\n", - " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", - " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", - "\n", - " return { x: x, y: y };\n", - "};\n", - "\n", - "/*\n", - " * return a copy of an object with only non-object keys\n", - " * we need this to avoid circular references\n", - " * http://stackoverflow.com/a/24161582/3208463\n", - " */\n", - "function simpleKeys(original) {\n", - " return Object.keys(original).reduce(function (obj, key) {\n", - " if (typeof original[key] !== 'object') {\n", - " obj[key] = original[key];\n", - " }\n", - " return obj;\n", - " }, {});\n", - "}\n", - "\n", - "mpl.figure.prototype.mouse_event = function (event, name) {\n", - " var canvas_pos = mpl.findpos(event);\n", - "\n", - " if (name === 'button_press') {\n", - " this.canvas.focus();\n", - " this.canvas_div.focus();\n", - " }\n", - "\n", - " var x = canvas_pos.x * this.ratio;\n", - " var y = canvas_pos.y * this.ratio;\n", - "\n", - " this.send_message(name, {\n", - " x: x,\n", - " y: y,\n", - " button: event.button,\n", - " step: event.step,\n", - " guiEvent: simpleKeys(event),\n", - " });\n", - "\n", - " /* This prevents the web browser from automatically changing to\n", - " * the text insertion cursor when the button is pressed. We want\n", - " * to control all of the cursor setting manually through the\n", - " * 'cursor' event from matplotlib */\n", - " event.preventDefault();\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", - " // Handle any extra behaviour associated with a key event\n", - "};\n", - "\n", - "mpl.figure.prototype.key_event = function (event, name) {\n", - " // Prevent repeat events\n", - " if (name === 'key_press') {\n", - " if (event.which === this._key) {\n", - " return;\n", - " } else {\n", - " this._key = event.which;\n", - " }\n", - " }\n", - " if (name === 'key_release') {\n", - " this._key = null;\n", - " }\n", - "\n", - " var value = '';\n", - " if (event.ctrlKey && event.which !== 17) {\n", - " value += 'ctrl+';\n", - " }\n", - " if (event.altKey && event.which !== 18) {\n", - " value += 'alt+';\n", - " }\n", - " if (event.shiftKey && event.which !== 16) {\n", - " value += 'shift+';\n", - " }\n", - "\n", - " value += 'k';\n", - " value += event.which.toString();\n", - "\n", - " this._key_event_extra(event, name);\n", - "\n", - " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", - " if (name === 'download') {\n", - " this.handle_save(this, null);\n", - " } else {\n", - " this.send_message('toolbar_button', { name: name });\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", - " this.message.textContent = tooltip;\n", - "};\n", - "\n", - "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", - "// prettier-ignore\n", - "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", - "\n", - "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", - "\n", - "mpl.default_extension = \"png\";/* global mpl */\n", - "\n", - "var comm_websocket_adapter = function (comm) {\n", - " // Create a \"websocket\"-like object which calls the given IPython comm\n", - " // object with the appropriate methods. Currently this is a non binary\n", - " // socket, so there is still some room for performance tuning.\n", - " var ws = {};\n", - "\n", - " ws.close = function () {\n", - " comm.close();\n", - " };\n", - " ws.send = function (m) {\n", - " //console.log('sending', m);\n", - " comm.send(m);\n", - " };\n", - " // Register the callback with on_msg.\n", - " comm.on_msg(function (msg) {\n", - " //console.log('receiving', msg['content']['data'], msg);\n", - " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", - " ws.onmessage(msg['content']['data']);\n", - " });\n", - " return ws;\n", - "};\n", - "\n", - "mpl.mpl_figure_comm = function (comm, msg) {\n", - " // This is the function which gets called when the mpl process\n", - " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", - "\n", - " var id = msg.content.data.id;\n", - " // Get hold of the div created by the display call when the Comm\n", - " // socket was opened in Python.\n", - " var element = document.getElementById(id);\n", - " var ws_proxy = comm_websocket_adapter(comm);\n", - "\n", - " function ondownload(figure, _format) {\n", - " window.open(figure.canvas.toDataURL());\n", - " }\n", - "\n", - " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", - "\n", - " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", - " // web socket which is closed, not our websocket->open comm proxy.\n", - " ws_proxy.onopen();\n", - "\n", - " fig.parent_element = element;\n", - " fig.cell_info = mpl.find_output_cell(\"
\");\n", - " if (!fig.cell_info) {\n", - " console.error('Failed to find cell for figure', id, fig);\n", - " return;\n", - " }\n", - " fig.cell_info[0].output_area.element.on(\n", - " 'cleared',\n", - " { fig: fig },\n", - " fig._remove_fig_handler\n", - " );\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_close = function (fig, msg) {\n", - " var width = fig.canvas.width / fig.ratio;\n", - " fig.cell_info[0].output_area.element.off(\n", - " 'cleared',\n", - " fig._remove_fig_handler\n", - " );\n", - " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", - "\n", - " // Update the output cell to use the data from the current canvas.\n", - " fig.push_to_output();\n", - " var dataURL = fig.canvas.toDataURL();\n", - " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", - " // the notebook keyboard shortcuts fail.\n", - " IPython.keyboard_manager.enable();\n", - " fig.parent_element.innerHTML =\n", - " '';\n", - " fig.close_ws(fig, msg);\n", - "};\n", - "\n", - "mpl.figure.prototype.close_ws = function (fig, msg) {\n", - " fig.send_message('closing', msg);\n", - " // fig.ws.close()\n", - "};\n", - "\n", - "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", - " // Turn the data on the canvas into data in the output cell.\n", - " var width = this.canvas.width / this.ratio;\n", - " var dataURL = this.canvas.toDataURL();\n", - " this.cell_info[1]['text/html'] =\n", - " '';\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Tell IPython that the notebook contents must change.\n", - " IPython.notebook.set_dirty(true);\n", - " this.send_message('ack', {});\n", - " var fig = this;\n", - " // Wait a second, then push the new image to the DOM so\n", - " // that it is saved nicely (might be nice to debounce this).\n", - " setTimeout(function () {\n", - " fig.push_to_output();\n", - " }, 1000);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'btn-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " var button;\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " continue;\n", - " }\n", - "\n", - " button = fig.buttons[name] = document.createElement('button');\n", - " button.classList = 'btn btn-default';\n", - " button.href = '#';\n", - " button.title = name;\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " // Add the status bar.\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message pull-right';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "\n", - " // Add the close button to the window.\n", - " var buttongrp = document.createElement('div');\n", - " buttongrp.classList = 'btn-group inline pull-right';\n", - " button = document.createElement('button');\n", - " button.classList = 'btn btn-mini btn-primary';\n", - " button.href = '#';\n", - " button.title = 'Stop Interaction';\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', function (_evt) {\n", - " fig.handle_close(fig, {});\n", - " });\n", - " button.addEventListener(\n", - " 'mouseover',\n", - " on_mouseover_closure('Stop Interaction')\n", - " );\n", - " buttongrp.appendChild(button);\n", - " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", - " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", - "};\n", - "\n", - "mpl.figure.prototype._remove_fig_handler = function (event) {\n", - " var fig = event.data.fig;\n", - " if (event.target !== this) {\n", - " // Ignore bubbled events from children.\n", - " return;\n", - " }\n", - " fig.close_ws(fig, {});\n", - "};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (el) {\n", - " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (el) {\n", - " // this is important to make the div 'focusable\n", - " el.setAttribute('tabindex', 0);\n", - " // reach out to IPython and tell the keyboard manager to turn it's self\n", - " // off when our div gets focus\n", - "\n", - " // location in version 3\n", - " if (IPython.notebook.keyboard_manager) {\n", - " IPython.notebook.keyboard_manager.register_events(el);\n", - " } else {\n", - " // location in version 2\n", - " IPython.keyboard_manager.register_events(el);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", - " var manager = IPython.notebook.keyboard_manager;\n", - " if (!manager) {\n", - " manager = IPython.keyboard_manager;\n", - " }\n", - "\n", - " // Check for shift+enter\n", - " if (event.shiftKey && event.which === 13) {\n", - " this.canvas_div.blur();\n", - " // select the cell after this one\n", - " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", - " IPython.notebook.select(index + 1);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " fig.ondownload(fig, null);\n", - "};\n", - "\n", - "mpl.find_output_cell = function (html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i = 0; i < ncells; i++) {\n", - " var cell = cells[i];\n", - " if (cell.cell_type === 'code') {\n", - " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", - " var data = cell.output_area.outputs[j];\n", - " if (data.data) {\n", - " // IPython >= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] === html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "};\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel !== null) {\n", - " IPython.notebook.kernel.comm_manager.register_target(\n", - " 'matplotlib',\n", - " mpl.mpl_figure_comm\n", - " );\n", - "}\n" - ], + "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n if (typeof WebSocket !== 'undefined') {\n return WebSocket;\n } else if (typeof MozWebSocket !== 'undefined') {\n return MozWebSocket;\n } else {\n alert(\n 'Your browser does not have WebSocket support. ' +\n 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n 'Firefox 4 and 5 are also supported but you ' +\n 'have to enable WebSockets in about:config.'\n );\n }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n this.id = figure_id;\n\n this.ws = websocket;\n\n this.supports_binary = this.ws.binaryType !== undefined;\n\n if (!this.supports_binary) {\n var warnings = document.getElementById('mpl-warnings');\n if (warnings) {\n warnings.style.display = 'block';\n warnings.textContent =\n 'This browser does not support binary websocket messages. ' +\n 'Performance may be slow.';\n }\n }\n\n this.imageObj = new Image();\n\n this.context = undefined;\n this.message = undefined;\n this.canvas = undefined;\n this.rubberband_canvas = undefined;\n this.rubberband_context = undefined;\n this.format_dropdown = undefined;\n\n this.image_mode = 'full';\n\n this.root = document.createElement('div');\n this.root.setAttribute('style', 'display: inline-block');\n this._root_extra_style(this.root);\n\n parent_element.appendChild(this.root);\n\n this._init_header(this);\n this._init_canvas(this);\n this._init_toolbar(this);\n\n var fig = this;\n\n this.waiting = false;\n\n this.ws.onopen = function () {\n fig.send_message('supports_binary', { value: fig.supports_binary });\n fig.send_message('send_image_mode', {});\n if (fig.ratio !== 1) {\n fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n }\n fig.send_message('refresh', {});\n };\n\n this.imageObj.onload = function () {\n if (fig.image_mode === 'full') {\n // Full images could contain transparency (where diff images\n // almost always do), so we need to clear the canvas so that\n // there is no ghosting.\n fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n }\n fig.context.drawImage(fig.imageObj, 0, 0);\n };\n\n this.imageObj.onunload = function () {\n fig.ws.close();\n };\n\n this.ws.onmessage = this._make_on_message_function(this);\n\n this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n var titlebar = document.createElement('div');\n titlebar.classList =\n 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n var titletext = document.createElement('div');\n titletext.classList = 'ui-dialog-title';\n titletext.setAttribute(\n 'style',\n 'width: 100%; text-align: center; padding: 3px;'\n );\n titlebar.appendChild(titletext);\n this.root.appendChild(titlebar);\n this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n var fig = this;\n\n var canvas_div = (this.canvas_div = document.createElement('div'));\n canvas_div.setAttribute(\n 'style',\n 'border: 1px solid #ddd;' +\n 'box-sizing: content-box;' +\n 'clear: both;' +\n 'min-height: 1px;' +\n 'min-width: 1px;' +\n 'outline: 0;' +\n 'overflow: hidden;' +\n 'position: relative;' +\n 'resize: both;'\n );\n\n function on_keyboard_event_closure(name) {\n return function (event) {\n return fig.key_event(event, name);\n };\n }\n\n canvas_div.addEventListener(\n 'keydown',\n on_keyboard_event_closure('key_press')\n );\n canvas_div.addEventListener(\n 'keyup',\n on_keyboard_event_closure('key_release')\n );\n\n this._canvas_extra_style(canvas_div);\n this.root.appendChild(canvas_div);\n\n var canvas = (this.canvas = document.createElement('canvas'));\n canvas.classList.add('mpl-canvas');\n canvas.setAttribute('style', 'box-sizing: content-box;');\n\n this.context = canvas.getContext('2d');\n\n var backingStore =\n this.context.backingStorePixelRatio ||\n this.context.webkitBackingStorePixelRatio ||\n this.context.mozBackingStorePixelRatio ||\n this.context.msBackingStorePixelRatio ||\n this.context.oBackingStorePixelRatio ||\n this.context.backingStorePixelRatio ||\n 1;\n\n this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n 'canvas'\n ));\n rubberband_canvas.setAttribute(\n 'style',\n 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n );\n\n // Apply a ponyfill if ResizeObserver is not implemented by browser.\n if (this.ResizeObserver === undefined) {\n if (window.ResizeObserver !== undefined) {\n this.ResizeObserver = window.ResizeObserver;\n } else {\n var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n this.ResizeObserver = obs.ResizeObserver;\n }\n }\n\n this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n var nentries = entries.length;\n for (var i = 0; i < nentries; i++) {\n var entry = entries[i];\n var width, height;\n if (entry.contentBoxSize) {\n if (entry.contentBoxSize instanceof Array) {\n // Chrome 84 implements new version of spec.\n width = entry.contentBoxSize[0].inlineSize;\n height = entry.contentBoxSize[0].blockSize;\n } else {\n // Firefox implements old version of spec.\n width = entry.contentBoxSize.inlineSize;\n height = entry.contentBoxSize.blockSize;\n }\n } else {\n // Chrome <84 implements even older version of spec.\n width = entry.contentRect.width;\n height = entry.contentRect.height;\n }\n\n // Keep the size of the canvas and rubber band canvas in sync with\n // the canvas container.\n if (entry.devicePixelContentBoxSize) {\n // Chrome 84 implements new version of spec.\n canvas.setAttribute(\n 'width',\n entry.devicePixelContentBoxSize[0].inlineSize\n );\n canvas.setAttribute(\n 'height',\n entry.devicePixelContentBoxSize[0].blockSize\n );\n } else {\n canvas.setAttribute('width', width * fig.ratio);\n canvas.setAttribute('height', height * fig.ratio);\n }\n canvas.setAttribute(\n 'style',\n 'width: ' + width + 'px; height: ' + height + 'px;'\n );\n\n rubberband_canvas.setAttribute('width', width);\n rubberband_canvas.setAttribute('height', height);\n\n // And update the size in Python. We ignore the initial 0/0 size\n // that occurs as the element is placed into the DOM, which should\n // otherwise not happen due to the minimum size styling.\n if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n fig.request_resize(width, height);\n }\n }\n });\n this.resizeObserverInstance.observe(canvas_div);\n\n function on_mouse_event_closure(name) {\n return function (event) {\n return fig.mouse_event(event, name);\n };\n }\n\n rubberband_canvas.addEventListener(\n 'mousedown',\n on_mouse_event_closure('button_press')\n );\n rubberband_canvas.addEventListener(\n 'mouseup',\n on_mouse_event_closure('button_release')\n );\n // Throttle sequential mouse events to 1 every 20ms.\n rubberband_canvas.addEventListener(\n 'mousemove',\n on_mouse_event_closure('motion_notify')\n );\n\n rubberband_canvas.addEventListener(\n 'mouseenter',\n on_mouse_event_closure('figure_enter')\n );\n rubberband_canvas.addEventListener(\n 'mouseleave',\n on_mouse_event_closure('figure_leave')\n );\n\n canvas_div.addEventListener('wheel', function (event) {\n if (event.deltaY < 0) {\n event.step = 1;\n } else {\n event.step = -1;\n }\n on_mouse_event_closure('scroll')(event);\n });\n\n canvas_div.appendChild(canvas);\n canvas_div.appendChild(rubberband_canvas);\n\n this.rubberband_context = rubberband_canvas.getContext('2d');\n this.rubberband_context.strokeStyle = '#000000';\n\n this._resize_canvas = function (width, height, forward) {\n if (forward) {\n canvas_div.style.width = width + 'px';\n canvas_div.style.height = height + 'px';\n }\n };\n\n // Disable right mouse context menu.\n this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n event.preventDefault();\n return false;\n });\n\n function set_focus() {\n canvas.focus();\n canvas_div.focus();\n }\n\n window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'mpl-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n continue;\n }\n\n var button = (fig.buttons[name] = document.createElement('button'));\n button.classList = 'mpl-widget';\n button.setAttribute('role', 'button');\n button.setAttribute('aria-disabled', 'false');\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n var icon_img = document.createElement('img');\n icon_img.src = '_images/' + image + '.png';\n icon_img.srcset = '_images/' + image + '_large.png 2x';\n icon_img.alt = tooltip;\n button.appendChild(icon_img);\n\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n var fmt_picker = document.createElement('select');\n fmt_picker.classList = 'mpl-widget';\n toolbar.appendChild(fmt_picker);\n this.format_dropdown = fmt_picker;\n\n for (var ind in mpl.extensions) {\n var fmt = mpl.extensions[ind];\n var option = document.createElement('option');\n option.selected = fmt === mpl.default_extension;\n option.innerHTML = fmt;\n fmt_picker.appendChild(option);\n }\n\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n // which will in turn request a refresh of the image.\n this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n properties['type'] = type;\n properties['figure_id'] = this.id;\n this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n if (!this.waiting) {\n this.waiting = true;\n this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n var format_dropdown = fig.format_dropdown;\n var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n var size = msg['size'];\n if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n fig._resize_canvas(size[0], size[1], msg['forward']);\n fig.send_message('refresh', {});\n }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n var x0 = msg['x0'] / fig.ratio;\n var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n var x1 = msg['x1'] / fig.ratio;\n var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n x0 = Math.floor(x0) + 0.5;\n y0 = Math.floor(y0) + 0.5;\n x1 = Math.floor(x1) + 0.5;\n y1 = Math.floor(y1) + 0.5;\n var min_x = Math.min(x0, x1);\n var min_y = Math.min(y0, y1);\n var width = Math.abs(x1 - x0);\n var height = Math.abs(y1 - y0);\n\n fig.rubberband_context.clearRect(\n 0,\n 0,\n fig.canvas.width / fig.ratio,\n fig.canvas.height / fig.ratio\n );\n\n fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n // Updates the figure title.\n fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n var cursor = msg['cursor'];\n switch (cursor) {\n case 0:\n cursor = 'pointer';\n break;\n case 1:\n cursor = 'default';\n break;\n case 2:\n cursor = 'crosshair';\n break;\n case 3:\n cursor = 'move';\n break;\n }\n fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n // Request the server to send over a new figure.\n fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n for (var key in msg) {\n if (!(key in fig.buttons)) {\n continue;\n }\n fig.buttons[key].disabled = !msg[key];\n fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n if (msg['mode'] === 'PAN') {\n fig.buttons['Pan'].classList.add('active');\n fig.buttons['Zoom'].classList.remove('active');\n } else if (msg['mode'] === 'ZOOM') {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.add('active');\n } else {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.remove('active');\n }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Called whenever the canvas gets updated.\n this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n return function socket_on_message(evt) {\n if (evt.data instanceof Blob) {\n /* FIXME: We get \"Resource interpreted as Image but\n * transferred with MIME type text/plain:\" errors on\n * Chrome. But how to set the MIME type? It doesn't seem\n * to be part of the websocket stream */\n evt.data.type = 'image/png';\n\n /* Free the memory for the previous frames */\n if (fig.imageObj.src) {\n (window.URL || window.webkitURL).revokeObjectURL(\n fig.imageObj.src\n );\n }\n\n fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n evt.data\n );\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n } else if (\n typeof evt.data === 'string' &&\n evt.data.slice(0, 21) === 'data:image/png;base64'\n ) {\n fig.imageObj.src = evt.data;\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n }\n\n var msg = JSON.parse(evt.data);\n var msg_type = msg['type'];\n\n // Call the \"handle_{type}\" callback, which takes\n // the figure and JSON message as its only arguments.\n try {\n var callback = fig['handle_' + msg_type];\n } catch (e) {\n console.log(\n \"No handler for the '\" + msg_type + \"' message type: \",\n msg\n );\n return;\n }\n\n if (callback) {\n try {\n // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n callback(fig, msg);\n } catch (e) {\n console.log(\n \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n e,\n e.stack,\n msg\n );\n }\n }\n };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n //this section is from http://www.quirksmode.org/js/events_properties.html\n var targ;\n if (!e) {\n e = window.event;\n }\n if (e.target) {\n targ = e.target;\n } else if (e.srcElement) {\n targ = e.srcElement;\n }\n if (targ.nodeType === 3) {\n // defeat Safari bug\n targ = targ.parentNode;\n }\n\n // pageX,Y are the mouse positions relative to the document\n var boundingRect = targ.getBoundingClientRect();\n var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n return Object.keys(original).reduce(function (obj, key) {\n if (typeof original[key] !== 'object') {\n obj[key] = original[key];\n }\n return obj;\n }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n var canvas_pos = mpl.findpos(event);\n\n if (name === 'button_press') {\n this.canvas.focus();\n this.canvas_div.focus();\n }\n\n var x = canvas_pos.x * this.ratio;\n var y = canvas_pos.y * this.ratio;\n\n this.send_message(name, {\n x: x,\n y: y,\n button: event.button,\n step: event.step,\n guiEvent: simpleKeys(event),\n });\n\n /* This prevents the web browser from automatically changing to\n * the text insertion cursor when the button is pressed. We want\n * to control all of the cursor setting manually through the\n * 'cursor' event from matplotlib */\n event.preventDefault();\n return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n // Prevent repeat events\n if (name === 'key_press') {\n if (event.which === this._key) {\n return;\n } else {\n this._key = event.which;\n }\n }\n if (name === 'key_release') {\n this._key = null;\n }\n\n var value = '';\n if (event.ctrlKey && event.which !== 17) {\n value += 'ctrl+';\n }\n if (event.altKey && event.which !== 18) {\n value += 'alt+';\n }\n if (event.shiftKey && event.which !== 16) {\n value += 'shift+';\n }\n\n value += 'k';\n value += event.which.toString();\n\n this._key_event_extra(event, name);\n\n this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n if (name === 'download') {\n this.handle_save(this, null);\n } else {\n this.send_message('toolbar_button', { name: name });\n }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\nmpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n\nmpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n // Create a \"websocket\"-like object which calls the given IPython comm\n // object with the appropriate methods. Currently this is a non binary\n // socket, so there is still some room for performance tuning.\n var ws = {};\n\n ws.close = function () {\n comm.close();\n };\n ws.send = function (m) {\n //console.log('sending', m);\n comm.send(m);\n };\n // Register the callback with on_msg.\n comm.on_msg(function (msg) {\n //console.log('receiving', msg['content']['data'], msg);\n // Pass the mpl event to the overridden (by mpl) onmessage function.\n ws.onmessage(msg['content']['data']);\n });\n return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n // This is the function which gets called when the mpl process\n // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n var id = msg.content.data.id;\n // Get hold of the div created by the display call when the Comm\n // socket was opened in Python.\n var element = document.getElementById(id);\n var ws_proxy = comm_websocket_adapter(comm);\n\n function ondownload(figure, _format) {\n window.open(figure.canvas.toDataURL());\n }\n\n var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n // web socket which is closed, not our websocket->open comm proxy.\n ws_proxy.onopen();\n\n fig.parent_element = element;\n fig.cell_info = mpl.find_output_cell(\"
\");\n if (!fig.cell_info) {\n console.error('Failed to find cell for figure', id, fig);\n return;\n }\n fig.cell_info[0].output_area.element.on(\n 'cleared',\n { fig: fig },\n fig._remove_fig_handler\n );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n var width = fig.canvas.width / fig.ratio;\n fig.cell_info[0].output_area.element.off(\n 'cleared',\n fig._remove_fig_handler\n );\n fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n // Update the output cell to use the data from the current canvas.\n fig.push_to_output();\n var dataURL = fig.canvas.toDataURL();\n // Re-enable the keyboard manager in IPython - without this line, in FF,\n // the notebook keyboard shortcuts fail.\n IPython.keyboard_manager.enable();\n fig.parent_element.innerHTML =\n '';\n fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n fig.send_message('closing', msg);\n // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n // Turn the data on the canvas into data in the output cell.\n var width = this.canvas.width / this.ratio;\n var dataURL = this.canvas.toDataURL();\n this.cell_info[1]['text/html'] =\n '';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Tell IPython that the notebook contents must change.\n IPython.notebook.set_dirty(true);\n this.send_message('ack', {});\n var fig = this;\n // Wait a second, then push the new image to the DOM so\n // that it is saved nicely (might be nice to debounce this).\n setTimeout(function () {\n fig.push_to_output();\n }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'btn-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n var button;\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n continue;\n }\n\n button = fig.buttons[name] = document.createElement('button');\n button.classList = 'btn btn-default';\n button.href = '#';\n button.title = name;\n button.innerHTML = '';\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n // Add the status bar.\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message pull-right';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n\n // Add the close button to the window.\n var buttongrp = document.createElement('div');\n buttongrp.classList = 'btn-group inline pull-right';\n button = document.createElement('button');\n button.classList = 'btn btn-mini btn-primary';\n button.href = '#';\n button.title = 'Stop Interaction';\n button.innerHTML = '';\n button.addEventListener('click', function (_evt) {\n fig.handle_close(fig, {});\n });\n button.addEventListener(\n 'mouseover',\n on_mouseover_closure('Stop Interaction')\n );\n buttongrp.appendChild(button);\n var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n var fig = event.data.fig;\n if (event.target !== this) {\n // Ignore bubbled events from children.\n return;\n }\n fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n // this is important to make the div 'focusable\n el.setAttribute('tabindex', 0);\n // reach out to IPython and tell the keyboard manager to turn it's self\n // off when our div gets focus\n\n // location in version 3\n if (IPython.notebook.keyboard_manager) {\n IPython.notebook.keyboard_manager.register_events(el);\n } else {\n // location in version 2\n IPython.keyboard_manager.register_events(el);\n }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n var manager = IPython.notebook.keyboard_manager;\n if (!manager) {\n manager = IPython.keyboard_manager;\n }\n\n // Check for shift+enter\n if (event.shiftKey && event.which === 13) {\n this.canvas_div.blur();\n // select the cell after this one\n var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n IPython.notebook.select(index + 1);\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n // Return the cell and output element which can be found *uniquely* in the notebook.\n // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n // IPython event is triggered only after the cells have been serialised, which for\n // our purposes (turning an active figure into a static one), is too late.\n var cells = IPython.notebook.get_cells();\n var ncells = cells.length;\n for (var i = 0; i < ncells; i++) {\n var cell = cells[i];\n if (cell.cell_type === 'code') {\n for (var j = 0; j < cell.output_area.outputs.length; j++) {\n var data = cell.output_area.outputs[j];\n if (data.data) {\n // IPython >= 3 moved mimebundle to data attribute of output\n data = data.data;\n }\n if (data['text/html'] === html_output) {\n return [cell, data, j];\n }\n }\n }\n }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n IPython.notebook.kernel.comm_manager.register_target(\n 'matplotlib',\n mpl.mpl_figure_comm\n );\n}\n", "text/plain": [ "" ] @@ -14882,955 +1610,7 @@ }, { "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "/* global mpl */\n", - "window.mpl = {};\n", - "\n", - "mpl.get_websocket_type = function () {\n", - " if (typeof WebSocket !== 'undefined') {\n", - " return WebSocket;\n", - " } else if (typeof MozWebSocket !== 'undefined') {\n", - " return MozWebSocket;\n", - " } else {\n", - " alert(\n", - " 'Your browser does not have WebSocket support. ' +\n", - " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", - " 'Firefox 4 and 5 are also supported but you ' +\n", - " 'have to enable WebSockets in about:config.'\n", - " );\n", - " }\n", - "};\n", - "\n", - "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", - " this.id = figure_id;\n", - "\n", - " this.ws = websocket;\n", - "\n", - " this.supports_binary = this.ws.binaryType !== undefined;\n", - "\n", - " if (!this.supports_binary) {\n", - " var warnings = document.getElementById('mpl-warnings');\n", - " if (warnings) {\n", - " warnings.style.display = 'block';\n", - " warnings.textContent =\n", - " 'This browser does not support binary websocket messages. ' +\n", - " 'Performance may be slow.';\n", - " }\n", - " }\n", - "\n", - " this.imageObj = new Image();\n", - "\n", - " this.context = undefined;\n", - " this.message = undefined;\n", - " this.canvas = undefined;\n", - " this.rubberband_canvas = undefined;\n", - " this.rubberband_context = undefined;\n", - " this.format_dropdown = undefined;\n", - "\n", - " this.image_mode = 'full';\n", - "\n", - " this.root = document.createElement('div');\n", - " this.root.setAttribute('style', 'display: inline-block');\n", - " this._root_extra_style(this.root);\n", - "\n", - " parent_element.appendChild(this.root);\n", - "\n", - " this._init_header(this);\n", - " this._init_canvas(this);\n", - " this._init_toolbar(this);\n", - "\n", - " var fig = this;\n", - "\n", - " this.waiting = false;\n", - "\n", - " this.ws.onopen = function () {\n", - " fig.send_message('supports_binary', { value: fig.supports_binary });\n", - " fig.send_message('send_image_mode', {});\n", - " if (fig.ratio !== 1) {\n", - " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", - " }\n", - " fig.send_message('refresh', {});\n", - " };\n", - "\n", - " this.imageObj.onload = function () {\n", - " if (fig.image_mode === 'full') {\n", - " // Full images could contain transparency (where diff images\n", - " // almost always do), so we need to clear the canvas so that\n", - " // there is no ghosting.\n", - " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", - " }\n", - " fig.context.drawImage(fig.imageObj, 0, 0);\n", - " };\n", - "\n", - " this.imageObj.onunload = function () {\n", - " fig.ws.close();\n", - " };\n", - "\n", - " this.ws.onmessage = this._make_on_message_function(this);\n", - "\n", - " this.ondownload = ondownload;\n", - "};\n", - "\n", - "mpl.figure.prototype._init_header = function () {\n", - " var titlebar = document.createElement('div');\n", - " titlebar.classList =\n", - " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", - " var titletext = document.createElement('div');\n", - " titletext.classList = 'ui-dialog-title';\n", - " titletext.setAttribute(\n", - " 'style',\n", - " 'width: 100%; text-align: center; padding: 3px;'\n", - " );\n", - " titlebar.appendChild(titletext);\n", - " this.root.appendChild(titlebar);\n", - " this.header = titletext;\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._init_canvas = function () {\n", - " var fig = this;\n", - "\n", - " var canvas_div = (this.canvas_div = document.createElement('div'));\n", - " canvas_div.setAttribute(\n", - " 'style',\n", - " 'border: 1px solid #ddd;' +\n", - " 'box-sizing: content-box;' +\n", - " 'clear: both;' +\n", - " 'min-height: 1px;' +\n", - " 'min-width: 1px;' +\n", - " 'outline: 0;' +\n", - " 'overflow: hidden;' +\n", - " 'position: relative;' +\n", - " 'resize: both;'\n", - " );\n", - "\n", - " function on_keyboard_event_closure(name) {\n", - " return function (event) {\n", - " return fig.key_event(event, name);\n", - " };\n", - " }\n", - "\n", - " canvas_div.addEventListener(\n", - " 'keydown',\n", - " on_keyboard_event_closure('key_press')\n", - " );\n", - " canvas_div.addEventListener(\n", - " 'keyup',\n", - " on_keyboard_event_closure('key_release')\n", - " );\n", - "\n", - " this._canvas_extra_style(canvas_div);\n", - " this.root.appendChild(canvas_div);\n", - "\n", - " var canvas = (this.canvas = document.createElement('canvas'));\n", - " canvas.classList.add('mpl-canvas');\n", - " canvas.setAttribute('style', 'box-sizing: content-box;');\n", - "\n", - " this.context = canvas.getContext('2d');\n", - "\n", - " var backingStore =\n", - " this.context.backingStorePixelRatio ||\n", - " this.context.webkitBackingStorePixelRatio ||\n", - " this.context.mozBackingStorePixelRatio ||\n", - " this.context.msBackingStorePixelRatio ||\n", - " this.context.oBackingStorePixelRatio ||\n", - " this.context.backingStorePixelRatio ||\n", - " 1;\n", - "\n", - " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", - "\n", - " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", - " 'canvas'\n", - " ));\n", - " rubberband_canvas.setAttribute(\n", - " 'style',\n", - " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", - " );\n", - "\n", - " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", - " if (this.ResizeObserver === undefined) {\n", - " if (window.ResizeObserver !== undefined) {\n", - " this.ResizeObserver = window.ResizeObserver;\n", - " } else {\n", - " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", - " this.ResizeObserver = obs.ResizeObserver;\n", - " }\n", - " }\n", - "\n", - " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", - " var nentries = entries.length;\n", - " for (var i = 0; i < nentries; i++) {\n", - " var entry = entries[i];\n", - " var width, height;\n", - " if (entry.contentBoxSize) {\n", - " if (entry.contentBoxSize instanceof Array) {\n", - " // Chrome 84 implements new version of spec.\n", - " width = entry.contentBoxSize[0].inlineSize;\n", - " height = entry.contentBoxSize[0].blockSize;\n", - " } else {\n", - " // Firefox implements old version of spec.\n", - " width = entry.contentBoxSize.inlineSize;\n", - " height = entry.contentBoxSize.blockSize;\n", - " }\n", - " } else {\n", - " // Chrome <84 implements even older version of spec.\n", - " width = entry.contentRect.width;\n", - " height = entry.contentRect.height;\n", - " }\n", - "\n", - " // Keep the size of the canvas and rubber band canvas in sync with\n", - " // the canvas container.\n", - " if (entry.devicePixelContentBoxSize) {\n", - " // Chrome 84 implements new version of spec.\n", - " canvas.setAttribute(\n", - " 'width',\n", - " entry.devicePixelContentBoxSize[0].inlineSize\n", - " );\n", - " canvas.setAttribute(\n", - " 'height',\n", - " entry.devicePixelContentBoxSize[0].blockSize\n", - " );\n", - " } else {\n", - " canvas.setAttribute('width', width * fig.ratio);\n", - " canvas.setAttribute('height', height * fig.ratio);\n", - " }\n", - " canvas.setAttribute(\n", - " 'style',\n", - " 'width: ' + width + 'px; height: ' + height + 'px;'\n", - " );\n", - "\n", - " rubberband_canvas.setAttribute('width', width);\n", - " rubberband_canvas.setAttribute('height', height);\n", - "\n", - " // And update the size in Python. We ignore the initial 0/0 size\n", - " // that occurs as the element is placed into the DOM, which should\n", - " // otherwise not happen due to the minimum size styling.\n", - " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", - " fig.request_resize(width, height);\n", - " }\n", - " }\n", - " });\n", - " this.resizeObserverInstance.observe(canvas_div);\n", - "\n", - " function on_mouse_event_closure(name) {\n", - " return function (event) {\n", - " return fig.mouse_event(event, name);\n", - " };\n", - " }\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mousedown',\n", - " on_mouse_event_closure('button_press')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseup',\n", - " on_mouse_event_closure('button_release')\n", - " );\n", - " // Throttle sequential mouse events to 1 every 20ms.\n", - " rubberband_canvas.addEventListener(\n", - " 'mousemove',\n", - " on_mouse_event_closure('motion_notify')\n", - " );\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseenter',\n", - " on_mouse_event_closure('figure_enter')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseleave',\n", - " on_mouse_event_closure('figure_leave')\n", - " );\n", - "\n", - " canvas_div.addEventListener('wheel', function (event) {\n", - " if (event.deltaY < 0) {\n", - " event.step = 1;\n", - " } else {\n", - " event.step = -1;\n", - " }\n", - " on_mouse_event_closure('scroll')(event);\n", - " });\n", - "\n", - " canvas_div.appendChild(canvas);\n", - " canvas_div.appendChild(rubberband_canvas);\n", - "\n", - " this.rubberband_context = rubberband_canvas.getContext('2d');\n", - " this.rubberband_context.strokeStyle = '#000000';\n", - "\n", - " this._resize_canvas = function (width, height, forward) {\n", - " if (forward) {\n", - " canvas_div.style.width = width + 'px';\n", - " canvas_div.style.height = height + 'px';\n", - " }\n", - " };\n", - "\n", - " // Disable right mouse context menu.\n", - " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", - " event.preventDefault();\n", - " return false;\n", - " });\n", - "\n", - " function set_focus() {\n", - " canvas.focus();\n", - " canvas_div.focus();\n", - " }\n", - "\n", - " window.setTimeout(set_focus, 100);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'mpl-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " continue;\n", - " }\n", - "\n", - " var button = (fig.buttons[name] = document.createElement('button'));\n", - " button.classList = 'mpl-widget';\n", - " button.setAttribute('role', 'button');\n", - " button.setAttribute('aria-disabled', 'false');\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - "\n", - " var icon_img = document.createElement('img');\n", - " icon_img.src = '_images/' + image + '.png';\n", - " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", - " icon_img.alt = tooltip;\n", - " button.appendChild(icon_img);\n", - "\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " var fmt_picker = document.createElement('select');\n", - " fmt_picker.classList = 'mpl-widget';\n", - " toolbar.appendChild(fmt_picker);\n", - " this.format_dropdown = fmt_picker;\n", - "\n", - " for (var ind in mpl.extensions) {\n", - " var fmt = mpl.extensions[ind];\n", - " var option = document.createElement('option');\n", - " option.selected = fmt === mpl.default_extension;\n", - " option.innerHTML = fmt;\n", - " fmt_picker.appendChild(option);\n", - " }\n", - "\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "};\n", - "\n", - "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", - " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", - " // which will in turn request a refresh of the image.\n", - " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", - "};\n", - "\n", - "mpl.figure.prototype.send_message = function (type, properties) {\n", - " properties['type'] = type;\n", - " properties['figure_id'] = this.id;\n", - " this.ws.send(JSON.stringify(properties));\n", - "};\n", - "\n", - "mpl.figure.prototype.send_draw_message = function () {\n", - " if (!this.waiting) {\n", - " this.waiting = true;\n", - " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " var format_dropdown = fig.format_dropdown;\n", - " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", - " fig.ondownload(fig, format);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", - " var size = msg['size'];\n", - " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", - " fig._resize_canvas(size[0], size[1], msg['forward']);\n", - " fig.send_message('refresh', {});\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", - " var x0 = msg['x0'] / fig.ratio;\n", - " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", - " var x1 = msg['x1'] / fig.ratio;\n", - " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", - " x0 = Math.floor(x0) + 0.5;\n", - " y0 = Math.floor(y0) + 0.5;\n", - " x1 = Math.floor(x1) + 0.5;\n", - " y1 = Math.floor(y1) + 0.5;\n", - " var min_x = Math.min(x0, x1);\n", - " var min_y = Math.min(y0, y1);\n", - " var width = Math.abs(x1 - x0);\n", - " var height = Math.abs(y1 - y0);\n", - "\n", - " fig.rubberband_context.clearRect(\n", - " 0,\n", - " 0,\n", - " fig.canvas.width / fig.ratio,\n", - " fig.canvas.height / fig.ratio\n", - " );\n", - "\n", - " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", - " // Updates the figure title.\n", - " fig.header.textContent = msg['label'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", - " var cursor = msg['cursor'];\n", - " switch (cursor) {\n", - " case 0:\n", - " cursor = 'pointer';\n", - " break;\n", - " case 1:\n", - " cursor = 'default';\n", - " break;\n", - " case 2:\n", - " cursor = 'crosshair';\n", - " break;\n", - " case 3:\n", - " cursor = 'move';\n", - " break;\n", - " }\n", - " fig.rubberband_canvas.style.cursor = cursor;\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_message = function (fig, msg) {\n", - " fig.message.textContent = msg['message'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", - " // Request the server to send over a new figure.\n", - " fig.send_draw_message();\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", - " fig.image_mode = msg['mode'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", - " for (var key in msg) {\n", - " if (!(key in fig.buttons)) {\n", - " continue;\n", - " }\n", - " fig.buttons[key].disabled = !msg[key];\n", - " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", - " if (msg['mode'] === 'PAN') {\n", - " fig.buttons['Pan'].classList.add('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " } else if (msg['mode'] === 'ZOOM') {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.add('active');\n", - " } else {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Called whenever the canvas gets updated.\n", - " this.send_message('ack', {});\n", - "};\n", - "\n", - "// A function to construct a web socket function for onmessage handling.\n", - "// Called in the figure constructor.\n", - "mpl.figure.prototype._make_on_message_function = function (fig) {\n", - " return function socket_on_message(evt) {\n", - " if (evt.data instanceof Blob) {\n", - " /* FIXME: We get \"Resource interpreted as Image but\n", - " * transferred with MIME type text/plain:\" errors on\n", - " * Chrome. But how to set the MIME type? It doesn't seem\n", - " * to be part of the websocket stream */\n", - " evt.data.type = 'image/png';\n", - "\n", - " /* Free the memory for the previous frames */\n", - " if (fig.imageObj.src) {\n", - " (window.URL || window.webkitURL).revokeObjectURL(\n", - " fig.imageObj.src\n", - " );\n", - " }\n", - "\n", - " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", - " evt.data\n", - " );\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " } else if (\n", - " typeof evt.data === 'string' &&\n", - " evt.data.slice(0, 21) === 'data:image/png;base64'\n", - " ) {\n", - " fig.imageObj.src = evt.data;\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " }\n", - "\n", - " var msg = JSON.parse(evt.data);\n", - " var msg_type = msg['type'];\n", - "\n", - " // Call the \"handle_{type}\" callback, which takes\n", - " // the figure and JSON message as its only arguments.\n", - " try {\n", - " var callback = fig['handle_' + msg_type];\n", - " } catch (e) {\n", - " console.log(\n", - " \"No handler for the '\" + msg_type + \"' message type: \",\n", - " msg\n", - " );\n", - " return;\n", - " }\n", - "\n", - " if (callback) {\n", - " try {\n", - " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", - " callback(fig, msg);\n", - " } catch (e) {\n", - " console.log(\n", - " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", - " e,\n", - " e.stack,\n", - " msg\n", - " );\n", - " }\n", - " }\n", - " };\n", - "};\n", - "\n", - "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", - "mpl.findpos = function (e) {\n", - " //this section is from http://www.quirksmode.org/js/events_properties.html\n", - " var targ;\n", - " if (!e) {\n", - " e = window.event;\n", - " }\n", - " if (e.target) {\n", - " targ = e.target;\n", - " } else if (e.srcElement) {\n", - " targ = e.srcElement;\n", - " }\n", - " if (targ.nodeType === 3) {\n", - " // defeat Safari bug\n", - " targ = targ.parentNode;\n", - " }\n", - "\n", - " // pageX,Y are the mouse positions relative to the document\n", - " var boundingRect = targ.getBoundingClientRect();\n", - " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", - " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", - "\n", - " return { x: x, y: y };\n", - "};\n", - "\n", - "/*\n", - " * return a copy of an object with only non-object keys\n", - " * we need this to avoid circular references\n", - " * http://stackoverflow.com/a/24161582/3208463\n", - " */\n", - "function simpleKeys(original) {\n", - " return Object.keys(original).reduce(function (obj, key) {\n", - " if (typeof original[key] !== 'object') {\n", - " obj[key] = original[key];\n", - " }\n", - " return obj;\n", - " }, {});\n", - "}\n", - "\n", - "mpl.figure.prototype.mouse_event = function (event, name) {\n", - " var canvas_pos = mpl.findpos(event);\n", - "\n", - " if (name === 'button_press') {\n", - " this.canvas.focus();\n", - " this.canvas_div.focus();\n", - " }\n", - "\n", - " var x = canvas_pos.x * this.ratio;\n", - " var y = canvas_pos.y * this.ratio;\n", - "\n", - " this.send_message(name, {\n", - " x: x,\n", - " y: y,\n", - " button: event.button,\n", - " step: event.step,\n", - " guiEvent: simpleKeys(event),\n", - " });\n", - "\n", - " /* This prevents the web browser from automatically changing to\n", - " * the text insertion cursor when the button is pressed. We want\n", - " * to control all of the cursor setting manually through the\n", - " * 'cursor' event from matplotlib */\n", - " event.preventDefault();\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", - " // Handle any extra behaviour associated with a key event\n", - "};\n", - "\n", - "mpl.figure.prototype.key_event = function (event, name) {\n", - " // Prevent repeat events\n", - " if (name === 'key_press') {\n", - " if (event.which === this._key) {\n", - " return;\n", - " } else {\n", - " this._key = event.which;\n", - " }\n", - " }\n", - " if (name === 'key_release') {\n", - " this._key = null;\n", - " }\n", - "\n", - " var value = '';\n", - " if (event.ctrlKey && event.which !== 17) {\n", - " value += 'ctrl+';\n", - " }\n", - " if (event.altKey && event.which !== 18) {\n", - " value += 'alt+';\n", - " }\n", - " if (event.shiftKey && event.which !== 16) {\n", - " value += 'shift+';\n", - " }\n", - "\n", - " value += 'k';\n", - " value += event.which.toString();\n", - "\n", - " this._key_event_extra(event, name);\n", - "\n", - " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", - " if (name === 'download') {\n", - " this.handle_save(this, null);\n", - " } else {\n", - " this.send_message('toolbar_button', { name: name });\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", - " this.message.textContent = tooltip;\n", - "};\n", - "\n", - "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", - "// prettier-ignore\n", - "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", - "\n", - "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", - "\n", - "mpl.default_extension = \"png\";/* global mpl */\n", - "\n", - "var comm_websocket_adapter = function (comm) {\n", - " // Create a \"websocket\"-like object which calls the given IPython comm\n", - " // object with the appropriate methods. Currently this is a non binary\n", - " // socket, so there is still some room for performance tuning.\n", - " var ws = {};\n", - "\n", - " ws.close = function () {\n", - " comm.close();\n", - " };\n", - " ws.send = function (m) {\n", - " //console.log('sending', m);\n", - " comm.send(m);\n", - " };\n", - " // Register the callback with on_msg.\n", - " comm.on_msg(function (msg) {\n", - " //console.log('receiving', msg['content']['data'], msg);\n", - " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", - " ws.onmessage(msg['content']['data']);\n", - " });\n", - " return ws;\n", - "};\n", - "\n", - "mpl.mpl_figure_comm = function (comm, msg) {\n", - " // This is the function which gets called when the mpl process\n", - " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", - "\n", - " var id = msg.content.data.id;\n", - " // Get hold of the div created by the display call when the Comm\n", - " // socket was opened in Python.\n", - " var element = document.getElementById(id);\n", - " var ws_proxy = comm_websocket_adapter(comm);\n", - "\n", - " function ondownload(figure, _format) {\n", - " window.open(figure.canvas.toDataURL());\n", - " }\n", - "\n", - " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", - "\n", - " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", - " // web socket which is closed, not our websocket->open comm proxy.\n", - " ws_proxy.onopen();\n", - "\n", - " fig.parent_element = element;\n", - " fig.cell_info = mpl.find_output_cell(\"
\");\n", - " if (!fig.cell_info) {\n", - " console.error('Failed to find cell for figure', id, fig);\n", - " return;\n", - " }\n", - " fig.cell_info[0].output_area.element.on(\n", - " 'cleared',\n", - " { fig: fig },\n", - " fig._remove_fig_handler\n", - " );\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_close = function (fig, msg) {\n", - " var width = fig.canvas.width / fig.ratio;\n", - " fig.cell_info[0].output_area.element.off(\n", - " 'cleared',\n", - " fig._remove_fig_handler\n", - " );\n", - " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", - "\n", - " // Update the output cell to use the data from the current canvas.\n", - " fig.push_to_output();\n", - " var dataURL = fig.canvas.toDataURL();\n", - " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", - " // the notebook keyboard shortcuts fail.\n", - " IPython.keyboard_manager.enable();\n", - " fig.parent_element.innerHTML =\n", - " '';\n", - " fig.close_ws(fig, msg);\n", - "};\n", - "\n", - "mpl.figure.prototype.close_ws = function (fig, msg) {\n", - " fig.send_message('closing', msg);\n", - " // fig.ws.close()\n", - "};\n", - "\n", - "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", - " // Turn the data on the canvas into data in the output cell.\n", - " var width = this.canvas.width / this.ratio;\n", - " var dataURL = this.canvas.toDataURL();\n", - " this.cell_info[1]['text/html'] =\n", - " '';\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Tell IPython that the notebook contents must change.\n", - " IPython.notebook.set_dirty(true);\n", - " this.send_message('ack', {});\n", - " var fig = this;\n", - " // Wait a second, then push the new image to the DOM so\n", - " // that it is saved nicely (might be nice to debounce this).\n", - " setTimeout(function () {\n", - " fig.push_to_output();\n", - " }, 1000);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'btn-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " var button;\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " continue;\n", - " }\n", - "\n", - " button = fig.buttons[name] = document.createElement('button');\n", - " button.classList = 'btn btn-default';\n", - " button.href = '#';\n", - " button.title = name;\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " // Add the status bar.\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message pull-right';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "\n", - " // Add the close button to the window.\n", - " var buttongrp = document.createElement('div');\n", - " buttongrp.classList = 'btn-group inline pull-right';\n", - " button = document.createElement('button');\n", - " button.classList = 'btn btn-mini btn-primary';\n", - " button.href = '#';\n", - " button.title = 'Stop Interaction';\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', function (_evt) {\n", - " fig.handle_close(fig, {});\n", - " });\n", - " button.addEventListener(\n", - " 'mouseover',\n", - " on_mouseover_closure('Stop Interaction')\n", - " );\n", - " buttongrp.appendChild(button);\n", - " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", - " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", - "};\n", - "\n", - "mpl.figure.prototype._remove_fig_handler = function (event) {\n", - " var fig = event.data.fig;\n", - " if (event.target !== this) {\n", - " // Ignore bubbled events from children.\n", - " return;\n", - " }\n", - " fig.close_ws(fig, {});\n", - "};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (el) {\n", - " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (el) {\n", - " // this is important to make the div 'focusable\n", - " el.setAttribute('tabindex', 0);\n", - " // reach out to IPython and tell the keyboard manager to turn it's self\n", - " // off when our div gets focus\n", - "\n", - " // location in version 3\n", - " if (IPython.notebook.keyboard_manager) {\n", - " IPython.notebook.keyboard_manager.register_events(el);\n", - " } else {\n", - " // location in version 2\n", - " IPython.keyboard_manager.register_events(el);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", - " var manager = IPython.notebook.keyboard_manager;\n", - " if (!manager) {\n", - " manager = IPython.keyboard_manager;\n", - " }\n", - "\n", - " // Check for shift+enter\n", - " if (event.shiftKey && event.which === 13) {\n", - " this.canvas_div.blur();\n", - " // select the cell after this one\n", - " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", - " IPython.notebook.select(index + 1);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " fig.ondownload(fig, null);\n", - "};\n", - "\n", - "mpl.find_output_cell = function (html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i = 0; i < ncells; i++) {\n", - " var cell = cells[i];\n", - " if (cell.cell_type === 'code') {\n", - " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", - " var data = cell.output_area.outputs[j];\n", - " if (data.data) {\n", - " // IPython >= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] === html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "};\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel !== null) {\n", - " IPython.notebook.kernel.comm_manager.register_target(\n", - " 'matplotlib',\n", - " mpl.mpl_figure_comm\n", - " );\n", - "}\n" - ], + "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n if (typeof WebSocket !== 'undefined') {\n return WebSocket;\n } else if (typeof MozWebSocket !== 'undefined') {\n return MozWebSocket;\n } else {\n alert(\n 'Your browser does not have WebSocket support. ' +\n 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n 'Firefox 4 and 5 are also supported but you ' +\n 'have to enable WebSockets in about:config.'\n );\n }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n this.id = figure_id;\n\n this.ws = websocket;\n\n this.supports_binary = this.ws.binaryType !== undefined;\n\n if (!this.supports_binary) {\n var warnings = document.getElementById('mpl-warnings');\n if (warnings) {\n warnings.style.display = 'block';\n warnings.textContent =\n 'This browser does not support binary websocket messages. ' +\n 'Performance may be slow.';\n }\n }\n\n this.imageObj = new Image();\n\n this.context = undefined;\n this.message = undefined;\n this.canvas = undefined;\n this.rubberband_canvas = undefined;\n this.rubberband_context = undefined;\n this.format_dropdown = undefined;\n\n this.image_mode = 'full';\n\n this.root = document.createElement('div');\n this.root.setAttribute('style', 'display: inline-block');\n this._root_extra_style(this.root);\n\n parent_element.appendChild(this.root);\n\n this._init_header(this);\n this._init_canvas(this);\n this._init_toolbar(this);\n\n var fig = this;\n\n this.waiting = false;\n\n this.ws.onopen = function () {\n fig.send_message('supports_binary', { value: fig.supports_binary });\n fig.send_message('send_image_mode', {});\n if (fig.ratio !== 1) {\n fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n }\n fig.send_message('refresh', {});\n };\n\n this.imageObj.onload = function () {\n if (fig.image_mode === 'full') {\n // Full images could contain transparency (where diff images\n // almost always do), so we need to clear the canvas so that\n // there is no ghosting.\n fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n }\n fig.context.drawImage(fig.imageObj, 0, 0);\n };\n\n this.imageObj.onunload = function () {\n fig.ws.close();\n };\n\n this.ws.onmessage = this._make_on_message_function(this);\n\n this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n var titlebar = document.createElement('div');\n titlebar.classList =\n 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n var titletext = document.createElement('div');\n titletext.classList = 'ui-dialog-title';\n titletext.setAttribute(\n 'style',\n 'width: 100%; text-align: center; padding: 3px;'\n );\n titlebar.appendChild(titletext);\n this.root.appendChild(titlebar);\n this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n var fig = this;\n\n var canvas_div = (this.canvas_div = document.createElement('div'));\n canvas_div.setAttribute(\n 'style',\n 'border: 1px solid #ddd;' +\n 'box-sizing: content-box;' +\n 'clear: both;' +\n 'min-height: 1px;' +\n 'min-width: 1px;' +\n 'outline: 0;' +\n 'overflow: hidden;' +\n 'position: relative;' +\n 'resize: both;'\n );\n\n function on_keyboard_event_closure(name) {\n return function (event) {\n return fig.key_event(event, name);\n };\n }\n\n canvas_div.addEventListener(\n 'keydown',\n on_keyboard_event_closure('key_press')\n );\n canvas_div.addEventListener(\n 'keyup',\n on_keyboard_event_closure('key_release')\n );\n\n this._canvas_extra_style(canvas_div);\n this.root.appendChild(canvas_div);\n\n var canvas = (this.canvas = document.createElement('canvas'));\n canvas.classList.add('mpl-canvas');\n canvas.setAttribute('style', 'box-sizing: content-box;');\n\n this.context = canvas.getContext('2d');\n\n var backingStore =\n this.context.backingStorePixelRatio ||\n this.context.webkitBackingStorePixelRatio ||\n this.context.mozBackingStorePixelRatio ||\n this.context.msBackingStorePixelRatio ||\n this.context.oBackingStorePixelRatio ||\n this.context.backingStorePixelRatio ||\n 1;\n\n this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n 'canvas'\n ));\n rubberband_canvas.setAttribute(\n 'style',\n 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n );\n\n // Apply a ponyfill if ResizeObserver is not implemented by browser.\n if (this.ResizeObserver === undefined) {\n if (window.ResizeObserver !== undefined) {\n this.ResizeObserver = window.ResizeObserver;\n } else {\n var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n this.ResizeObserver = obs.ResizeObserver;\n }\n }\n\n this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n var nentries = entries.length;\n for (var i = 0; i < nentries; i++) {\n var entry = entries[i];\n var width, height;\n if (entry.contentBoxSize) {\n if (entry.contentBoxSize instanceof Array) {\n // Chrome 84 implements new version of spec.\n width = entry.contentBoxSize[0].inlineSize;\n height = entry.contentBoxSize[0].blockSize;\n } else {\n // Firefox implements old version of spec.\n width = entry.contentBoxSize.inlineSize;\n height = entry.contentBoxSize.blockSize;\n }\n } else {\n // Chrome <84 implements even older version of spec.\n width = entry.contentRect.width;\n height = entry.contentRect.height;\n }\n\n // Keep the size of the canvas and rubber band canvas in sync with\n // the canvas container.\n if (entry.devicePixelContentBoxSize) {\n // Chrome 84 implements new version of spec.\n canvas.setAttribute(\n 'width',\n entry.devicePixelContentBoxSize[0].inlineSize\n );\n canvas.setAttribute(\n 'height',\n entry.devicePixelContentBoxSize[0].blockSize\n );\n } else {\n canvas.setAttribute('width', width * fig.ratio);\n canvas.setAttribute('height', height * fig.ratio);\n }\n canvas.setAttribute(\n 'style',\n 'width: ' + width + 'px; height: ' + height + 'px;'\n );\n\n rubberband_canvas.setAttribute('width', width);\n rubberband_canvas.setAttribute('height', height);\n\n // And update the size in Python. We ignore the initial 0/0 size\n // that occurs as the element is placed into the DOM, which should\n // otherwise not happen due to the minimum size styling.\n if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n fig.request_resize(width, height);\n }\n }\n });\n this.resizeObserverInstance.observe(canvas_div);\n\n function on_mouse_event_closure(name) {\n return function (event) {\n return fig.mouse_event(event, name);\n };\n }\n\n rubberband_canvas.addEventListener(\n 'mousedown',\n on_mouse_event_closure('button_press')\n );\n rubberband_canvas.addEventListener(\n 'mouseup',\n on_mouse_event_closure('button_release')\n );\n // Throttle sequential mouse events to 1 every 20ms.\n rubberband_canvas.addEventListener(\n 'mousemove',\n on_mouse_event_closure('motion_notify')\n );\n\n rubberband_canvas.addEventListener(\n 'mouseenter',\n on_mouse_event_closure('figure_enter')\n );\n rubberband_canvas.addEventListener(\n 'mouseleave',\n on_mouse_event_closure('figure_leave')\n );\n\n canvas_div.addEventListener('wheel', function (event) {\n if (event.deltaY < 0) {\n event.step = 1;\n } else {\n event.step = -1;\n }\n on_mouse_event_closure('scroll')(event);\n });\n\n canvas_div.appendChild(canvas);\n canvas_div.appendChild(rubberband_canvas);\n\n this.rubberband_context = rubberband_canvas.getContext('2d');\n this.rubberband_context.strokeStyle = '#000000';\n\n this._resize_canvas = function (width, height, forward) {\n if (forward) {\n canvas_div.style.width = width + 'px';\n canvas_div.style.height = height + 'px';\n }\n };\n\n // Disable right mouse context menu.\n this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n event.preventDefault();\n return false;\n });\n\n function set_focus() {\n canvas.focus();\n canvas_div.focus();\n }\n\n window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'mpl-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n continue;\n }\n\n var button = (fig.buttons[name] = document.createElement('button'));\n button.classList = 'mpl-widget';\n button.setAttribute('role', 'button');\n button.setAttribute('aria-disabled', 'false');\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n var icon_img = document.createElement('img');\n icon_img.src = '_images/' + image + '.png';\n icon_img.srcset = '_images/' + image + '_large.png 2x';\n icon_img.alt = tooltip;\n button.appendChild(icon_img);\n\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n var fmt_picker = document.createElement('select');\n fmt_picker.classList = 'mpl-widget';\n toolbar.appendChild(fmt_picker);\n this.format_dropdown = fmt_picker;\n\n for (var ind in mpl.extensions) {\n var fmt = mpl.extensions[ind];\n var option = document.createElement('option');\n option.selected = fmt === mpl.default_extension;\n option.innerHTML = fmt;\n fmt_picker.appendChild(option);\n }\n\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n // which will in turn request a refresh of the image.\n this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n properties['type'] = type;\n properties['figure_id'] = this.id;\n this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n if (!this.waiting) {\n this.waiting = true;\n this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n var format_dropdown = fig.format_dropdown;\n var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n var size = msg['size'];\n if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n fig._resize_canvas(size[0], size[1], msg['forward']);\n fig.send_message('refresh', {});\n }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n var x0 = msg['x0'] / fig.ratio;\n var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n var x1 = msg['x1'] / fig.ratio;\n var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n x0 = Math.floor(x0) + 0.5;\n y0 = Math.floor(y0) + 0.5;\n x1 = Math.floor(x1) + 0.5;\n y1 = Math.floor(y1) + 0.5;\n var min_x = Math.min(x0, x1);\n var min_y = Math.min(y0, y1);\n var width = Math.abs(x1 - x0);\n var height = Math.abs(y1 - y0);\n\n fig.rubberband_context.clearRect(\n 0,\n 0,\n fig.canvas.width / fig.ratio,\n fig.canvas.height / fig.ratio\n );\n\n fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n // Updates the figure title.\n fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n var cursor = msg['cursor'];\n switch (cursor) {\n case 0:\n cursor = 'pointer';\n break;\n case 1:\n cursor = 'default';\n break;\n case 2:\n cursor = 'crosshair';\n break;\n case 3:\n cursor = 'move';\n break;\n }\n fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n // Request the server to send over a new figure.\n fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n for (var key in msg) {\n if (!(key in fig.buttons)) {\n continue;\n }\n fig.buttons[key].disabled = !msg[key];\n fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n if (msg['mode'] === 'PAN') {\n fig.buttons['Pan'].classList.add('active');\n fig.buttons['Zoom'].classList.remove('active');\n } else if (msg['mode'] === 'ZOOM') {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.add('active');\n } else {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.remove('active');\n }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Called whenever the canvas gets updated.\n this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n return function socket_on_message(evt) {\n if (evt.data instanceof Blob) {\n /* FIXME: We get \"Resource interpreted as Image but\n * transferred with MIME type text/plain:\" errors on\n * Chrome. But how to set the MIME type? It doesn't seem\n * to be part of the websocket stream */\n evt.data.type = 'image/png';\n\n /* Free the memory for the previous frames */\n if (fig.imageObj.src) {\n (window.URL || window.webkitURL).revokeObjectURL(\n fig.imageObj.src\n );\n }\n\n fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n evt.data\n );\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n } else if (\n typeof evt.data === 'string' &&\n evt.data.slice(0, 21) === 'data:image/png;base64'\n ) {\n fig.imageObj.src = evt.data;\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n }\n\n var msg = JSON.parse(evt.data);\n var msg_type = msg['type'];\n\n // Call the \"handle_{type}\" callback, which takes\n // the figure and JSON message as its only arguments.\n try {\n var callback = fig['handle_' + msg_type];\n } catch (e) {\n console.log(\n \"No handler for the '\" + msg_type + \"' message type: \",\n msg\n );\n return;\n }\n\n if (callback) {\n try {\n // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n callback(fig, msg);\n } catch (e) {\n console.log(\n \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n e,\n e.stack,\n msg\n );\n }\n }\n };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n //this section is from http://www.quirksmode.org/js/events_properties.html\n var targ;\n if (!e) {\n e = window.event;\n }\n if (e.target) {\n targ = e.target;\n } else if (e.srcElement) {\n targ = e.srcElement;\n }\n if (targ.nodeType === 3) {\n // defeat Safari bug\n targ = targ.parentNode;\n }\n\n // pageX,Y are the mouse positions relative to the document\n var boundingRect = targ.getBoundingClientRect();\n var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n return Object.keys(original).reduce(function (obj, key) {\n if (typeof original[key] !== 'object') {\n obj[key] = original[key];\n }\n return obj;\n }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n var canvas_pos = mpl.findpos(event);\n\n if (name === 'button_press') {\n this.canvas.focus();\n this.canvas_div.focus();\n }\n\n var x = canvas_pos.x * this.ratio;\n var y = canvas_pos.y * this.ratio;\n\n this.send_message(name, {\n x: x,\n y: y,\n button: event.button,\n step: event.step,\n guiEvent: simpleKeys(event),\n });\n\n /* This prevents the web browser from automatically changing to\n * the text insertion cursor when the button is pressed. We want\n * to control all of the cursor setting manually through the\n * 'cursor' event from matplotlib */\n event.preventDefault();\n return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n // Prevent repeat events\n if (name === 'key_press') {\n if (event.which === this._key) {\n return;\n } else {\n this._key = event.which;\n }\n }\n if (name === 'key_release') {\n this._key = null;\n }\n\n var value = '';\n if (event.ctrlKey && event.which !== 17) {\n value += 'ctrl+';\n }\n if (event.altKey && event.which !== 18) {\n value += 'alt+';\n }\n if (event.shiftKey && event.which !== 16) {\n value += 'shift+';\n }\n\n value += 'k';\n value += event.which.toString();\n\n this._key_event_extra(event, name);\n\n this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n if (name === 'download') {\n this.handle_save(this, null);\n } else {\n this.send_message('toolbar_button', { name: name });\n }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\nmpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n\nmpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n // Create a \"websocket\"-like object which calls the given IPython comm\n // object with the appropriate methods. Currently this is a non binary\n // socket, so there is still some room for performance tuning.\n var ws = {};\n\n ws.close = function () {\n comm.close();\n };\n ws.send = function (m) {\n //console.log('sending', m);\n comm.send(m);\n };\n // Register the callback with on_msg.\n comm.on_msg(function (msg) {\n //console.log('receiving', msg['content']['data'], msg);\n // Pass the mpl event to the overridden (by mpl) onmessage function.\n ws.onmessage(msg['content']['data']);\n });\n return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n // This is the function which gets called when the mpl process\n // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n var id = msg.content.data.id;\n // Get hold of the div created by the display call when the Comm\n // socket was opened in Python.\n var element = document.getElementById(id);\n var ws_proxy = comm_websocket_adapter(comm);\n\n function ondownload(figure, _format) {\n window.open(figure.canvas.toDataURL());\n }\n\n var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n // web socket which is closed, not our websocket->open comm proxy.\n ws_proxy.onopen();\n\n fig.parent_element = element;\n fig.cell_info = mpl.find_output_cell(\"
\");\n if (!fig.cell_info) {\n console.error('Failed to find cell for figure', id, fig);\n return;\n }\n fig.cell_info[0].output_area.element.on(\n 'cleared',\n { fig: fig },\n fig._remove_fig_handler\n );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n var width = fig.canvas.width / fig.ratio;\n fig.cell_info[0].output_area.element.off(\n 'cleared',\n fig._remove_fig_handler\n );\n fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n // Update the output cell to use the data from the current canvas.\n fig.push_to_output();\n var dataURL = fig.canvas.toDataURL();\n // Re-enable the keyboard manager in IPython - without this line, in FF,\n // the notebook keyboard shortcuts fail.\n IPython.keyboard_manager.enable();\n fig.parent_element.innerHTML =\n '';\n fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n fig.send_message('closing', msg);\n // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n // Turn the data on the canvas into data in the output cell.\n var width = this.canvas.width / this.ratio;\n var dataURL = this.canvas.toDataURL();\n this.cell_info[1]['text/html'] =\n '';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Tell IPython that the notebook contents must change.\n IPython.notebook.set_dirty(true);\n this.send_message('ack', {});\n var fig = this;\n // Wait a second, then push the new image to the DOM so\n // that it is saved nicely (might be nice to debounce this).\n setTimeout(function () {\n fig.push_to_output();\n }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'btn-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n var button;\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n continue;\n }\n\n button = fig.buttons[name] = document.createElement('button');\n button.classList = 'btn btn-default';\n button.href = '#';\n button.title = name;\n button.innerHTML = '';\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n // Add the status bar.\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message pull-right';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n\n // Add the close button to the window.\n var buttongrp = document.createElement('div');\n buttongrp.classList = 'btn-group inline pull-right';\n button = document.createElement('button');\n button.classList = 'btn btn-mini btn-primary';\n button.href = '#';\n button.title = 'Stop Interaction';\n button.innerHTML = '';\n button.addEventListener('click', function (_evt) {\n fig.handle_close(fig, {});\n });\n button.addEventListener(\n 'mouseover',\n on_mouseover_closure('Stop Interaction')\n );\n buttongrp.appendChild(button);\n var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n var fig = event.data.fig;\n if (event.target !== this) {\n // Ignore bubbled events from children.\n return;\n }\n fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n // this is important to make the div 'focusable\n el.setAttribute('tabindex', 0);\n // reach out to IPython and tell the keyboard manager to turn it's self\n // off when our div gets focus\n\n // location in version 3\n if (IPython.notebook.keyboard_manager) {\n IPython.notebook.keyboard_manager.register_events(el);\n } else {\n // location in version 2\n IPython.keyboard_manager.register_events(el);\n }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n var manager = IPython.notebook.keyboard_manager;\n if (!manager) {\n manager = IPython.keyboard_manager;\n }\n\n // Check for shift+enter\n if (event.shiftKey && event.which === 13) {\n this.canvas_div.blur();\n // select the cell after this one\n var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n IPython.notebook.select(index + 1);\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n // Return the cell and output element which can be found *uniquely* in the notebook.\n // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n // IPython event is triggered only after the cells have been serialised, which for\n // our purposes (turning an active figure into a static one), is too late.\n var cells = IPython.notebook.get_cells();\n var ncells = cells.length;\n for (var i = 0; i < ncells; i++) {\n var cell = cells[i];\n if (cell.cell_type === 'code') {\n for (var j = 0; j < cell.output_area.outputs.length; j++) {\n var data = cell.output_area.outputs[j];\n if (data.data) {\n // IPython >= 3 moved mimebundle to data attribute of output\n data = data.data;\n }\n if (data['text/html'] === html_output) {\n return [cell, data, j];\n }\n }\n }\n }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n IPython.notebook.kernel.comm_manager.register_target(\n 'matplotlib',\n mpl.mpl_figure_comm\n );\n}\n", "text/plain": [ "" ] @@ -15852,955 +1632,7 @@ }, { "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "/* global mpl */\n", - "window.mpl = {};\n", - "\n", - "mpl.get_websocket_type = function () {\n", - " if (typeof WebSocket !== 'undefined') {\n", - " return WebSocket;\n", - " } else if (typeof MozWebSocket !== 'undefined') {\n", - " return MozWebSocket;\n", - " } else {\n", - " alert(\n", - " 'Your browser does not have WebSocket support. ' +\n", - " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", - " 'Firefox 4 and 5 are also supported but you ' +\n", - " 'have to enable WebSockets in about:config.'\n", - " );\n", - " }\n", - "};\n", - "\n", - "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", - " this.id = figure_id;\n", - "\n", - " this.ws = websocket;\n", - "\n", - " this.supports_binary = this.ws.binaryType !== undefined;\n", - "\n", - " if (!this.supports_binary) {\n", - " var warnings = document.getElementById('mpl-warnings');\n", - " if (warnings) {\n", - " warnings.style.display = 'block';\n", - " warnings.textContent =\n", - " 'This browser does not support binary websocket messages. ' +\n", - " 'Performance may be slow.';\n", - " }\n", - " }\n", - "\n", - " this.imageObj = new Image();\n", - "\n", - " this.context = undefined;\n", - " this.message = undefined;\n", - " this.canvas = undefined;\n", - " this.rubberband_canvas = undefined;\n", - " this.rubberband_context = undefined;\n", - " this.format_dropdown = undefined;\n", - "\n", - " this.image_mode = 'full';\n", - "\n", - " this.root = document.createElement('div');\n", - " this.root.setAttribute('style', 'display: inline-block');\n", - " this._root_extra_style(this.root);\n", - "\n", - " parent_element.appendChild(this.root);\n", - "\n", - " this._init_header(this);\n", - " this._init_canvas(this);\n", - " this._init_toolbar(this);\n", - "\n", - " var fig = this;\n", - "\n", - " this.waiting = false;\n", - "\n", - " this.ws.onopen = function () {\n", - " fig.send_message('supports_binary', { value: fig.supports_binary });\n", - " fig.send_message('send_image_mode', {});\n", - " if (fig.ratio !== 1) {\n", - " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", - " }\n", - " fig.send_message('refresh', {});\n", - " };\n", - "\n", - " this.imageObj.onload = function () {\n", - " if (fig.image_mode === 'full') {\n", - " // Full images could contain transparency (where diff images\n", - " // almost always do), so we need to clear the canvas so that\n", - " // there is no ghosting.\n", - " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", - " }\n", - " fig.context.drawImage(fig.imageObj, 0, 0);\n", - " };\n", - "\n", - " this.imageObj.onunload = function () {\n", - " fig.ws.close();\n", - " };\n", - "\n", - " this.ws.onmessage = this._make_on_message_function(this);\n", - "\n", - " this.ondownload = ondownload;\n", - "};\n", - "\n", - "mpl.figure.prototype._init_header = function () {\n", - " var titlebar = document.createElement('div');\n", - " titlebar.classList =\n", - " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", - " var titletext = document.createElement('div');\n", - " titletext.classList = 'ui-dialog-title';\n", - " titletext.setAttribute(\n", - " 'style',\n", - " 'width: 100%; text-align: center; padding: 3px;'\n", - " );\n", - " titlebar.appendChild(titletext);\n", - " this.root.appendChild(titlebar);\n", - " this.header = titletext;\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._init_canvas = function () {\n", - " var fig = this;\n", - "\n", - " var canvas_div = (this.canvas_div = document.createElement('div'));\n", - " canvas_div.setAttribute(\n", - " 'style',\n", - " 'border: 1px solid #ddd;' +\n", - " 'box-sizing: content-box;' +\n", - " 'clear: both;' +\n", - " 'min-height: 1px;' +\n", - " 'min-width: 1px;' +\n", - " 'outline: 0;' +\n", - " 'overflow: hidden;' +\n", - " 'position: relative;' +\n", - " 'resize: both;'\n", - " );\n", - "\n", - " function on_keyboard_event_closure(name) {\n", - " return function (event) {\n", - " return fig.key_event(event, name);\n", - " };\n", - " }\n", - "\n", - " canvas_div.addEventListener(\n", - " 'keydown',\n", - " on_keyboard_event_closure('key_press')\n", - " );\n", - " canvas_div.addEventListener(\n", - " 'keyup',\n", - " on_keyboard_event_closure('key_release')\n", - " );\n", - "\n", - " this._canvas_extra_style(canvas_div);\n", - " this.root.appendChild(canvas_div);\n", - "\n", - " var canvas = (this.canvas = document.createElement('canvas'));\n", - " canvas.classList.add('mpl-canvas');\n", - " canvas.setAttribute('style', 'box-sizing: content-box;');\n", - "\n", - " this.context = canvas.getContext('2d');\n", - "\n", - " var backingStore =\n", - " this.context.backingStorePixelRatio ||\n", - " this.context.webkitBackingStorePixelRatio ||\n", - " this.context.mozBackingStorePixelRatio ||\n", - " this.context.msBackingStorePixelRatio ||\n", - " this.context.oBackingStorePixelRatio ||\n", - " this.context.backingStorePixelRatio ||\n", - " 1;\n", - "\n", - " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", - "\n", - " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", - " 'canvas'\n", - " ));\n", - " rubberband_canvas.setAttribute(\n", - " 'style',\n", - " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", - " );\n", - "\n", - " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", - " if (this.ResizeObserver === undefined) {\n", - " if (window.ResizeObserver !== undefined) {\n", - " this.ResizeObserver = window.ResizeObserver;\n", - " } else {\n", - " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", - " this.ResizeObserver = obs.ResizeObserver;\n", - " }\n", - " }\n", - "\n", - " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", - " var nentries = entries.length;\n", - " for (var i = 0; i < nentries; i++) {\n", - " var entry = entries[i];\n", - " var width, height;\n", - " if (entry.contentBoxSize) {\n", - " if (entry.contentBoxSize instanceof Array) {\n", - " // Chrome 84 implements new version of spec.\n", - " width = entry.contentBoxSize[0].inlineSize;\n", - " height = entry.contentBoxSize[0].blockSize;\n", - " } else {\n", - " // Firefox implements old version of spec.\n", - " width = entry.contentBoxSize.inlineSize;\n", - " height = entry.contentBoxSize.blockSize;\n", - " }\n", - " } else {\n", - " // Chrome <84 implements even older version of spec.\n", - " width = entry.contentRect.width;\n", - " height = entry.contentRect.height;\n", - " }\n", - "\n", - " // Keep the size of the canvas and rubber band canvas in sync with\n", - " // the canvas container.\n", - " if (entry.devicePixelContentBoxSize) {\n", - " // Chrome 84 implements new version of spec.\n", - " canvas.setAttribute(\n", - " 'width',\n", - " entry.devicePixelContentBoxSize[0].inlineSize\n", - " );\n", - " canvas.setAttribute(\n", - " 'height',\n", - " entry.devicePixelContentBoxSize[0].blockSize\n", - " );\n", - " } else {\n", - " canvas.setAttribute('width', width * fig.ratio);\n", - " canvas.setAttribute('height', height * fig.ratio);\n", - " }\n", - " canvas.setAttribute(\n", - " 'style',\n", - " 'width: ' + width + 'px; height: ' + height + 'px;'\n", - " );\n", - "\n", - " rubberband_canvas.setAttribute('width', width);\n", - " rubberband_canvas.setAttribute('height', height);\n", - "\n", - " // And update the size in Python. We ignore the initial 0/0 size\n", - " // that occurs as the element is placed into the DOM, which should\n", - " // otherwise not happen due to the minimum size styling.\n", - " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", - " fig.request_resize(width, height);\n", - " }\n", - " }\n", - " });\n", - " this.resizeObserverInstance.observe(canvas_div);\n", - "\n", - " function on_mouse_event_closure(name) {\n", - " return function (event) {\n", - " return fig.mouse_event(event, name);\n", - " };\n", - " }\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mousedown',\n", - " on_mouse_event_closure('button_press')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseup',\n", - " on_mouse_event_closure('button_release')\n", - " );\n", - " // Throttle sequential mouse events to 1 every 20ms.\n", - " rubberband_canvas.addEventListener(\n", - " 'mousemove',\n", - " on_mouse_event_closure('motion_notify')\n", - " );\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseenter',\n", - " on_mouse_event_closure('figure_enter')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseleave',\n", - " on_mouse_event_closure('figure_leave')\n", - " );\n", - "\n", - " canvas_div.addEventListener('wheel', function (event) {\n", - " if (event.deltaY < 0) {\n", - " event.step = 1;\n", - " } else {\n", - " event.step = -1;\n", - " }\n", - " on_mouse_event_closure('scroll')(event);\n", - " });\n", - "\n", - " canvas_div.appendChild(canvas);\n", - " canvas_div.appendChild(rubberband_canvas);\n", - "\n", - " this.rubberband_context = rubberband_canvas.getContext('2d');\n", - " this.rubberband_context.strokeStyle = '#000000';\n", - "\n", - " this._resize_canvas = function (width, height, forward) {\n", - " if (forward) {\n", - " canvas_div.style.width = width + 'px';\n", - " canvas_div.style.height = height + 'px';\n", - " }\n", - " };\n", - "\n", - " // Disable right mouse context menu.\n", - " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", - " event.preventDefault();\n", - " return false;\n", - " });\n", - "\n", - " function set_focus() {\n", - " canvas.focus();\n", - " canvas_div.focus();\n", - " }\n", - "\n", - " window.setTimeout(set_focus, 100);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'mpl-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " continue;\n", - " }\n", - "\n", - " var button = (fig.buttons[name] = document.createElement('button'));\n", - " button.classList = 'mpl-widget';\n", - " button.setAttribute('role', 'button');\n", - " button.setAttribute('aria-disabled', 'false');\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - "\n", - " var icon_img = document.createElement('img');\n", - " icon_img.src = '_images/' + image + '.png';\n", - " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", - " icon_img.alt = tooltip;\n", - " button.appendChild(icon_img);\n", - "\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " var fmt_picker = document.createElement('select');\n", - " fmt_picker.classList = 'mpl-widget';\n", - " toolbar.appendChild(fmt_picker);\n", - " this.format_dropdown = fmt_picker;\n", - "\n", - " for (var ind in mpl.extensions) {\n", - " var fmt = mpl.extensions[ind];\n", - " var option = document.createElement('option');\n", - " option.selected = fmt === mpl.default_extension;\n", - " option.innerHTML = fmt;\n", - " fmt_picker.appendChild(option);\n", - " }\n", - "\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "};\n", - "\n", - "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", - " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", - " // which will in turn request a refresh of the image.\n", - " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", - "};\n", - "\n", - "mpl.figure.prototype.send_message = function (type, properties) {\n", - " properties['type'] = type;\n", - " properties['figure_id'] = this.id;\n", - " this.ws.send(JSON.stringify(properties));\n", - "};\n", - "\n", - "mpl.figure.prototype.send_draw_message = function () {\n", - " if (!this.waiting) {\n", - " this.waiting = true;\n", - " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " var format_dropdown = fig.format_dropdown;\n", - " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", - " fig.ondownload(fig, format);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", - " var size = msg['size'];\n", - " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", - " fig._resize_canvas(size[0], size[1], msg['forward']);\n", - " fig.send_message('refresh', {});\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", - " var x0 = msg['x0'] / fig.ratio;\n", - " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", - " var x1 = msg['x1'] / fig.ratio;\n", - " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", - " x0 = Math.floor(x0) + 0.5;\n", - " y0 = Math.floor(y0) + 0.5;\n", - " x1 = Math.floor(x1) + 0.5;\n", - " y1 = Math.floor(y1) + 0.5;\n", - " var min_x = Math.min(x0, x1);\n", - " var min_y = Math.min(y0, y1);\n", - " var width = Math.abs(x1 - x0);\n", - " var height = Math.abs(y1 - y0);\n", - "\n", - " fig.rubberband_context.clearRect(\n", - " 0,\n", - " 0,\n", - " fig.canvas.width / fig.ratio,\n", - " fig.canvas.height / fig.ratio\n", - " );\n", - "\n", - " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", - " // Updates the figure title.\n", - " fig.header.textContent = msg['label'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", - " var cursor = msg['cursor'];\n", - " switch (cursor) {\n", - " case 0:\n", - " cursor = 'pointer';\n", - " break;\n", - " case 1:\n", - " cursor = 'default';\n", - " break;\n", - " case 2:\n", - " cursor = 'crosshair';\n", - " break;\n", - " case 3:\n", - " cursor = 'move';\n", - " break;\n", - " }\n", - " fig.rubberband_canvas.style.cursor = cursor;\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_message = function (fig, msg) {\n", - " fig.message.textContent = msg['message'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", - " // Request the server to send over a new figure.\n", - " fig.send_draw_message();\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", - " fig.image_mode = msg['mode'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", - " for (var key in msg) {\n", - " if (!(key in fig.buttons)) {\n", - " continue;\n", - " }\n", - " fig.buttons[key].disabled = !msg[key];\n", - " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", - " if (msg['mode'] === 'PAN') {\n", - " fig.buttons['Pan'].classList.add('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " } else if (msg['mode'] === 'ZOOM') {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.add('active');\n", - " } else {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Called whenever the canvas gets updated.\n", - " this.send_message('ack', {});\n", - "};\n", - "\n", - "// A function to construct a web socket function for onmessage handling.\n", - "// Called in the figure constructor.\n", - "mpl.figure.prototype._make_on_message_function = function (fig) {\n", - " return function socket_on_message(evt) {\n", - " if (evt.data instanceof Blob) {\n", - " /* FIXME: We get \"Resource interpreted as Image but\n", - " * transferred with MIME type text/plain:\" errors on\n", - " * Chrome. But how to set the MIME type? It doesn't seem\n", - " * to be part of the websocket stream */\n", - " evt.data.type = 'image/png';\n", - "\n", - " /* Free the memory for the previous frames */\n", - " if (fig.imageObj.src) {\n", - " (window.URL || window.webkitURL).revokeObjectURL(\n", - " fig.imageObj.src\n", - " );\n", - " }\n", - "\n", - " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", - " evt.data\n", - " );\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " } else if (\n", - " typeof evt.data === 'string' &&\n", - " evt.data.slice(0, 21) === 'data:image/png;base64'\n", - " ) {\n", - " fig.imageObj.src = evt.data;\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " }\n", - "\n", - " var msg = JSON.parse(evt.data);\n", - " var msg_type = msg['type'];\n", - "\n", - " // Call the \"handle_{type}\" callback, which takes\n", - " // the figure and JSON message as its only arguments.\n", - " try {\n", - " var callback = fig['handle_' + msg_type];\n", - " } catch (e) {\n", - " console.log(\n", - " \"No handler for the '\" + msg_type + \"' message type: \",\n", - " msg\n", - " );\n", - " return;\n", - " }\n", - "\n", - " if (callback) {\n", - " try {\n", - " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", - " callback(fig, msg);\n", - " } catch (e) {\n", - " console.log(\n", - " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", - " e,\n", - " e.stack,\n", - " msg\n", - " );\n", - " }\n", - " }\n", - " };\n", - "};\n", - "\n", - "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", - "mpl.findpos = function (e) {\n", - " //this section is from http://www.quirksmode.org/js/events_properties.html\n", - " var targ;\n", - " if (!e) {\n", - " e = window.event;\n", - " }\n", - " if (e.target) {\n", - " targ = e.target;\n", - " } else if (e.srcElement) {\n", - " targ = e.srcElement;\n", - " }\n", - " if (targ.nodeType === 3) {\n", - " // defeat Safari bug\n", - " targ = targ.parentNode;\n", - " }\n", - "\n", - " // pageX,Y are the mouse positions relative to the document\n", - " var boundingRect = targ.getBoundingClientRect();\n", - " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", - " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", - "\n", - " return { x: x, y: y };\n", - "};\n", - "\n", - "/*\n", - " * return a copy of an object with only non-object keys\n", - " * we need this to avoid circular references\n", - " * http://stackoverflow.com/a/24161582/3208463\n", - " */\n", - "function simpleKeys(original) {\n", - " return Object.keys(original).reduce(function (obj, key) {\n", - " if (typeof original[key] !== 'object') {\n", - " obj[key] = original[key];\n", - " }\n", - " return obj;\n", - " }, {});\n", - "}\n", - "\n", - "mpl.figure.prototype.mouse_event = function (event, name) {\n", - " var canvas_pos = mpl.findpos(event);\n", - "\n", - " if (name === 'button_press') {\n", - " this.canvas.focus();\n", - " this.canvas_div.focus();\n", - " }\n", - "\n", - " var x = canvas_pos.x * this.ratio;\n", - " var y = canvas_pos.y * this.ratio;\n", - "\n", - " this.send_message(name, {\n", - " x: x,\n", - " y: y,\n", - " button: event.button,\n", - " step: event.step,\n", - " guiEvent: simpleKeys(event),\n", - " });\n", - "\n", - " /* This prevents the web browser from automatically changing to\n", - " * the text insertion cursor when the button is pressed. We want\n", - " * to control all of the cursor setting manually through the\n", - " * 'cursor' event from matplotlib */\n", - " event.preventDefault();\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", - " // Handle any extra behaviour associated with a key event\n", - "};\n", - "\n", - "mpl.figure.prototype.key_event = function (event, name) {\n", - " // Prevent repeat events\n", - " if (name === 'key_press') {\n", - " if (event.which === this._key) {\n", - " return;\n", - " } else {\n", - " this._key = event.which;\n", - " }\n", - " }\n", - " if (name === 'key_release') {\n", - " this._key = null;\n", - " }\n", - "\n", - " var value = '';\n", - " if (event.ctrlKey && event.which !== 17) {\n", - " value += 'ctrl+';\n", - " }\n", - " if (event.altKey && event.which !== 18) {\n", - " value += 'alt+';\n", - " }\n", - " if (event.shiftKey && event.which !== 16) {\n", - " value += 'shift+';\n", - " }\n", - "\n", - " value += 'k';\n", - " value += event.which.toString();\n", - "\n", - " this._key_event_extra(event, name);\n", - "\n", - " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", - " if (name === 'download') {\n", - " this.handle_save(this, null);\n", - " } else {\n", - " this.send_message('toolbar_button', { name: name });\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", - " this.message.textContent = tooltip;\n", - "};\n", - "\n", - "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", - "// prettier-ignore\n", - "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", - "\n", - "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", - "\n", - "mpl.default_extension = \"png\";/* global mpl */\n", - "\n", - "var comm_websocket_adapter = function (comm) {\n", - " // Create a \"websocket\"-like object which calls the given IPython comm\n", - " // object with the appropriate methods. Currently this is a non binary\n", - " // socket, so there is still some room for performance tuning.\n", - " var ws = {};\n", - "\n", - " ws.close = function () {\n", - " comm.close();\n", - " };\n", - " ws.send = function (m) {\n", - " //console.log('sending', m);\n", - " comm.send(m);\n", - " };\n", - " // Register the callback with on_msg.\n", - " comm.on_msg(function (msg) {\n", - " //console.log('receiving', msg['content']['data'], msg);\n", - " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", - " ws.onmessage(msg['content']['data']);\n", - " });\n", - " return ws;\n", - "};\n", - "\n", - "mpl.mpl_figure_comm = function (comm, msg) {\n", - " // This is the function which gets called when the mpl process\n", - " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", - "\n", - " var id = msg.content.data.id;\n", - " // Get hold of the div created by the display call when the Comm\n", - " // socket was opened in Python.\n", - " var element = document.getElementById(id);\n", - " var ws_proxy = comm_websocket_adapter(comm);\n", - "\n", - " function ondownload(figure, _format) {\n", - " window.open(figure.canvas.toDataURL());\n", - " }\n", - "\n", - " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", - "\n", - " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", - " // web socket which is closed, not our websocket->open comm proxy.\n", - " ws_proxy.onopen();\n", - "\n", - " fig.parent_element = element;\n", - " fig.cell_info = mpl.find_output_cell(\"
\");\n", - " if (!fig.cell_info) {\n", - " console.error('Failed to find cell for figure', id, fig);\n", - " return;\n", - " }\n", - " fig.cell_info[0].output_area.element.on(\n", - " 'cleared',\n", - " { fig: fig },\n", - " fig._remove_fig_handler\n", - " );\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_close = function (fig, msg) {\n", - " var width = fig.canvas.width / fig.ratio;\n", - " fig.cell_info[0].output_area.element.off(\n", - " 'cleared',\n", - " fig._remove_fig_handler\n", - " );\n", - " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", - "\n", - " // Update the output cell to use the data from the current canvas.\n", - " fig.push_to_output();\n", - " var dataURL = fig.canvas.toDataURL();\n", - " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", - " // the notebook keyboard shortcuts fail.\n", - " IPython.keyboard_manager.enable();\n", - " fig.parent_element.innerHTML =\n", - " '';\n", - " fig.close_ws(fig, msg);\n", - "};\n", - "\n", - "mpl.figure.prototype.close_ws = function (fig, msg) {\n", - " fig.send_message('closing', msg);\n", - " // fig.ws.close()\n", - "};\n", - "\n", - "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", - " // Turn the data on the canvas into data in the output cell.\n", - " var width = this.canvas.width / this.ratio;\n", - " var dataURL = this.canvas.toDataURL();\n", - " this.cell_info[1]['text/html'] =\n", - " '';\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Tell IPython that the notebook contents must change.\n", - " IPython.notebook.set_dirty(true);\n", - " this.send_message('ack', {});\n", - " var fig = this;\n", - " // Wait a second, then push the new image to the DOM so\n", - " // that it is saved nicely (might be nice to debounce this).\n", - " setTimeout(function () {\n", - " fig.push_to_output();\n", - " }, 1000);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'btn-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " var button;\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " continue;\n", - " }\n", - "\n", - " button = fig.buttons[name] = document.createElement('button');\n", - " button.classList = 'btn btn-default';\n", - " button.href = '#';\n", - " button.title = name;\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " // Add the status bar.\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message pull-right';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "\n", - " // Add the close button to the window.\n", - " var buttongrp = document.createElement('div');\n", - " buttongrp.classList = 'btn-group inline pull-right';\n", - " button = document.createElement('button');\n", - " button.classList = 'btn btn-mini btn-primary';\n", - " button.href = '#';\n", - " button.title = 'Stop Interaction';\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', function (_evt) {\n", - " fig.handle_close(fig, {});\n", - " });\n", - " button.addEventListener(\n", - " 'mouseover',\n", - " on_mouseover_closure('Stop Interaction')\n", - " );\n", - " buttongrp.appendChild(button);\n", - " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", - " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", - "};\n", - "\n", - "mpl.figure.prototype._remove_fig_handler = function (event) {\n", - " var fig = event.data.fig;\n", - " if (event.target !== this) {\n", - " // Ignore bubbled events from children.\n", - " return;\n", - " }\n", - " fig.close_ws(fig, {});\n", - "};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (el) {\n", - " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (el) {\n", - " // this is important to make the div 'focusable\n", - " el.setAttribute('tabindex', 0);\n", - " // reach out to IPython and tell the keyboard manager to turn it's self\n", - " // off when our div gets focus\n", - "\n", - " // location in version 3\n", - " if (IPython.notebook.keyboard_manager) {\n", - " IPython.notebook.keyboard_manager.register_events(el);\n", - " } else {\n", - " // location in version 2\n", - " IPython.keyboard_manager.register_events(el);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", - " var manager = IPython.notebook.keyboard_manager;\n", - " if (!manager) {\n", - " manager = IPython.keyboard_manager;\n", - " }\n", - "\n", - " // Check for shift+enter\n", - " if (event.shiftKey && event.which === 13) {\n", - " this.canvas_div.blur();\n", - " // select the cell after this one\n", - " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", - " IPython.notebook.select(index + 1);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " fig.ondownload(fig, null);\n", - "};\n", - "\n", - "mpl.find_output_cell = function (html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i = 0; i < ncells; i++) {\n", - " var cell = cells[i];\n", - " if (cell.cell_type === 'code') {\n", - " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", - " var data = cell.output_area.outputs[j];\n", - " if (data.data) {\n", - " // IPython >= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] === html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "};\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel !== null) {\n", - " IPython.notebook.kernel.comm_manager.register_target(\n", - " 'matplotlib',\n", - " mpl.mpl_figure_comm\n", - " );\n", - "}\n" - ], + "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n if (typeof WebSocket !== 'undefined') {\n return WebSocket;\n } else if (typeof MozWebSocket !== 'undefined') {\n return MozWebSocket;\n } else {\n alert(\n 'Your browser does not have WebSocket support. ' +\n 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n 'Firefox 4 and 5 are also supported but you ' +\n 'have to enable WebSockets in about:config.'\n );\n }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n this.id = figure_id;\n\n this.ws = websocket;\n\n this.supports_binary = this.ws.binaryType !== undefined;\n\n if (!this.supports_binary) {\n var warnings = document.getElementById('mpl-warnings');\n if (warnings) {\n warnings.style.display = 'block';\n warnings.textContent =\n 'This browser does not support binary websocket messages. ' +\n 'Performance may be slow.';\n }\n }\n\n this.imageObj = new Image();\n\n this.context = undefined;\n this.message = undefined;\n this.canvas = undefined;\n this.rubberband_canvas = undefined;\n this.rubberband_context = undefined;\n this.format_dropdown = undefined;\n\n this.image_mode = 'full';\n\n this.root = document.createElement('div');\n this.root.setAttribute('style', 'display: inline-block');\n this._root_extra_style(this.root);\n\n parent_element.appendChild(this.root);\n\n this._init_header(this);\n this._init_canvas(this);\n this._init_toolbar(this);\n\n var fig = this;\n\n this.waiting = false;\n\n this.ws.onopen = function () {\n fig.send_message('supports_binary', { value: fig.supports_binary });\n fig.send_message('send_image_mode', {});\n if (fig.ratio !== 1) {\n fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n }\n fig.send_message('refresh', {});\n };\n\n this.imageObj.onload = function () {\n if (fig.image_mode === 'full') {\n // Full images could contain transparency (where diff images\n // almost always do), so we need to clear the canvas so that\n // there is no ghosting.\n fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n }\n fig.context.drawImage(fig.imageObj, 0, 0);\n };\n\n this.imageObj.onunload = function () {\n fig.ws.close();\n };\n\n this.ws.onmessage = this._make_on_message_function(this);\n\n this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n var titlebar = document.createElement('div');\n titlebar.classList =\n 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n var titletext = document.createElement('div');\n titletext.classList = 'ui-dialog-title';\n titletext.setAttribute(\n 'style',\n 'width: 100%; text-align: center; padding: 3px;'\n );\n titlebar.appendChild(titletext);\n this.root.appendChild(titlebar);\n this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n var fig = this;\n\n var canvas_div = (this.canvas_div = document.createElement('div'));\n canvas_div.setAttribute(\n 'style',\n 'border: 1px solid #ddd;' +\n 'box-sizing: content-box;' +\n 'clear: both;' +\n 'min-height: 1px;' +\n 'min-width: 1px;' +\n 'outline: 0;' +\n 'overflow: hidden;' +\n 'position: relative;' +\n 'resize: both;'\n );\n\n function on_keyboard_event_closure(name) {\n return function (event) {\n return fig.key_event(event, name);\n };\n }\n\n canvas_div.addEventListener(\n 'keydown',\n on_keyboard_event_closure('key_press')\n );\n canvas_div.addEventListener(\n 'keyup',\n on_keyboard_event_closure('key_release')\n );\n\n this._canvas_extra_style(canvas_div);\n this.root.appendChild(canvas_div);\n\n var canvas = (this.canvas = document.createElement('canvas'));\n canvas.classList.add('mpl-canvas');\n canvas.setAttribute('style', 'box-sizing: content-box;');\n\n this.context = canvas.getContext('2d');\n\n var backingStore =\n this.context.backingStorePixelRatio ||\n this.context.webkitBackingStorePixelRatio ||\n this.context.mozBackingStorePixelRatio ||\n this.context.msBackingStorePixelRatio ||\n this.context.oBackingStorePixelRatio ||\n this.context.backingStorePixelRatio ||\n 1;\n\n this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n 'canvas'\n ));\n rubberband_canvas.setAttribute(\n 'style',\n 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n );\n\n // Apply a ponyfill if ResizeObserver is not implemented by browser.\n if (this.ResizeObserver === undefined) {\n if (window.ResizeObserver !== undefined) {\n this.ResizeObserver = window.ResizeObserver;\n } else {\n var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n this.ResizeObserver = obs.ResizeObserver;\n }\n }\n\n this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n var nentries = entries.length;\n for (var i = 0; i < nentries; i++) {\n var entry = entries[i];\n var width, height;\n if (entry.contentBoxSize) {\n if (entry.contentBoxSize instanceof Array) {\n // Chrome 84 implements new version of spec.\n width = entry.contentBoxSize[0].inlineSize;\n height = entry.contentBoxSize[0].blockSize;\n } else {\n // Firefox implements old version of spec.\n width = entry.contentBoxSize.inlineSize;\n height = entry.contentBoxSize.blockSize;\n }\n } else {\n // Chrome <84 implements even older version of spec.\n width = entry.contentRect.width;\n height = entry.contentRect.height;\n }\n\n // Keep the size of the canvas and rubber band canvas in sync with\n // the canvas container.\n if (entry.devicePixelContentBoxSize) {\n // Chrome 84 implements new version of spec.\n canvas.setAttribute(\n 'width',\n entry.devicePixelContentBoxSize[0].inlineSize\n );\n canvas.setAttribute(\n 'height',\n entry.devicePixelContentBoxSize[0].blockSize\n );\n } else {\n canvas.setAttribute('width', width * fig.ratio);\n canvas.setAttribute('height', height * fig.ratio);\n }\n canvas.setAttribute(\n 'style',\n 'width: ' + width + 'px; height: ' + height + 'px;'\n );\n\n rubberband_canvas.setAttribute('width', width);\n rubberband_canvas.setAttribute('height', height);\n\n // And update the size in Python. We ignore the initial 0/0 size\n // that occurs as the element is placed into the DOM, which should\n // otherwise not happen due to the minimum size styling.\n if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n fig.request_resize(width, height);\n }\n }\n });\n this.resizeObserverInstance.observe(canvas_div);\n\n function on_mouse_event_closure(name) {\n return function (event) {\n return fig.mouse_event(event, name);\n };\n }\n\n rubberband_canvas.addEventListener(\n 'mousedown',\n on_mouse_event_closure('button_press')\n );\n rubberband_canvas.addEventListener(\n 'mouseup',\n on_mouse_event_closure('button_release')\n );\n // Throttle sequential mouse events to 1 every 20ms.\n rubberband_canvas.addEventListener(\n 'mousemove',\n on_mouse_event_closure('motion_notify')\n );\n\n rubberband_canvas.addEventListener(\n 'mouseenter',\n on_mouse_event_closure('figure_enter')\n );\n rubberband_canvas.addEventListener(\n 'mouseleave',\n on_mouse_event_closure('figure_leave')\n );\n\n canvas_div.addEventListener('wheel', function (event) {\n if (event.deltaY < 0) {\n event.step = 1;\n } else {\n event.step = -1;\n }\n on_mouse_event_closure('scroll')(event);\n });\n\n canvas_div.appendChild(canvas);\n canvas_div.appendChild(rubberband_canvas);\n\n this.rubberband_context = rubberband_canvas.getContext('2d');\n this.rubberband_context.strokeStyle = '#000000';\n\n this._resize_canvas = function (width, height, forward) {\n if (forward) {\n canvas_div.style.width = width + 'px';\n canvas_div.style.height = height + 'px';\n }\n };\n\n // Disable right mouse context menu.\n this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n event.preventDefault();\n return false;\n });\n\n function set_focus() {\n canvas.focus();\n canvas_div.focus();\n }\n\n window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'mpl-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n continue;\n }\n\n var button = (fig.buttons[name] = document.createElement('button'));\n button.classList = 'mpl-widget';\n button.setAttribute('role', 'button');\n button.setAttribute('aria-disabled', 'false');\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n var icon_img = document.createElement('img');\n icon_img.src = '_images/' + image + '.png';\n icon_img.srcset = '_images/' + image + '_large.png 2x';\n icon_img.alt = tooltip;\n button.appendChild(icon_img);\n\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n var fmt_picker = document.createElement('select');\n fmt_picker.classList = 'mpl-widget';\n toolbar.appendChild(fmt_picker);\n this.format_dropdown = fmt_picker;\n\n for (var ind in mpl.extensions) {\n var fmt = mpl.extensions[ind];\n var option = document.createElement('option');\n option.selected = fmt === mpl.default_extension;\n option.innerHTML = fmt;\n fmt_picker.appendChild(option);\n }\n\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n // which will in turn request a refresh of the image.\n this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n properties['type'] = type;\n properties['figure_id'] = this.id;\n this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n if (!this.waiting) {\n this.waiting = true;\n this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n var format_dropdown = fig.format_dropdown;\n var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n var size = msg['size'];\n if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n fig._resize_canvas(size[0], size[1], msg['forward']);\n fig.send_message('refresh', {});\n }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n var x0 = msg['x0'] / fig.ratio;\n var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n var x1 = msg['x1'] / fig.ratio;\n var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n x0 = Math.floor(x0) + 0.5;\n y0 = Math.floor(y0) + 0.5;\n x1 = Math.floor(x1) + 0.5;\n y1 = Math.floor(y1) + 0.5;\n var min_x = Math.min(x0, x1);\n var min_y = Math.min(y0, y1);\n var width = Math.abs(x1 - x0);\n var height = Math.abs(y1 - y0);\n\n fig.rubberband_context.clearRect(\n 0,\n 0,\n fig.canvas.width / fig.ratio,\n fig.canvas.height / fig.ratio\n );\n\n fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n // Updates the figure title.\n fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n var cursor = msg['cursor'];\n switch (cursor) {\n case 0:\n cursor = 'pointer';\n break;\n case 1:\n cursor = 'default';\n break;\n case 2:\n cursor = 'crosshair';\n break;\n case 3:\n cursor = 'move';\n break;\n }\n fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n // Request the server to send over a new figure.\n fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n for (var key in msg) {\n if (!(key in fig.buttons)) {\n continue;\n }\n fig.buttons[key].disabled = !msg[key];\n fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n if (msg['mode'] === 'PAN') {\n fig.buttons['Pan'].classList.add('active');\n fig.buttons['Zoom'].classList.remove('active');\n } else if (msg['mode'] === 'ZOOM') {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.add('active');\n } else {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.remove('active');\n }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Called whenever the canvas gets updated.\n this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n return function socket_on_message(evt) {\n if (evt.data instanceof Blob) {\n /* FIXME: We get \"Resource interpreted as Image but\n * transferred with MIME type text/plain:\" errors on\n * Chrome. But how to set the MIME type? It doesn't seem\n * to be part of the websocket stream */\n evt.data.type = 'image/png';\n\n /* Free the memory for the previous frames */\n if (fig.imageObj.src) {\n (window.URL || window.webkitURL).revokeObjectURL(\n fig.imageObj.src\n );\n }\n\n fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n evt.data\n );\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n } else if (\n typeof evt.data === 'string' &&\n evt.data.slice(0, 21) === 'data:image/png;base64'\n ) {\n fig.imageObj.src = evt.data;\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n }\n\n var msg = JSON.parse(evt.data);\n var msg_type = msg['type'];\n\n // Call the \"handle_{type}\" callback, which takes\n // the figure and JSON message as its only arguments.\n try {\n var callback = fig['handle_' + msg_type];\n } catch (e) {\n console.log(\n \"No handler for the '\" + msg_type + \"' message type: \",\n msg\n );\n return;\n }\n\n if (callback) {\n try {\n // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n callback(fig, msg);\n } catch (e) {\n console.log(\n \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n e,\n e.stack,\n msg\n );\n }\n }\n };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n //this section is from http://www.quirksmode.org/js/events_properties.html\n var targ;\n if (!e) {\n e = window.event;\n }\n if (e.target) {\n targ = e.target;\n } else if (e.srcElement) {\n targ = e.srcElement;\n }\n if (targ.nodeType === 3) {\n // defeat Safari bug\n targ = targ.parentNode;\n }\n\n // pageX,Y are the mouse positions relative to the document\n var boundingRect = targ.getBoundingClientRect();\n var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n return Object.keys(original).reduce(function (obj, key) {\n if (typeof original[key] !== 'object') {\n obj[key] = original[key];\n }\n return obj;\n }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n var canvas_pos = mpl.findpos(event);\n\n if (name === 'button_press') {\n this.canvas.focus();\n this.canvas_div.focus();\n }\n\n var x = canvas_pos.x * this.ratio;\n var y = canvas_pos.y * this.ratio;\n\n this.send_message(name, {\n x: x,\n y: y,\n button: event.button,\n step: event.step,\n guiEvent: simpleKeys(event),\n });\n\n /* This prevents the web browser from automatically changing to\n * the text insertion cursor when the button is pressed. We want\n * to control all of the cursor setting manually through the\n * 'cursor' event from matplotlib */\n event.preventDefault();\n return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n // Prevent repeat events\n if (name === 'key_press') {\n if (event.which === this._key) {\n return;\n } else {\n this._key = event.which;\n }\n }\n if (name === 'key_release') {\n this._key = null;\n }\n\n var value = '';\n if (event.ctrlKey && event.which !== 17) {\n value += 'ctrl+';\n }\n if (event.altKey && event.which !== 18) {\n value += 'alt+';\n }\n if (event.shiftKey && event.which !== 16) {\n value += 'shift+';\n }\n\n value += 'k';\n value += event.which.toString();\n\n this._key_event_extra(event, name);\n\n this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n if (name === 'download') {\n this.handle_save(this, null);\n } else {\n this.send_message('toolbar_button', { name: name });\n }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\nmpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n\nmpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n // Create a \"websocket\"-like object which calls the given IPython comm\n // object with the appropriate methods. Currently this is a non binary\n // socket, so there is still some room for performance tuning.\n var ws = {};\n\n ws.close = function () {\n comm.close();\n };\n ws.send = function (m) {\n //console.log('sending', m);\n comm.send(m);\n };\n // Register the callback with on_msg.\n comm.on_msg(function (msg) {\n //console.log('receiving', msg['content']['data'], msg);\n // Pass the mpl event to the overridden (by mpl) onmessage function.\n ws.onmessage(msg['content']['data']);\n });\n return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n // This is the function which gets called when the mpl process\n // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n var id = msg.content.data.id;\n // Get hold of the div created by the display call when the Comm\n // socket was opened in Python.\n var element = document.getElementById(id);\n var ws_proxy = comm_websocket_adapter(comm);\n\n function ondownload(figure, _format) {\n window.open(figure.canvas.toDataURL());\n }\n\n var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n // web socket which is closed, not our websocket->open comm proxy.\n ws_proxy.onopen();\n\n fig.parent_element = element;\n fig.cell_info = mpl.find_output_cell(\"
\");\n if (!fig.cell_info) {\n console.error('Failed to find cell for figure', id, fig);\n return;\n }\n fig.cell_info[0].output_area.element.on(\n 'cleared',\n { fig: fig },\n fig._remove_fig_handler\n );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n var width = fig.canvas.width / fig.ratio;\n fig.cell_info[0].output_area.element.off(\n 'cleared',\n fig._remove_fig_handler\n );\n fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n // Update the output cell to use the data from the current canvas.\n fig.push_to_output();\n var dataURL = fig.canvas.toDataURL();\n // Re-enable the keyboard manager in IPython - without this line, in FF,\n // the notebook keyboard shortcuts fail.\n IPython.keyboard_manager.enable();\n fig.parent_element.innerHTML =\n '';\n fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n fig.send_message('closing', msg);\n // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n // Turn the data on the canvas into data in the output cell.\n var width = this.canvas.width / this.ratio;\n var dataURL = this.canvas.toDataURL();\n this.cell_info[1]['text/html'] =\n '';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Tell IPython that the notebook contents must change.\n IPython.notebook.set_dirty(true);\n this.send_message('ack', {});\n var fig = this;\n // Wait a second, then push the new image to the DOM so\n // that it is saved nicely (might be nice to debounce this).\n setTimeout(function () {\n fig.push_to_output();\n }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'btn-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n var button;\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n continue;\n }\n\n button = fig.buttons[name] = document.createElement('button');\n button.classList = 'btn btn-default';\n button.href = '#';\n button.title = name;\n button.innerHTML = '';\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n // Add the status bar.\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message pull-right';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n\n // Add the close button to the window.\n var buttongrp = document.createElement('div');\n buttongrp.classList = 'btn-group inline pull-right';\n button = document.createElement('button');\n button.classList = 'btn btn-mini btn-primary';\n button.href = '#';\n button.title = 'Stop Interaction';\n button.innerHTML = '';\n button.addEventListener('click', function (_evt) {\n fig.handle_close(fig, {});\n });\n button.addEventListener(\n 'mouseover',\n on_mouseover_closure('Stop Interaction')\n );\n buttongrp.appendChild(button);\n var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n var fig = event.data.fig;\n if (event.target !== this) {\n // Ignore bubbled events from children.\n return;\n }\n fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n // this is important to make the div 'focusable\n el.setAttribute('tabindex', 0);\n // reach out to IPython and tell the keyboard manager to turn it's self\n // off when our div gets focus\n\n // location in version 3\n if (IPython.notebook.keyboard_manager) {\n IPython.notebook.keyboard_manager.register_events(el);\n } else {\n // location in version 2\n IPython.keyboard_manager.register_events(el);\n }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n var manager = IPython.notebook.keyboard_manager;\n if (!manager) {\n manager = IPython.keyboard_manager;\n }\n\n // Check for shift+enter\n if (event.shiftKey && event.which === 13) {\n this.canvas_div.blur();\n // select the cell after this one\n var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n IPython.notebook.select(index + 1);\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n // Return the cell and output element which can be found *uniquely* in the notebook.\n // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n // IPython event is triggered only after the cells have been serialised, which for\n // our purposes (turning an active figure into a static one), is too late.\n var cells = IPython.notebook.get_cells();\n var ncells = cells.length;\n for (var i = 0; i < ncells; i++) {\n var cell = cells[i];\n if (cell.cell_type === 'code') {\n for (var j = 0; j < cell.output_area.outputs.length; j++) {\n var data = cell.output_area.outputs[j];\n if (data.data) {\n // IPython >= 3 moved mimebundle to data attribute of output\n data = data.data;\n }\n if (data['text/html'] === html_output) {\n return [cell, data, j];\n }\n }\n }\n }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n IPython.notebook.kernel.comm_manager.register_target(\n 'matplotlib',\n mpl.mpl_figure_comm\n );\n}\n", "text/plain": [ "" ] @@ -16822,955 +1654,7 @@ }, { "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "/* global mpl */\n", - "window.mpl = {};\n", - "\n", - "mpl.get_websocket_type = function () {\n", - " if (typeof WebSocket !== 'undefined') {\n", - " return WebSocket;\n", - " } else if (typeof MozWebSocket !== 'undefined') {\n", - " return MozWebSocket;\n", - " } else {\n", - " alert(\n", - " 'Your browser does not have WebSocket support. ' +\n", - " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", - " 'Firefox 4 and 5 are also supported but you ' +\n", - " 'have to enable WebSockets in about:config.'\n", - " );\n", - " }\n", - "};\n", - "\n", - "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", - " this.id = figure_id;\n", - "\n", - " this.ws = websocket;\n", - "\n", - " this.supports_binary = this.ws.binaryType !== undefined;\n", - "\n", - " if (!this.supports_binary) {\n", - " var warnings = document.getElementById('mpl-warnings');\n", - " if (warnings) {\n", - " warnings.style.display = 'block';\n", - " warnings.textContent =\n", - " 'This browser does not support binary websocket messages. ' +\n", - " 'Performance may be slow.';\n", - " }\n", - " }\n", - "\n", - " this.imageObj = new Image();\n", - "\n", - " this.context = undefined;\n", - " this.message = undefined;\n", - " this.canvas = undefined;\n", - " this.rubberband_canvas = undefined;\n", - " this.rubberband_context = undefined;\n", - " this.format_dropdown = undefined;\n", - "\n", - " this.image_mode = 'full';\n", - "\n", - " this.root = document.createElement('div');\n", - " this.root.setAttribute('style', 'display: inline-block');\n", - " this._root_extra_style(this.root);\n", - "\n", - " parent_element.appendChild(this.root);\n", - "\n", - " this._init_header(this);\n", - " this._init_canvas(this);\n", - " this._init_toolbar(this);\n", - "\n", - " var fig = this;\n", - "\n", - " this.waiting = false;\n", - "\n", - " this.ws.onopen = function () {\n", - " fig.send_message('supports_binary', { value: fig.supports_binary });\n", - " fig.send_message('send_image_mode', {});\n", - " if (fig.ratio !== 1) {\n", - " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", - " }\n", - " fig.send_message('refresh', {});\n", - " };\n", - "\n", - " this.imageObj.onload = function () {\n", - " if (fig.image_mode === 'full') {\n", - " // Full images could contain transparency (where diff images\n", - " // almost always do), so we need to clear the canvas so that\n", - " // there is no ghosting.\n", - " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", - " }\n", - " fig.context.drawImage(fig.imageObj, 0, 0);\n", - " };\n", - "\n", - " this.imageObj.onunload = function () {\n", - " fig.ws.close();\n", - " };\n", - "\n", - " this.ws.onmessage = this._make_on_message_function(this);\n", - "\n", - " this.ondownload = ondownload;\n", - "};\n", - "\n", - "mpl.figure.prototype._init_header = function () {\n", - " var titlebar = document.createElement('div');\n", - " titlebar.classList =\n", - " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", - " var titletext = document.createElement('div');\n", - " titletext.classList = 'ui-dialog-title';\n", - " titletext.setAttribute(\n", - " 'style',\n", - " 'width: 100%; text-align: center; padding: 3px;'\n", - " );\n", - " titlebar.appendChild(titletext);\n", - " this.root.appendChild(titlebar);\n", - " this.header = titletext;\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._init_canvas = function () {\n", - " var fig = this;\n", - "\n", - " var canvas_div = (this.canvas_div = document.createElement('div'));\n", - " canvas_div.setAttribute(\n", - " 'style',\n", - " 'border: 1px solid #ddd;' +\n", - " 'box-sizing: content-box;' +\n", - " 'clear: both;' +\n", - " 'min-height: 1px;' +\n", - " 'min-width: 1px;' +\n", - " 'outline: 0;' +\n", - " 'overflow: hidden;' +\n", - " 'position: relative;' +\n", - " 'resize: both;'\n", - " );\n", - "\n", - " function on_keyboard_event_closure(name) {\n", - " return function (event) {\n", - " return fig.key_event(event, name);\n", - " };\n", - " }\n", - "\n", - " canvas_div.addEventListener(\n", - " 'keydown',\n", - " on_keyboard_event_closure('key_press')\n", - " );\n", - " canvas_div.addEventListener(\n", - " 'keyup',\n", - " on_keyboard_event_closure('key_release')\n", - " );\n", - "\n", - " this._canvas_extra_style(canvas_div);\n", - " this.root.appendChild(canvas_div);\n", - "\n", - " var canvas = (this.canvas = document.createElement('canvas'));\n", - " canvas.classList.add('mpl-canvas');\n", - " canvas.setAttribute('style', 'box-sizing: content-box;');\n", - "\n", - " this.context = canvas.getContext('2d');\n", - "\n", - " var backingStore =\n", - " this.context.backingStorePixelRatio ||\n", - " this.context.webkitBackingStorePixelRatio ||\n", - " this.context.mozBackingStorePixelRatio ||\n", - " this.context.msBackingStorePixelRatio ||\n", - " this.context.oBackingStorePixelRatio ||\n", - " this.context.backingStorePixelRatio ||\n", - " 1;\n", - "\n", - " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", - "\n", - " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", - " 'canvas'\n", - " ));\n", - " rubberband_canvas.setAttribute(\n", - " 'style',\n", - " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", - " );\n", - "\n", - " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", - " if (this.ResizeObserver === undefined) {\n", - " if (window.ResizeObserver !== undefined) {\n", - " this.ResizeObserver = window.ResizeObserver;\n", - " } else {\n", - " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", - " this.ResizeObserver = obs.ResizeObserver;\n", - " }\n", - " }\n", - "\n", - " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", - " var nentries = entries.length;\n", - " for (var i = 0; i < nentries; i++) {\n", - " var entry = entries[i];\n", - " var width, height;\n", - " if (entry.contentBoxSize) {\n", - " if (entry.contentBoxSize instanceof Array) {\n", - " // Chrome 84 implements new version of spec.\n", - " width = entry.contentBoxSize[0].inlineSize;\n", - " height = entry.contentBoxSize[0].blockSize;\n", - " } else {\n", - " // Firefox implements old version of spec.\n", - " width = entry.contentBoxSize.inlineSize;\n", - " height = entry.contentBoxSize.blockSize;\n", - " }\n", - " } else {\n", - " // Chrome <84 implements even older version of spec.\n", - " width = entry.contentRect.width;\n", - " height = entry.contentRect.height;\n", - " }\n", - "\n", - " // Keep the size of the canvas and rubber band canvas in sync with\n", - " // the canvas container.\n", - " if (entry.devicePixelContentBoxSize) {\n", - " // Chrome 84 implements new version of spec.\n", - " canvas.setAttribute(\n", - " 'width',\n", - " entry.devicePixelContentBoxSize[0].inlineSize\n", - " );\n", - " canvas.setAttribute(\n", - " 'height',\n", - " entry.devicePixelContentBoxSize[0].blockSize\n", - " );\n", - " } else {\n", - " canvas.setAttribute('width', width * fig.ratio);\n", - " canvas.setAttribute('height', height * fig.ratio);\n", - " }\n", - " canvas.setAttribute(\n", - " 'style',\n", - " 'width: ' + width + 'px; height: ' + height + 'px;'\n", - " );\n", - "\n", - " rubberband_canvas.setAttribute('width', width);\n", - " rubberband_canvas.setAttribute('height', height);\n", - "\n", - " // And update the size in Python. We ignore the initial 0/0 size\n", - " // that occurs as the element is placed into the DOM, which should\n", - " // otherwise not happen due to the minimum size styling.\n", - " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", - " fig.request_resize(width, height);\n", - " }\n", - " }\n", - " });\n", - " this.resizeObserverInstance.observe(canvas_div);\n", - "\n", - " function on_mouse_event_closure(name) {\n", - " return function (event) {\n", - " return fig.mouse_event(event, name);\n", - " };\n", - " }\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mousedown',\n", - " on_mouse_event_closure('button_press')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseup',\n", - " on_mouse_event_closure('button_release')\n", - " );\n", - " // Throttle sequential mouse events to 1 every 20ms.\n", - " rubberband_canvas.addEventListener(\n", - " 'mousemove',\n", - " on_mouse_event_closure('motion_notify')\n", - " );\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseenter',\n", - " on_mouse_event_closure('figure_enter')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseleave',\n", - " on_mouse_event_closure('figure_leave')\n", - " );\n", - "\n", - " canvas_div.addEventListener('wheel', function (event) {\n", - " if (event.deltaY < 0) {\n", - " event.step = 1;\n", - " } else {\n", - " event.step = -1;\n", - " }\n", - " on_mouse_event_closure('scroll')(event);\n", - " });\n", - "\n", - " canvas_div.appendChild(canvas);\n", - " canvas_div.appendChild(rubberband_canvas);\n", - "\n", - " this.rubberband_context = rubberband_canvas.getContext('2d');\n", - " this.rubberband_context.strokeStyle = '#000000';\n", - "\n", - " this._resize_canvas = function (width, height, forward) {\n", - " if (forward) {\n", - " canvas_div.style.width = width + 'px';\n", - " canvas_div.style.height = height + 'px';\n", - " }\n", - " };\n", - "\n", - " // Disable right mouse context menu.\n", - " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", - " event.preventDefault();\n", - " return false;\n", - " });\n", - "\n", - " function set_focus() {\n", - " canvas.focus();\n", - " canvas_div.focus();\n", - " }\n", - "\n", - " window.setTimeout(set_focus, 100);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'mpl-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " continue;\n", - " }\n", - "\n", - " var button = (fig.buttons[name] = document.createElement('button'));\n", - " button.classList = 'mpl-widget';\n", - " button.setAttribute('role', 'button');\n", - " button.setAttribute('aria-disabled', 'false');\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - "\n", - " var icon_img = document.createElement('img');\n", - " icon_img.src = '_images/' + image + '.png';\n", - " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", - " icon_img.alt = tooltip;\n", - " button.appendChild(icon_img);\n", - "\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " var fmt_picker = document.createElement('select');\n", - " fmt_picker.classList = 'mpl-widget';\n", - " toolbar.appendChild(fmt_picker);\n", - " this.format_dropdown = fmt_picker;\n", - "\n", - " for (var ind in mpl.extensions) {\n", - " var fmt = mpl.extensions[ind];\n", - " var option = document.createElement('option');\n", - " option.selected = fmt === mpl.default_extension;\n", - " option.innerHTML = fmt;\n", - " fmt_picker.appendChild(option);\n", - " }\n", - "\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "};\n", - "\n", - "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", - " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", - " // which will in turn request a refresh of the image.\n", - " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", - "};\n", - "\n", - "mpl.figure.prototype.send_message = function (type, properties) {\n", - " properties['type'] = type;\n", - " properties['figure_id'] = this.id;\n", - " this.ws.send(JSON.stringify(properties));\n", - "};\n", - "\n", - "mpl.figure.prototype.send_draw_message = function () {\n", - " if (!this.waiting) {\n", - " this.waiting = true;\n", - " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " var format_dropdown = fig.format_dropdown;\n", - " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", - " fig.ondownload(fig, format);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", - " var size = msg['size'];\n", - " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", - " fig._resize_canvas(size[0], size[1], msg['forward']);\n", - " fig.send_message('refresh', {});\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", - " var x0 = msg['x0'] / fig.ratio;\n", - " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", - " var x1 = msg['x1'] / fig.ratio;\n", - " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", - " x0 = Math.floor(x0) + 0.5;\n", - " y0 = Math.floor(y0) + 0.5;\n", - " x1 = Math.floor(x1) + 0.5;\n", - " y1 = Math.floor(y1) + 0.5;\n", - " var min_x = Math.min(x0, x1);\n", - " var min_y = Math.min(y0, y1);\n", - " var width = Math.abs(x1 - x0);\n", - " var height = Math.abs(y1 - y0);\n", - "\n", - " fig.rubberband_context.clearRect(\n", - " 0,\n", - " 0,\n", - " fig.canvas.width / fig.ratio,\n", - " fig.canvas.height / fig.ratio\n", - " );\n", - "\n", - " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", - " // Updates the figure title.\n", - " fig.header.textContent = msg['label'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", - " var cursor = msg['cursor'];\n", - " switch (cursor) {\n", - " case 0:\n", - " cursor = 'pointer';\n", - " break;\n", - " case 1:\n", - " cursor = 'default';\n", - " break;\n", - " case 2:\n", - " cursor = 'crosshair';\n", - " break;\n", - " case 3:\n", - " cursor = 'move';\n", - " break;\n", - " }\n", - " fig.rubberband_canvas.style.cursor = cursor;\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_message = function (fig, msg) {\n", - " fig.message.textContent = msg['message'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", - " // Request the server to send over a new figure.\n", - " fig.send_draw_message();\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", - " fig.image_mode = msg['mode'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", - " for (var key in msg) {\n", - " if (!(key in fig.buttons)) {\n", - " continue;\n", - " }\n", - " fig.buttons[key].disabled = !msg[key];\n", - " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", - " if (msg['mode'] === 'PAN') {\n", - " fig.buttons['Pan'].classList.add('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " } else if (msg['mode'] === 'ZOOM') {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.add('active');\n", - " } else {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Called whenever the canvas gets updated.\n", - " this.send_message('ack', {});\n", - "};\n", - "\n", - "// A function to construct a web socket function for onmessage handling.\n", - "// Called in the figure constructor.\n", - "mpl.figure.prototype._make_on_message_function = function (fig) {\n", - " return function socket_on_message(evt) {\n", - " if (evt.data instanceof Blob) {\n", - " /* FIXME: We get \"Resource interpreted as Image but\n", - " * transferred with MIME type text/plain:\" errors on\n", - " * Chrome. But how to set the MIME type? It doesn't seem\n", - " * to be part of the websocket stream */\n", - " evt.data.type = 'image/png';\n", - "\n", - " /* Free the memory for the previous frames */\n", - " if (fig.imageObj.src) {\n", - " (window.URL || window.webkitURL).revokeObjectURL(\n", - " fig.imageObj.src\n", - " );\n", - " }\n", - "\n", - " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", - " evt.data\n", - " );\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " } else if (\n", - " typeof evt.data === 'string' &&\n", - " evt.data.slice(0, 21) === 'data:image/png;base64'\n", - " ) {\n", - " fig.imageObj.src = evt.data;\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " }\n", - "\n", - " var msg = JSON.parse(evt.data);\n", - " var msg_type = msg['type'];\n", - "\n", - " // Call the \"handle_{type}\" callback, which takes\n", - " // the figure and JSON message as its only arguments.\n", - " try {\n", - " var callback = fig['handle_' + msg_type];\n", - " } catch (e) {\n", - " console.log(\n", - " \"No handler for the '\" + msg_type + \"' message type: \",\n", - " msg\n", - " );\n", - " return;\n", - " }\n", - "\n", - " if (callback) {\n", - " try {\n", - " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", - " callback(fig, msg);\n", - " } catch (e) {\n", - " console.log(\n", - " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", - " e,\n", - " e.stack,\n", - " msg\n", - " );\n", - " }\n", - " }\n", - " };\n", - "};\n", - "\n", - "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", - "mpl.findpos = function (e) {\n", - " //this section is from http://www.quirksmode.org/js/events_properties.html\n", - " var targ;\n", - " if (!e) {\n", - " e = window.event;\n", - " }\n", - " if (e.target) {\n", - " targ = e.target;\n", - " } else if (e.srcElement) {\n", - " targ = e.srcElement;\n", - " }\n", - " if (targ.nodeType === 3) {\n", - " // defeat Safari bug\n", - " targ = targ.parentNode;\n", - " }\n", - "\n", - " // pageX,Y are the mouse positions relative to the document\n", - " var boundingRect = targ.getBoundingClientRect();\n", - " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", - " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", - "\n", - " return { x: x, y: y };\n", - "};\n", - "\n", - "/*\n", - " * return a copy of an object with only non-object keys\n", - " * we need this to avoid circular references\n", - " * http://stackoverflow.com/a/24161582/3208463\n", - " */\n", - "function simpleKeys(original) {\n", - " return Object.keys(original).reduce(function (obj, key) {\n", - " if (typeof original[key] !== 'object') {\n", - " obj[key] = original[key];\n", - " }\n", - " return obj;\n", - " }, {});\n", - "}\n", - "\n", - "mpl.figure.prototype.mouse_event = function (event, name) {\n", - " var canvas_pos = mpl.findpos(event);\n", - "\n", - " if (name === 'button_press') {\n", - " this.canvas.focus();\n", - " this.canvas_div.focus();\n", - " }\n", - "\n", - " var x = canvas_pos.x * this.ratio;\n", - " var y = canvas_pos.y * this.ratio;\n", - "\n", - " this.send_message(name, {\n", - " x: x,\n", - " y: y,\n", - " button: event.button,\n", - " step: event.step,\n", - " guiEvent: simpleKeys(event),\n", - " });\n", - "\n", - " /* This prevents the web browser from automatically changing to\n", - " * the text insertion cursor when the button is pressed. We want\n", - " * to control all of the cursor setting manually through the\n", - " * 'cursor' event from matplotlib */\n", - " event.preventDefault();\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", - " // Handle any extra behaviour associated with a key event\n", - "};\n", - "\n", - "mpl.figure.prototype.key_event = function (event, name) {\n", - " // Prevent repeat events\n", - " if (name === 'key_press') {\n", - " if (event.which === this._key) {\n", - " return;\n", - " } else {\n", - " this._key = event.which;\n", - " }\n", - " }\n", - " if (name === 'key_release') {\n", - " this._key = null;\n", - " }\n", - "\n", - " var value = '';\n", - " if (event.ctrlKey && event.which !== 17) {\n", - " value += 'ctrl+';\n", - " }\n", - " if (event.altKey && event.which !== 18) {\n", - " value += 'alt+';\n", - " }\n", - " if (event.shiftKey && event.which !== 16) {\n", - " value += 'shift+';\n", - " }\n", - "\n", - " value += 'k';\n", - " value += event.which.toString();\n", - "\n", - " this._key_event_extra(event, name);\n", - "\n", - " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", - " if (name === 'download') {\n", - " this.handle_save(this, null);\n", - " } else {\n", - " this.send_message('toolbar_button', { name: name });\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", - " this.message.textContent = tooltip;\n", - "};\n", - "\n", - "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", - "// prettier-ignore\n", - "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", - "\n", - "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", - "\n", - "mpl.default_extension = \"png\";/* global mpl */\n", - "\n", - "var comm_websocket_adapter = function (comm) {\n", - " // Create a \"websocket\"-like object which calls the given IPython comm\n", - " // object with the appropriate methods. Currently this is a non binary\n", - " // socket, so there is still some room for performance tuning.\n", - " var ws = {};\n", - "\n", - " ws.close = function () {\n", - " comm.close();\n", - " };\n", - " ws.send = function (m) {\n", - " //console.log('sending', m);\n", - " comm.send(m);\n", - " };\n", - " // Register the callback with on_msg.\n", - " comm.on_msg(function (msg) {\n", - " //console.log('receiving', msg['content']['data'], msg);\n", - " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", - " ws.onmessage(msg['content']['data']);\n", - " });\n", - " return ws;\n", - "};\n", - "\n", - "mpl.mpl_figure_comm = function (comm, msg) {\n", - " // This is the function which gets called when the mpl process\n", - " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", - "\n", - " var id = msg.content.data.id;\n", - " // Get hold of the div created by the display call when the Comm\n", - " // socket was opened in Python.\n", - " var element = document.getElementById(id);\n", - " var ws_proxy = comm_websocket_adapter(comm);\n", - "\n", - " function ondownload(figure, _format) {\n", - " window.open(figure.canvas.toDataURL());\n", - " }\n", - "\n", - " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", - "\n", - " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", - " // web socket which is closed, not our websocket->open comm proxy.\n", - " ws_proxy.onopen();\n", - "\n", - " fig.parent_element = element;\n", - " fig.cell_info = mpl.find_output_cell(\"
\");\n", - " if (!fig.cell_info) {\n", - " console.error('Failed to find cell for figure', id, fig);\n", - " return;\n", - " }\n", - " fig.cell_info[0].output_area.element.on(\n", - " 'cleared',\n", - " { fig: fig },\n", - " fig._remove_fig_handler\n", - " );\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_close = function (fig, msg) {\n", - " var width = fig.canvas.width / fig.ratio;\n", - " fig.cell_info[0].output_area.element.off(\n", - " 'cleared',\n", - " fig._remove_fig_handler\n", - " );\n", - " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", - "\n", - " // Update the output cell to use the data from the current canvas.\n", - " fig.push_to_output();\n", - " var dataURL = fig.canvas.toDataURL();\n", - " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", - " // the notebook keyboard shortcuts fail.\n", - " IPython.keyboard_manager.enable();\n", - " fig.parent_element.innerHTML =\n", - " '';\n", - " fig.close_ws(fig, msg);\n", - "};\n", - "\n", - "mpl.figure.prototype.close_ws = function (fig, msg) {\n", - " fig.send_message('closing', msg);\n", - " // fig.ws.close()\n", - "};\n", - "\n", - "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", - " // Turn the data on the canvas into data in the output cell.\n", - " var width = this.canvas.width / this.ratio;\n", - " var dataURL = this.canvas.toDataURL();\n", - " this.cell_info[1]['text/html'] =\n", - " '';\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Tell IPython that the notebook contents must change.\n", - " IPython.notebook.set_dirty(true);\n", - " this.send_message('ack', {});\n", - " var fig = this;\n", - " // Wait a second, then push the new image to the DOM so\n", - " // that it is saved nicely (might be nice to debounce this).\n", - " setTimeout(function () {\n", - " fig.push_to_output();\n", - " }, 1000);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'btn-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " var button;\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " continue;\n", - " }\n", - "\n", - " button = fig.buttons[name] = document.createElement('button');\n", - " button.classList = 'btn btn-default';\n", - " button.href = '#';\n", - " button.title = name;\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " // Add the status bar.\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message pull-right';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "\n", - " // Add the close button to the window.\n", - " var buttongrp = document.createElement('div');\n", - " buttongrp.classList = 'btn-group inline pull-right';\n", - " button = document.createElement('button');\n", - " button.classList = 'btn btn-mini btn-primary';\n", - " button.href = '#';\n", - " button.title = 'Stop Interaction';\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', function (_evt) {\n", - " fig.handle_close(fig, {});\n", - " });\n", - " button.addEventListener(\n", - " 'mouseover',\n", - " on_mouseover_closure('Stop Interaction')\n", - " );\n", - " buttongrp.appendChild(button);\n", - " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", - " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", - "};\n", - "\n", - "mpl.figure.prototype._remove_fig_handler = function (event) {\n", - " var fig = event.data.fig;\n", - " if (event.target !== this) {\n", - " // Ignore bubbled events from children.\n", - " return;\n", - " }\n", - " fig.close_ws(fig, {});\n", - "};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (el) {\n", - " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (el) {\n", - " // this is important to make the div 'focusable\n", - " el.setAttribute('tabindex', 0);\n", - " // reach out to IPython and tell the keyboard manager to turn it's self\n", - " // off when our div gets focus\n", - "\n", - " // location in version 3\n", - " if (IPython.notebook.keyboard_manager) {\n", - " IPython.notebook.keyboard_manager.register_events(el);\n", - " } else {\n", - " // location in version 2\n", - " IPython.keyboard_manager.register_events(el);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", - " var manager = IPython.notebook.keyboard_manager;\n", - " if (!manager) {\n", - " manager = IPython.keyboard_manager;\n", - " }\n", - "\n", - " // Check for shift+enter\n", - " if (event.shiftKey && event.which === 13) {\n", - " this.canvas_div.blur();\n", - " // select the cell after this one\n", - " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", - " IPython.notebook.select(index + 1);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " fig.ondownload(fig, null);\n", - "};\n", - "\n", - "mpl.find_output_cell = function (html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i = 0; i < ncells; i++) {\n", - " var cell = cells[i];\n", - " if (cell.cell_type === 'code') {\n", - " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", - " var data = cell.output_area.outputs[j];\n", - " if (data.data) {\n", - " // IPython >= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] === html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "};\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel !== null) {\n", - " IPython.notebook.kernel.comm_manager.register_target(\n", - " 'matplotlib',\n", - " mpl.mpl_figure_comm\n", - " );\n", - "}\n" - ], + "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n if (typeof WebSocket !== 'undefined') {\n return WebSocket;\n } else if (typeof MozWebSocket !== 'undefined') {\n return MozWebSocket;\n } else {\n alert(\n 'Your browser does not have WebSocket support. ' +\n 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n 'Firefox 4 and 5 are also supported but you ' +\n 'have to enable WebSockets in about:config.'\n );\n }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n this.id = figure_id;\n\n this.ws = websocket;\n\n this.supports_binary = this.ws.binaryType !== undefined;\n\n if (!this.supports_binary) {\n var warnings = document.getElementById('mpl-warnings');\n if (warnings) {\n warnings.style.display = 'block';\n warnings.textContent =\n 'This browser does not support binary websocket messages. ' +\n 'Performance may be slow.';\n }\n }\n\n this.imageObj = new Image();\n\n this.context = undefined;\n this.message = undefined;\n this.canvas = undefined;\n this.rubberband_canvas = undefined;\n this.rubberband_context = undefined;\n this.format_dropdown = undefined;\n\n this.image_mode = 'full';\n\n this.root = document.createElement('div');\n this.root.setAttribute('style', 'display: inline-block');\n this._root_extra_style(this.root);\n\n parent_element.appendChild(this.root);\n\n this._init_header(this);\n this._init_canvas(this);\n this._init_toolbar(this);\n\n var fig = this;\n\n this.waiting = false;\n\n this.ws.onopen = function () {\n fig.send_message('supports_binary', { value: fig.supports_binary });\n fig.send_message('send_image_mode', {});\n if (fig.ratio !== 1) {\n fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n }\n fig.send_message('refresh', {});\n };\n\n this.imageObj.onload = function () {\n if (fig.image_mode === 'full') {\n // Full images could contain transparency (where diff images\n // almost always do), so we need to clear the canvas so that\n // there is no ghosting.\n fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n }\n fig.context.drawImage(fig.imageObj, 0, 0);\n };\n\n this.imageObj.onunload = function () {\n fig.ws.close();\n };\n\n this.ws.onmessage = this._make_on_message_function(this);\n\n this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n var titlebar = document.createElement('div');\n titlebar.classList =\n 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n var titletext = document.createElement('div');\n titletext.classList = 'ui-dialog-title';\n titletext.setAttribute(\n 'style',\n 'width: 100%; text-align: center; padding: 3px;'\n );\n titlebar.appendChild(titletext);\n this.root.appendChild(titlebar);\n this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n var fig = this;\n\n var canvas_div = (this.canvas_div = document.createElement('div'));\n canvas_div.setAttribute(\n 'style',\n 'border: 1px solid #ddd;' +\n 'box-sizing: content-box;' +\n 'clear: both;' +\n 'min-height: 1px;' +\n 'min-width: 1px;' +\n 'outline: 0;' +\n 'overflow: hidden;' +\n 'position: relative;' +\n 'resize: both;'\n );\n\n function on_keyboard_event_closure(name) {\n return function (event) {\n return fig.key_event(event, name);\n };\n }\n\n canvas_div.addEventListener(\n 'keydown',\n on_keyboard_event_closure('key_press')\n );\n canvas_div.addEventListener(\n 'keyup',\n on_keyboard_event_closure('key_release')\n );\n\n this._canvas_extra_style(canvas_div);\n this.root.appendChild(canvas_div);\n\n var canvas = (this.canvas = document.createElement('canvas'));\n canvas.classList.add('mpl-canvas');\n canvas.setAttribute('style', 'box-sizing: content-box;');\n\n this.context = canvas.getContext('2d');\n\n var backingStore =\n this.context.backingStorePixelRatio ||\n this.context.webkitBackingStorePixelRatio ||\n this.context.mozBackingStorePixelRatio ||\n this.context.msBackingStorePixelRatio ||\n this.context.oBackingStorePixelRatio ||\n this.context.backingStorePixelRatio ||\n 1;\n\n this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n 'canvas'\n ));\n rubberband_canvas.setAttribute(\n 'style',\n 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n );\n\n // Apply a ponyfill if ResizeObserver is not implemented by browser.\n if (this.ResizeObserver === undefined) {\n if (window.ResizeObserver !== undefined) {\n this.ResizeObserver = window.ResizeObserver;\n } else {\n var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n this.ResizeObserver = obs.ResizeObserver;\n }\n }\n\n this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n var nentries = entries.length;\n for (var i = 0; i < nentries; i++) {\n var entry = entries[i];\n var width, height;\n if (entry.contentBoxSize) {\n if (entry.contentBoxSize instanceof Array) {\n // Chrome 84 implements new version of spec.\n width = entry.contentBoxSize[0].inlineSize;\n height = entry.contentBoxSize[0].blockSize;\n } else {\n // Firefox implements old version of spec.\n width = entry.contentBoxSize.inlineSize;\n height = entry.contentBoxSize.blockSize;\n }\n } else {\n // Chrome <84 implements even older version of spec.\n width = entry.contentRect.width;\n height = entry.contentRect.height;\n }\n\n // Keep the size of the canvas and rubber band canvas in sync with\n // the canvas container.\n if (entry.devicePixelContentBoxSize) {\n // Chrome 84 implements new version of spec.\n canvas.setAttribute(\n 'width',\n entry.devicePixelContentBoxSize[0].inlineSize\n );\n canvas.setAttribute(\n 'height',\n entry.devicePixelContentBoxSize[0].blockSize\n );\n } else {\n canvas.setAttribute('width', width * fig.ratio);\n canvas.setAttribute('height', height * fig.ratio);\n }\n canvas.setAttribute(\n 'style',\n 'width: ' + width + 'px; height: ' + height + 'px;'\n );\n\n rubberband_canvas.setAttribute('width', width);\n rubberband_canvas.setAttribute('height', height);\n\n // And update the size in Python. We ignore the initial 0/0 size\n // that occurs as the element is placed into the DOM, which should\n // otherwise not happen due to the minimum size styling.\n if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n fig.request_resize(width, height);\n }\n }\n });\n this.resizeObserverInstance.observe(canvas_div);\n\n function on_mouse_event_closure(name) {\n return function (event) {\n return fig.mouse_event(event, name);\n };\n }\n\n rubberband_canvas.addEventListener(\n 'mousedown',\n on_mouse_event_closure('button_press')\n );\n rubberband_canvas.addEventListener(\n 'mouseup',\n on_mouse_event_closure('button_release')\n );\n // Throttle sequential mouse events to 1 every 20ms.\n rubberband_canvas.addEventListener(\n 'mousemove',\n on_mouse_event_closure('motion_notify')\n );\n\n rubberband_canvas.addEventListener(\n 'mouseenter',\n on_mouse_event_closure('figure_enter')\n );\n rubberband_canvas.addEventListener(\n 'mouseleave',\n on_mouse_event_closure('figure_leave')\n );\n\n canvas_div.addEventListener('wheel', function (event) {\n if (event.deltaY < 0) {\n event.step = 1;\n } else {\n event.step = -1;\n }\n on_mouse_event_closure('scroll')(event);\n });\n\n canvas_div.appendChild(canvas);\n canvas_div.appendChild(rubberband_canvas);\n\n this.rubberband_context = rubberband_canvas.getContext('2d');\n this.rubberband_context.strokeStyle = '#000000';\n\n this._resize_canvas = function (width, height, forward) {\n if (forward) {\n canvas_div.style.width = width + 'px';\n canvas_div.style.height = height + 'px';\n }\n };\n\n // Disable right mouse context menu.\n this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n event.preventDefault();\n return false;\n });\n\n function set_focus() {\n canvas.focus();\n canvas_div.focus();\n }\n\n window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'mpl-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n continue;\n }\n\n var button = (fig.buttons[name] = document.createElement('button'));\n button.classList = 'mpl-widget';\n button.setAttribute('role', 'button');\n button.setAttribute('aria-disabled', 'false');\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n var icon_img = document.createElement('img');\n icon_img.src = '_images/' + image + '.png';\n icon_img.srcset = '_images/' + image + '_large.png 2x';\n icon_img.alt = tooltip;\n button.appendChild(icon_img);\n\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n var fmt_picker = document.createElement('select');\n fmt_picker.classList = 'mpl-widget';\n toolbar.appendChild(fmt_picker);\n this.format_dropdown = fmt_picker;\n\n for (var ind in mpl.extensions) {\n var fmt = mpl.extensions[ind];\n var option = document.createElement('option');\n option.selected = fmt === mpl.default_extension;\n option.innerHTML = fmt;\n fmt_picker.appendChild(option);\n }\n\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n // which will in turn request a refresh of the image.\n this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n properties['type'] = type;\n properties['figure_id'] = this.id;\n this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n if (!this.waiting) {\n this.waiting = true;\n this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n var format_dropdown = fig.format_dropdown;\n var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n var size = msg['size'];\n if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n fig._resize_canvas(size[0], size[1], msg['forward']);\n fig.send_message('refresh', {});\n }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n var x0 = msg['x0'] / fig.ratio;\n var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n var x1 = msg['x1'] / fig.ratio;\n var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n x0 = Math.floor(x0) + 0.5;\n y0 = Math.floor(y0) + 0.5;\n x1 = Math.floor(x1) + 0.5;\n y1 = Math.floor(y1) + 0.5;\n var min_x = Math.min(x0, x1);\n var min_y = Math.min(y0, y1);\n var width = Math.abs(x1 - x0);\n var height = Math.abs(y1 - y0);\n\n fig.rubberband_context.clearRect(\n 0,\n 0,\n fig.canvas.width / fig.ratio,\n fig.canvas.height / fig.ratio\n );\n\n fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n // Updates the figure title.\n fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n var cursor = msg['cursor'];\n switch (cursor) {\n case 0:\n cursor = 'pointer';\n break;\n case 1:\n cursor = 'default';\n break;\n case 2:\n cursor = 'crosshair';\n break;\n case 3:\n cursor = 'move';\n break;\n }\n fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n // Request the server to send over a new figure.\n fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n for (var key in msg) {\n if (!(key in fig.buttons)) {\n continue;\n }\n fig.buttons[key].disabled = !msg[key];\n fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n if (msg['mode'] === 'PAN') {\n fig.buttons['Pan'].classList.add('active');\n fig.buttons['Zoom'].classList.remove('active');\n } else if (msg['mode'] === 'ZOOM') {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.add('active');\n } else {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.remove('active');\n }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Called whenever the canvas gets updated.\n this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n return function socket_on_message(evt) {\n if (evt.data instanceof Blob) {\n /* FIXME: We get \"Resource interpreted as Image but\n * transferred with MIME type text/plain:\" errors on\n * Chrome. But how to set the MIME type? It doesn't seem\n * to be part of the websocket stream */\n evt.data.type = 'image/png';\n\n /* Free the memory for the previous frames */\n if (fig.imageObj.src) {\n (window.URL || window.webkitURL).revokeObjectURL(\n fig.imageObj.src\n );\n }\n\n fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n evt.data\n );\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n } else if (\n typeof evt.data === 'string' &&\n evt.data.slice(0, 21) === 'data:image/png;base64'\n ) {\n fig.imageObj.src = evt.data;\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n }\n\n var msg = JSON.parse(evt.data);\n var msg_type = msg['type'];\n\n // Call the \"handle_{type}\" callback, which takes\n // the figure and JSON message as its only arguments.\n try {\n var callback = fig['handle_' + msg_type];\n } catch (e) {\n console.log(\n \"No handler for the '\" + msg_type + \"' message type: \",\n msg\n );\n return;\n }\n\n if (callback) {\n try {\n // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n callback(fig, msg);\n } catch (e) {\n console.log(\n \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n e,\n e.stack,\n msg\n );\n }\n }\n };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n //this section is from http://www.quirksmode.org/js/events_properties.html\n var targ;\n if (!e) {\n e = window.event;\n }\n if (e.target) {\n targ = e.target;\n } else if (e.srcElement) {\n targ = e.srcElement;\n }\n if (targ.nodeType === 3) {\n // defeat Safari bug\n targ = targ.parentNode;\n }\n\n // pageX,Y are the mouse positions relative to the document\n var boundingRect = targ.getBoundingClientRect();\n var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n return Object.keys(original).reduce(function (obj, key) {\n if (typeof original[key] !== 'object') {\n obj[key] = original[key];\n }\n return obj;\n }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n var canvas_pos = mpl.findpos(event);\n\n if (name === 'button_press') {\n this.canvas.focus();\n this.canvas_div.focus();\n }\n\n var x = canvas_pos.x * this.ratio;\n var y = canvas_pos.y * this.ratio;\n\n this.send_message(name, {\n x: x,\n y: y,\n button: event.button,\n step: event.step,\n guiEvent: simpleKeys(event),\n });\n\n /* This prevents the web browser from automatically changing to\n * the text insertion cursor when the button is pressed. We want\n * to control all of the cursor setting manually through the\n * 'cursor' event from matplotlib */\n event.preventDefault();\n return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n // Prevent repeat events\n if (name === 'key_press') {\n if (event.which === this._key) {\n return;\n } else {\n this._key = event.which;\n }\n }\n if (name === 'key_release') {\n this._key = null;\n }\n\n var value = '';\n if (event.ctrlKey && event.which !== 17) {\n value += 'ctrl+';\n }\n if (event.altKey && event.which !== 18) {\n value += 'alt+';\n }\n if (event.shiftKey && event.which !== 16) {\n value += 'shift+';\n }\n\n value += 'k';\n value += event.which.toString();\n\n this._key_event_extra(event, name);\n\n this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n if (name === 'download') {\n this.handle_save(this, null);\n } else {\n this.send_message('toolbar_button', { name: name });\n }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\nmpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n\nmpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n // Create a \"websocket\"-like object which calls the given IPython comm\n // object with the appropriate methods. Currently this is a non binary\n // socket, so there is still some room for performance tuning.\n var ws = {};\n\n ws.close = function () {\n comm.close();\n };\n ws.send = function (m) {\n //console.log('sending', m);\n comm.send(m);\n };\n // Register the callback with on_msg.\n comm.on_msg(function (msg) {\n //console.log('receiving', msg['content']['data'], msg);\n // Pass the mpl event to the overridden (by mpl) onmessage function.\n ws.onmessage(msg['content']['data']);\n });\n return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n // This is the function which gets called when the mpl process\n // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n var id = msg.content.data.id;\n // Get hold of the div created by the display call when the Comm\n // socket was opened in Python.\n var element = document.getElementById(id);\n var ws_proxy = comm_websocket_adapter(comm);\n\n function ondownload(figure, _format) {\n window.open(figure.canvas.toDataURL());\n }\n\n var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n // web socket which is closed, not our websocket->open comm proxy.\n ws_proxy.onopen();\n\n fig.parent_element = element;\n fig.cell_info = mpl.find_output_cell(\"
\");\n if (!fig.cell_info) {\n console.error('Failed to find cell for figure', id, fig);\n return;\n }\n fig.cell_info[0].output_area.element.on(\n 'cleared',\n { fig: fig },\n fig._remove_fig_handler\n );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n var width = fig.canvas.width / fig.ratio;\n fig.cell_info[0].output_area.element.off(\n 'cleared',\n fig._remove_fig_handler\n );\n fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n // Update the output cell to use the data from the current canvas.\n fig.push_to_output();\n var dataURL = fig.canvas.toDataURL();\n // Re-enable the keyboard manager in IPython - without this line, in FF,\n // the notebook keyboard shortcuts fail.\n IPython.keyboard_manager.enable();\n fig.parent_element.innerHTML =\n '';\n fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n fig.send_message('closing', msg);\n // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n // Turn the data on the canvas into data in the output cell.\n var width = this.canvas.width / this.ratio;\n var dataURL = this.canvas.toDataURL();\n this.cell_info[1]['text/html'] =\n '';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Tell IPython that the notebook contents must change.\n IPython.notebook.set_dirty(true);\n this.send_message('ack', {});\n var fig = this;\n // Wait a second, then push the new image to the DOM so\n // that it is saved nicely (might be nice to debounce this).\n setTimeout(function () {\n fig.push_to_output();\n }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'btn-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n var button;\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n continue;\n }\n\n button = fig.buttons[name] = document.createElement('button');\n button.classList = 'btn btn-default';\n button.href = '#';\n button.title = name;\n button.innerHTML = '';\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n // Add the status bar.\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message pull-right';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n\n // Add the close button to the window.\n var buttongrp = document.createElement('div');\n buttongrp.classList = 'btn-group inline pull-right';\n button = document.createElement('button');\n button.classList = 'btn btn-mini btn-primary';\n button.href = '#';\n button.title = 'Stop Interaction';\n button.innerHTML = '';\n button.addEventListener('click', function (_evt) {\n fig.handle_close(fig, {});\n });\n button.addEventListener(\n 'mouseover',\n on_mouseover_closure('Stop Interaction')\n );\n buttongrp.appendChild(button);\n var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n var fig = event.data.fig;\n if (event.target !== this) {\n // Ignore bubbled events from children.\n return;\n }\n fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n // this is important to make the div 'focusable\n el.setAttribute('tabindex', 0);\n // reach out to IPython and tell the keyboard manager to turn it's self\n // off when our div gets focus\n\n // location in version 3\n if (IPython.notebook.keyboard_manager) {\n IPython.notebook.keyboard_manager.register_events(el);\n } else {\n // location in version 2\n IPython.keyboard_manager.register_events(el);\n }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n var manager = IPython.notebook.keyboard_manager;\n if (!manager) {\n manager = IPython.keyboard_manager;\n }\n\n // Check for shift+enter\n if (event.shiftKey && event.which === 13) {\n this.canvas_div.blur();\n // select the cell after this one\n var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n IPython.notebook.select(index + 1);\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n // Return the cell and output element which can be found *uniquely* in the notebook.\n // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n // IPython event is triggered only after the cells have been serialised, which for\n // our purposes (turning an active figure into a static one), is too late.\n var cells = IPython.notebook.get_cells();\n var ncells = cells.length;\n for (var i = 0; i < ncells; i++) {\n var cell = cells[i];\n if (cell.cell_type === 'code') {\n for (var j = 0; j < cell.output_area.outputs.length; j++) {\n var data = cell.output_area.outputs[j];\n if (data.data) {\n // IPython >= 3 moved mimebundle to data attribute of output\n data = data.data;\n }\n if (data['text/html'] === html_output) {\n return [cell, data, j];\n }\n }\n }\n }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n IPython.notebook.kernel.comm_manager.register_target(\n 'matplotlib',\n mpl.mpl_figure_comm\n );\n}\n", "text/plain": [ "" ] @@ -17809,7 +1693,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3.8.8 64-bit", "language": "python", "name": "python3" }, @@ -17823,7 +1707,12 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.6" + "version": "3.8.8" + }, + "vscode": { + "interpreter": { + "hash": "b8df979b2a63b28a77ab58b7e3b47ecae7b25370869d24fd107bee2c562101a8" + } } }, "nbformat": 4, diff --git a/Tutorials/tuto_Optimization.ipynb b/Tutorials/tuto_Optimization.ipynb index 9cdfff882..76204abc6 100644 --- a/Tutorials/tuto_Optimization.ipynb +++ b/Tutorials/tuto_Optimization.ipynb @@ -76,7 +76,7 @@ }, { "data": { - "image/png": "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\n", + "image/png": "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", "text/plain": [ "
" ] @@ -198,17 +198,17 @@ "The second objective is set as a function. To set it as a string, this function can be defined inside a file and then keeper can be defined as \"path/to/file\" (example available at https://github.com/Eomys/pyleecan/blob/master/Tests/Validation/Multisimulation/test_multi_multi.py with the function \"make_gif\")\n", "\n", "### Design variables\n", - "We use the object [**OptiDesignVar**](https://www.pyleecan.org/pyleecan.Classes.OptiDesignVar.html) to define the design variables. \n", + "We use the object [**OptiDesignVarInterval**](https://www.pyleecan.org/pyleecan.Classes.OptiDesignVarInterval.html) or [**OptiDesignVarSet**](https://www.pyleecan.org/pyleecan.Classes.OptiDesignVarSet.html) to define the design variables. \n", "\n", + "OptiDesignVarInterval is for continuous variables.\n", + "OptiDesignVarSet is for discret variables.\n", "\n", - "To define a design variable, we have to specify different attributes: \n", + "\n", + "To define a design variable, we have to specify different attributes (both objects have the same attributes but different use): \n", "\n", "- *name* to define the design variable name\n", "- *symbol* to access to the variable / for plot (must be unique)\n", - "- *unit* to define the variable unit\n", - "- *type_var* to specify the variable \"type\": \n", - " - *interval* for continuous variables \n", - " - *set* for discrete variables \n", + "- *unit* to define the variable unit \n", "- *space* to set the variable bound\n", "- *setter* to access to the variable in the simu object. This attribute **must begin by \"simu\"**. \n", "- *get_value* function that takes the space in argument and returns a variable value (To initiate the first generation)\n", @@ -225,16 +225,16 @@ "metadata": {}, "outputs": [], "source": [ - "from pyleecan.Classes.OptiDesignVar import OptiDesignVar\n", + "from pyleecan.Classes.OptiDesignVarInterval import OptiDesignVarInterval\n", + "from pyleecan.Classes.OptiDesignVarSet import OptiDesignVarSet\n", "import random\n", "\n", "# Design variables\n", "my_design_var = [\n", - " OptiDesignVar(\n", + " OptiDesignVarInterval(\n", " name=\"Stator slot opening\",\n", " symbol = \"SW0\",\n", " unit = \"m\",\n", - " type_var=\"interval\",\n", " space=[\n", " 0 * simu_ref.machine.stator.slot.W2,\n", " simu_ref.machine.stator.slot.W2,\n", @@ -242,11 +242,10 @@ " get_value=\"lambda space: random.uniform(*space)\", # To initiate randomly the first generation\n", " setter=\"simu.machine.stator.slot.W0\", # Variable to edit\n", " ),\n", - " OptiDesignVar(\n", + " OptiDesignVarSet(\n", " name= \"Rotor ext radius\",\n", " symbol = \"Rext\",\n", " unit = \"m\",\n", - " type_var=\"set\",\n", " space=[\n", " 0.998 * simu_ref.machine.rotor.Rext,\n", " 0.999 * simu_ref.machine.rotor.Rext,\n", @@ -277,7 +276,7 @@ " - \">=\" \n", " - \">\" \n", "- value: value to compare \n", - "- get_variable: function which takes output in argument and returns the constraint value \n", + "- keeper: function which takes output in argument and returns the constraint value \n", "\n", "We also store the constraints into a list." ] @@ -294,7 +293,7 @@ " name = \"const1\",\n", " type_const = \"<=\",\n", " value = 700,\n", - " get_variable = \"lambda output: abs(output.mag.Tem_rip_pp)\",\n", + " keeper = \"lambda output: abs(output.mag.Tem_rip_pp)\",\n", " )\n", "]" ] @@ -1433,955 +1432,7 @@ "outputs": [ { "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "/* global mpl */\n", - "window.mpl = {};\n", - "\n", - "mpl.get_websocket_type = function () {\n", - " if (typeof WebSocket !== 'undefined') {\n", - " return WebSocket;\n", - " } else if (typeof MozWebSocket !== 'undefined') {\n", - " return MozWebSocket;\n", - " } else {\n", - " alert(\n", - " 'Your browser does not have WebSocket support. ' +\n", - " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", - " 'Firefox 4 and 5 are also supported but you ' +\n", - " 'have to enable WebSockets in about:config.'\n", - " );\n", - " }\n", - "};\n", - "\n", - "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", - " this.id = figure_id;\n", - "\n", - " this.ws = websocket;\n", - "\n", - " this.supports_binary = this.ws.binaryType !== undefined;\n", - "\n", - " if (!this.supports_binary) {\n", - " var warnings = document.getElementById('mpl-warnings');\n", - " if (warnings) {\n", - " warnings.style.display = 'block';\n", - " warnings.textContent =\n", - " 'This browser does not support binary websocket messages. ' +\n", - " 'Performance may be slow.';\n", - " }\n", - " }\n", - "\n", - " this.imageObj = new Image();\n", - "\n", - " this.context = undefined;\n", - " this.message = undefined;\n", - " this.canvas = undefined;\n", - " this.rubberband_canvas = undefined;\n", - " this.rubberband_context = undefined;\n", - " this.format_dropdown = undefined;\n", - "\n", - " this.image_mode = 'full';\n", - "\n", - " this.root = document.createElement('div');\n", - " this.root.setAttribute('style', 'display: inline-block');\n", - " this._root_extra_style(this.root);\n", - "\n", - " parent_element.appendChild(this.root);\n", - "\n", - " this._init_header(this);\n", - " this._init_canvas(this);\n", - " this._init_toolbar(this);\n", - "\n", - " var fig = this;\n", - "\n", - " this.waiting = false;\n", - "\n", - " this.ws.onopen = function () {\n", - " fig.send_message('supports_binary', { value: fig.supports_binary });\n", - " fig.send_message('send_image_mode', {});\n", - " if (fig.ratio !== 1) {\n", - " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", - " }\n", - " fig.send_message('refresh', {});\n", - " };\n", - "\n", - " this.imageObj.onload = function () {\n", - " if (fig.image_mode === 'full') {\n", - " // Full images could contain transparency (where diff images\n", - " // almost always do), so we need to clear the canvas so that\n", - " // there is no ghosting.\n", - " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", - " }\n", - " fig.context.drawImage(fig.imageObj, 0, 0);\n", - " };\n", - "\n", - " this.imageObj.onunload = function () {\n", - " fig.ws.close();\n", - " };\n", - "\n", - " this.ws.onmessage = this._make_on_message_function(this);\n", - "\n", - " this.ondownload = ondownload;\n", - "};\n", - "\n", - "mpl.figure.prototype._init_header = function () {\n", - " var titlebar = document.createElement('div');\n", - " titlebar.classList =\n", - " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", - " var titletext = document.createElement('div');\n", - " titletext.classList = 'ui-dialog-title';\n", - " titletext.setAttribute(\n", - " 'style',\n", - " 'width: 100%; text-align: center; padding: 3px;'\n", - " );\n", - " titlebar.appendChild(titletext);\n", - " this.root.appendChild(titlebar);\n", - " this.header = titletext;\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._init_canvas = function () {\n", - " var fig = this;\n", - "\n", - " var canvas_div = (this.canvas_div = document.createElement('div'));\n", - " canvas_div.setAttribute(\n", - " 'style',\n", - " 'border: 1px solid #ddd;' +\n", - " 'box-sizing: content-box;' +\n", - " 'clear: both;' +\n", - " 'min-height: 1px;' +\n", - " 'min-width: 1px;' +\n", - " 'outline: 0;' +\n", - " 'overflow: hidden;' +\n", - " 'position: relative;' +\n", - " 'resize: both;'\n", - " );\n", - "\n", - " function on_keyboard_event_closure(name) {\n", - " return function (event) {\n", - " return fig.key_event(event, name);\n", - " };\n", - " }\n", - "\n", - " canvas_div.addEventListener(\n", - " 'keydown',\n", - " on_keyboard_event_closure('key_press')\n", - " );\n", - " canvas_div.addEventListener(\n", - " 'keyup',\n", - " on_keyboard_event_closure('key_release')\n", - " );\n", - "\n", - " this._canvas_extra_style(canvas_div);\n", - " this.root.appendChild(canvas_div);\n", - "\n", - " var canvas = (this.canvas = document.createElement('canvas'));\n", - " canvas.classList.add('mpl-canvas');\n", - " canvas.setAttribute('style', 'box-sizing: content-box;');\n", - "\n", - " this.context = canvas.getContext('2d');\n", - "\n", - " var backingStore =\n", - " this.context.backingStorePixelRatio ||\n", - " this.context.webkitBackingStorePixelRatio ||\n", - " this.context.mozBackingStorePixelRatio ||\n", - " this.context.msBackingStorePixelRatio ||\n", - " this.context.oBackingStorePixelRatio ||\n", - " this.context.backingStorePixelRatio ||\n", - " 1;\n", - "\n", - " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", - "\n", - " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", - " 'canvas'\n", - " ));\n", - " rubberband_canvas.setAttribute(\n", - " 'style',\n", - " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", - " );\n", - "\n", - " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", - " if (this.ResizeObserver === undefined) {\n", - " if (window.ResizeObserver !== undefined) {\n", - " this.ResizeObserver = window.ResizeObserver;\n", - " } else {\n", - " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", - " this.ResizeObserver = obs.ResizeObserver;\n", - " }\n", - " }\n", - "\n", - " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", - " var nentries = entries.length;\n", - " for (var i = 0; i < nentries; i++) {\n", - " var entry = entries[i];\n", - " var width, height;\n", - " if (entry.contentBoxSize) {\n", - " if (entry.contentBoxSize instanceof Array) {\n", - " // Chrome 84 implements new version of spec.\n", - " width = entry.contentBoxSize[0].inlineSize;\n", - " height = entry.contentBoxSize[0].blockSize;\n", - " } else {\n", - " // Firefox implements old version of spec.\n", - " width = entry.contentBoxSize.inlineSize;\n", - " height = entry.contentBoxSize.blockSize;\n", - " }\n", - " } else {\n", - " // Chrome <84 implements even older version of spec.\n", - " width = entry.contentRect.width;\n", - " height = entry.contentRect.height;\n", - " }\n", - "\n", - " // Keep the size of the canvas and rubber band canvas in sync with\n", - " // the canvas container.\n", - " if (entry.devicePixelContentBoxSize) {\n", - " // Chrome 84 implements new version of spec.\n", - " canvas.setAttribute(\n", - " 'width',\n", - " entry.devicePixelContentBoxSize[0].inlineSize\n", - " );\n", - " canvas.setAttribute(\n", - " 'height',\n", - " entry.devicePixelContentBoxSize[0].blockSize\n", - " );\n", - " } else {\n", - " canvas.setAttribute('width', width * fig.ratio);\n", - " canvas.setAttribute('height', height * fig.ratio);\n", - " }\n", - " canvas.setAttribute(\n", - " 'style',\n", - " 'width: ' + width + 'px; height: ' + height + 'px;'\n", - " );\n", - "\n", - " rubberband_canvas.setAttribute('width', width);\n", - " rubberband_canvas.setAttribute('height', height);\n", - "\n", - " // And update the size in Python. We ignore the initial 0/0 size\n", - " // that occurs as the element is placed into the DOM, which should\n", - " // otherwise not happen due to the minimum size styling.\n", - " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", - " fig.request_resize(width, height);\n", - " }\n", - " }\n", - " });\n", - " this.resizeObserverInstance.observe(canvas_div);\n", - "\n", - " function on_mouse_event_closure(name) {\n", - " return function (event) {\n", - " return fig.mouse_event(event, name);\n", - " };\n", - " }\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mousedown',\n", - " on_mouse_event_closure('button_press')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseup',\n", - " on_mouse_event_closure('button_release')\n", - " );\n", - " // Throttle sequential mouse events to 1 every 20ms.\n", - " rubberband_canvas.addEventListener(\n", - " 'mousemove',\n", - " on_mouse_event_closure('motion_notify')\n", - " );\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseenter',\n", - " on_mouse_event_closure('figure_enter')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseleave',\n", - " on_mouse_event_closure('figure_leave')\n", - " );\n", - "\n", - " canvas_div.addEventListener('wheel', function (event) {\n", - " if (event.deltaY < 0) {\n", - " event.step = 1;\n", - " } else {\n", - " event.step = -1;\n", - " }\n", - " on_mouse_event_closure('scroll')(event);\n", - " });\n", - "\n", - " canvas_div.appendChild(canvas);\n", - " canvas_div.appendChild(rubberband_canvas);\n", - "\n", - " this.rubberband_context = rubberband_canvas.getContext('2d');\n", - " this.rubberband_context.strokeStyle = '#000000';\n", - "\n", - " this._resize_canvas = function (width, height, forward) {\n", - " if (forward) {\n", - " canvas_div.style.width = width + 'px';\n", - " canvas_div.style.height = height + 'px';\n", - " }\n", - " };\n", - "\n", - " // Disable right mouse context menu.\n", - " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", - " event.preventDefault();\n", - " return false;\n", - " });\n", - "\n", - " function set_focus() {\n", - " canvas.focus();\n", - " canvas_div.focus();\n", - " }\n", - "\n", - " window.setTimeout(set_focus, 100);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'mpl-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " continue;\n", - " }\n", - "\n", - " var button = (fig.buttons[name] = document.createElement('button'));\n", - " button.classList = 'mpl-widget';\n", - " button.setAttribute('role', 'button');\n", - " button.setAttribute('aria-disabled', 'false');\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - "\n", - " var icon_img = document.createElement('img');\n", - " icon_img.src = '_images/' + image + '.png';\n", - " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", - " icon_img.alt = tooltip;\n", - " button.appendChild(icon_img);\n", - "\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " var fmt_picker = document.createElement('select');\n", - " fmt_picker.classList = 'mpl-widget';\n", - " toolbar.appendChild(fmt_picker);\n", - " this.format_dropdown = fmt_picker;\n", - "\n", - " for (var ind in mpl.extensions) {\n", - " var fmt = mpl.extensions[ind];\n", - " var option = document.createElement('option');\n", - " option.selected = fmt === mpl.default_extension;\n", - " option.innerHTML = fmt;\n", - " fmt_picker.appendChild(option);\n", - " }\n", - "\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "};\n", - "\n", - "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", - " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", - " // which will in turn request a refresh of the image.\n", - " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", - "};\n", - "\n", - "mpl.figure.prototype.send_message = function (type, properties) {\n", - " properties['type'] = type;\n", - " properties['figure_id'] = this.id;\n", - " this.ws.send(JSON.stringify(properties));\n", - "};\n", - "\n", - "mpl.figure.prototype.send_draw_message = function () {\n", - " if (!this.waiting) {\n", - " this.waiting = true;\n", - " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " var format_dropdown = fig.format_dropdown;\n", - " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", - " fig.ondownload(fig, format);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", - " var size = msg['size'];\n", - " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", - " fig._resize_canvas(size[0], size[1], msg['forward']);\n", - " fig.send_message('refresh', {});\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", - " var x0 = msg['x0'] / fig.ratio;\n", - " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", - " var x1 = msg['x1'] / fig.ratio;\n", - " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", - " x0 = Math.floor(x0) + 0.5;\n", - " y0 = Math.floor(y0) + 0.5;\n", - " x1 = Math.floor(x1) + 0.5;\n", - " y1 = Math.floor(y1) + 0.5;\n", - " var min_x = Math.min(x0, x1);\n", - " var min_y = Math.min(y0, y1);\n", - " var width = Math.abs(x1 - x0);\n", - " var height = Math.abs(y1 - y0);\n", - "\n", - " fig.rubberband_context.clearRect(\n", - " 0,\n", - " 0,\n", - " fig.canvas.width / fig.ratio,\n", - " fig.canvas.height / fig.ratio\n", - " );\n", - "\n", - " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", - " // Updates the figure title.\n", - " fig.header.textContent = msg['label'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", - " var cursor = msg['cursor'];\n", - " switch (cursor) {\n", - " case 0:\n", - " cursor = 'pointer';\n", - " break;\n", - " case 1:\n", - " cursor = 'default';\n", - " break;\n", - " case 2:\n", - " cursor = 'crosshair';\n", - " break;\n", - " case 3:\n", - " cursor = 'move';\n", - " break;\n", - " }\n", - " fig.rubberband_canvas.style.cursor = cursor;\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_message = function (fig, msg) {\n", - " fig.message.textContent = msg['message'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", - " // Request the server to send over a new figure.\n", - " fig.send_draw_message();\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", - " fig.image_mode = msg['mode'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", - " for (var key in msg) {\n", - " if (!(key in fig.buttons)) {\n", - " continue;\n", - " }\n", - " fig.buttons[key].disabled = !msg[key];\n", - " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", - " if (msg['mode'] === 'PAN') {\n", - " fig.buttons['Pan'].classList.add('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " } else if (msg['mode'] === 'ZOOM') {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.add('active');\n", - " } else {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Called whenever the canvas gets updated.\n", - " this.send_message('ack', {});\n", - "};\n", - "\n", - "// A function to construct a web socket function for onmessage handling.\n", - "// Called in the figure constructor.\n", - "mpl.figure.prototype._make_on_message_function = function (fig) {\n", - " return function socket_on_message(evt) {\n", - " if (evt.data instanceof Blob) {\n", - " /* FIXME: We get \"Resource interpreted as Image but\n", - " * transferred with MIME type text/plain:\" errors on\n", - " * Chrome. But how to set the MIME type? It doesn't seem\n", - " * to be part of the websocket stream */\n", - " evt.data.type = 'image/png';\n", - "\n", - " /* Free the memory for the previous frames */\n", - " if (fig.imageObj.src) {\n", - " (window.URL || window.webkitURL).revokeObjectURL(\n", - " fig.imageObj.src\n", - " );\n", - " }\n", - "\n", - " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", - " evt.data\n", - " );\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " } else if (\n", - " typeof evt.data === 'string' &&\n", - " evt.data.slice(0, 21) === 'data:image/png;base64'\n", - " ) {\n", - " fig.imageObj.src = evt.data;\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " }\n", - "\n", - " var msg = JSON.parse(evt.data);\n", - " var msg_type = msg['type'];\n", - "\n", - " // Call the \"handle_{type}\" callback, which takes\n", - " // the figure and JSON message as its only arguments.\n", - " try {\n", - " var callback = fig['handle_' + msg_type];\n", - " } catch (e) {\n", - " console.log(\n", - " \"No handler for the '\" + msg_type + \"' message type: \",\n", - " msg\n", - " );\n", - " return;\n", - " }\n", - "\n", - " if (callback) {\n", - " try {\n", - " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", - " callback(fig, msg);\n", - " } catch (e) {\n", - " console.log(\n", - " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", - " e,\n", - " e.stack,\n", - " msg\n", - " );\n", - " }\n", - " }\n", - " };\n", - "};\n", - "\n", - "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", - "mpl.findpos = function (e) {\n", - " //this section is from http://www.quirksmode.org/js/events_properties.html\n", - " var targ;\n", - " if (!e) {\n", - " e = window.event;\n", - " }\n", - " if (e.target) {\n", - " targ = e.target;\n", - " } else if (e.srcElement) {\n", - " targ = e.srcElement;\n", - " }\n", - " if (targ.nodeType === 3) {\n", - " // defeat Safari bug\n", - " targ = targ.parentNode;\n", - " }\n", - "\n", - " // pageX,Y are the mouse positions relative to the document\n", - " var boundingRect = targ.getBoundingClientRect();\n", - " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", - " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", - "\n", - " return { x: x, y: y };\n", - "};\n", - "\n", - "/*\n", - " * return a copy of an object with only non-object keys\n", - " * we need this to avoid circular references\n", - " * http://stackoverflow.com/a/24161582/3208463\n", - " */\n", - "function simpleKeys(original) {\n", - " return Object.keys(original).reduce(function (obj, key) {\n", - " if (typeof original[key] !== 'object') {\n", - " obj[key] = original[key];\n", - " }\n", - " return obj;\n", - " }, {});\n", - "}\n", - "\n", - "mpl.figure.prototype.mouse_event = function (event, name) {\n", - " var canvas_pos = mpl.findpos(event);\n", - "\n", - " if (name === 'button_press') {\n", - " this.canvas.focus();\n", - " this.canvas_div.focus();\n", - " }\n", - "\n", - " var x = canvas_pos.x * this.ratio;\n", - " var y = canvas_pos.y * this.ratio;\n", - "\n", - " this.send_message(name, {\n", - " x: x,\n", - " y: y,\n", - " button: event.button,\n", - " step: event.step,\n", - " guiEvent: simpleKeys(event),\n", - " });\n", - "\n", - " /* This prevents the web browser from automatically changing to\n", - " * the text insertion cursor when the button is pressed. We want\n", - " * to control all of the cursor setting manually through the\n", - " * 'cursor' event from matplotlib */\n", - " event.preventDefault();\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", - " // Handle any extra behaviour associated with a key event\n", - "};\n", - "\n", - "mpl.figure.prototype.key_event = function (event, name) {\n", - " // Prevent repeat events\n", - " if (name === 'key_press') {\n", - " if (event.which === this._key) {\n", - " return;\n", - " } else {\n", - " this._key = event.which;\n", - " }\n", - " }\n", - " if (name === 'key_release') {\n", - " this._key = null;\n", - " }\n", - "\n", - " var value = '';\n", - " if (event.ctrlKey && event.which !== 17) {\n", - " value += 'ctrl+';\n", - " }\n", - " if (event.altKey && event.which !== 18) {\n", - " value += 'alt+';\n", - " }\n", - " if (event.shiftKey && event.which !== 16) {\n", - " value += 'shift+';\n", - " }\n", - "\n", - " value += 'k';\n", - " value += event.which.toString();\n", - "\n", - " this._key_event_extra(event, name);\n", - "\n", - " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", - " if (name === 'download') {\n", - " this.handle_save(this, null);\n", - " } else {\n", - " this.send_message('toolbar_button', { name: name });\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", - " this.message.textContent = tooltip;\n", - "};\n", - "\n", - "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", - "// prettier-ignore\n", - "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", - "\n", - "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", - "\n", - "mpl.default_extension = \"png\";/* global mpl */\n", - "\n", - "var comm_websocket_adapter = function (comm) {\n", - " // Create a \"websocket\"-like object which calls the given IPython comm\n", - " // object with the appropriate methods. Currently this is a non binary\n", - " // socket, so there is still some room for performance tuning.\n", - " var ws = {};\n", - "\n", - " ws.close = function () {\n", - " comm.close();\n", - " };\n", - " ws.send = function (m) {\n", - " //console.log('sending', m);\n", - " comm.send(m);\n", - " };\n", - " // Register the callback with on_msg.\n", - " comm.on_msg(function (msg) {\n", - " //console.log('receiving', msg['content']['data'], msg);\n", - " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", - " ws.onmessage(msg['content']['data']);\n", - " });\n", - " return ws;\n", - "};\n", - "\n", - "mpl.mpl_figure_comm = function (comm, msg) {\n", - " // This is the function which gets called when the mpl process\n", - " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", - "\n", - " var id = msg.content.data.id;\n", - " // Get hold of the div created by the display call when the Comm\n", - " // socket was opened in Python.\n", - " var element = document.getElementById(id);\n", - " var ws_proxy = comm_websocket_adapter(comm);\n", - "\n", - " function ondownload(figure, _format) {\n", - " window.open(figure.canvas.toDataURL());\n", - " }\n", - "\n", - " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", - "\n", - " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", - " // web socket which is closed, not our websocket->open comm proxy.\n", - " ws_proxy.onopen();\n", - "\n", - " fig.parent_element = element;\n", - " fig.cell_info = mpl.find_output_cell(\"
\");\n", - " if (!fig.cell_info) {\n", - " console.error('Failed to find cell for figure', id, fig);\n", - " return;\n", - " }\n", - " fig.cell_info[0].output_area.element.on(\n", - " 'cleared',\n", - " { fig: fig },\n", - " fig._remove_fig_handler\n", - " );\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_close = function (fig, msg) {\n", - " var width = fig.canvas.width / fig.ratio;\n", - " fig.cell_info[0].output_area.element.off(\n", - " 'cleared',\n", - " fig._remove_fig_handler\n", - " );\n", - " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", - "\n", - " // Update the output cell to use the data from the current canvas.\n", - " fig.push_to_output();\n", - " var dataURL = fig.canvas.toDataURL();\n", - " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", - " // the notebook keyboard shortcuts fail.\n", - " IPython.keyboard_manager.enable();\n", - " fig.parent_element.innerHTML =\n", - " '';\n", - " fig.close_ws(fig, msg);\n", - "};\n", - "\n", - "mpl.figure.prototype.close_ws = function (fig, msg) {\n", - " fig.send_message('closing', msg);\n", - " // fig.ws.close()\n", - "};\n", - "\n", - "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", - " // Turn the data on the canvas into data in the output cell.\n", - " var width = this.canvas.width / this.ratio;\n", - " var dataURL = this.canvas.toDataURL();\n", - " this.cell_info[1]['text/html'] =\n", - " '';\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Tell IPython that the notebook contents must change.\n", - " IPython.notebook.set_dirty(true);\n", - " this.send_message('ack', {});\n", - " var fig = this;\n", - " // Wait a second, then push the new image to the DOM so\n", - " // that it is saved nicely (might be nice to debounce this).\n", - " setTimeout(function () {\n", - " fig.push_to_output();\n", - " }, 1000);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'btn-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " var button;\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " continue;\n", - " }\n", - "\n", - " button = fig.buttons[name] = document.createElement('button');\n", - " button.classList = 'btn btn-default';\n", - " button.href = '#';\n", - " button.title = name;\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " // Add the status bar.\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message pull-right';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "\n", - " // Add the close button to the window.\n", - " var buttongrp = document.createElement('div');\n", - " buttongrp.classList = 'btn-group inline pull-right';\n", - " button = document.createElement('button');\n", - " button.classList = 'btn btn-mini btn-primary';\n", - " button.href = '#';\n", - " button.title = 'Stop Interaction';\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', function (_evt) {\n", - " fig.handle_close(fig, {});\n", - " });\n", - " button.addEventListener(\n", - " 'mouseover',\n", - " on_mouseover_closure('Stop Interaction')\n", - " );\n", - " buttongrp.appendChild(button);\n", - " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", - " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", - "};\n", - "\n", - "mpl.figure.prototype._remove_fig_handler = function (event) {\n", - " var fig = event.data.fig;\n", - " if (event.target !== this) {\n", - " // Ignore bubbled events from children.\n", - " return;\n", - " }\n", - " fig.close_ws(fig, {});\n", - "};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (el) {\n", - " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (el) {\n", - " // this is important to make the div 'focusable\n", - " el.setAttribute('tabindex', 0);\n", - " // reach out to IPython and tell the keyboard manager to turn it's self\n", - " // off when our div gets focus\n", - "\n", - " // location in version 3\n", - " if (IPython.notebook.keyboard_manager) {\n", - " IPython.notebook.keyboard_manager.register_events(el);\n", - " } else {\n", - " // location in version 2\n", - " IPython.keyboard_manager.register_events(el);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", - " var manager = IPython.notebook.keyboard_manager;\n", - " if (!manager) {\n", - " manager = IPython.keyboard_manager;\n", - " }\n", - "\n", - " // Check for shift+enter\n", - " if (event.shiftKey && event.which === 13) {\n", - " this.canvas_div.blur();\n", - " // select the cell after this one\n", - " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", - " IPython.notebook.select(index + 1);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " fig.ondownload(fig, null);\n", - "};\n", - "\n", - "mpl.find_output_cell = function (html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i = 0; i < ncells; i++) {\n", - " var cell = cells[i];\n", - " if (cell.cell_type === 'code') {\n", - " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", - " var data = cell.output_area.outputs[j];\n", - " if (data.data) {\n", - " // IPython >= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] === html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "};\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel !== null) {\n", - " IPython.notebook.kernel.comm_manager.register_target(\n", - " 'matplotlib',\n", - " mpl.mpl_figure_comm\n", - " );\n", - "}\n" - ], + "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n if (typeof WebSocket !== 'undefined') {\n return WebSocket;\n } else if (typeof MozWebSocket !== 'undefined') {\n return MozWebSocket;\n } else {\n alert(\n 'Your browser does not have WebSocket support. ' +\n 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n 'Firefox 4 and 5 are also supported but you ' +\n 'have to enable WebSockets in about:config.'\n );\n }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n this.id = figure_id;\n\n this.ws = websocket;\n\n this.supports_binary = this.ws.binaryType !== undefined;\n\n if (!this.supports_binary) {\n var warnings = document.getElementById('mpl-warnings');\n if (warnings) {\n warnings.style.display = 'block';\n warnings.textContent =\n 'This browser does not support binary websocket messages. ' +\n 'Performance may be slow.';\n }\n }\n\n this.imageObj = new Image();\n\n this.context = undefined;\n this.message = undefined;\n this.canvas = undefined;\n this.rubberband_canvas = undefined;\n this.rubberband_context = undefined;\n this.format_dropdown = undefined;\n\n this.image_mode = 'full';\n\n this.root = document.createElement('div');\n this.root.setAttribute('style', 'display: inline-block');\n this._root_extra_style(this.root);\n\n parent_element.appendChild(this.root);\n\n this._init_header(this);\n this._init_canvas(this);\n this._init_toolbar(this);\n\n var fig = this;\n\n this.waiting = false;\n\n this.ws.onopen = function () {\n fig.send_message('supports_binary', { value: fig.supports_binary });\n fig.send_message('send_image_mode', {});\n if (fig.ratio !== 1) {\n fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n }\n fig.send_message('refresh', {});\n };\n\n this.imageObj.onload = function () {\n if (fig.image_mode === 'full') {\n // Full images could contain transparency (where diff images\n // almost always do), so we need to clear the canvas so that\n // there is no ghosting.\n fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n }\n fig.context.drawImage(fig.imageObj, 0, 0);\n };\n\n this.imageObj.onunload = function () {\n fig.ws.close();\n };\n\n this.ws.onmessage = this._make_on_message_function(this);\n\n this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n var titlebar = document.createElement('div');\n titlebar.classList =\n 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n var titletext = document.createElement('div');\n titletext.classList = 'ui-dialog-title';\n titletext.setAttribute(\n 'style',\n 'width: 100%; text-align: center; padding: 3px;'\n );\n titlebar.appendChild(titletext);\n this.root.appendChild(titlebar);\n this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n var fig = this;\n\n var canvas_div = (this.canvas_div = document.createElement('div'));\n canvas_div.setAttribute(\n 'style',\n 'border: 1px solid #ddd;' +\n 'box-sizing: content-box;' +\n 'clear: both;' +\n 'min-height: 1px;' +\n 'min-width: 1px;' +\n 'outline: 0;' +\n 'overflow: hidden;' +\n 'position: relative;' +\n 'resize: both;'\n );\n\n function on_keyboard_event_closure(name) {\n return function (event) {\n return fig.key_event(event, name);\n };\n }\n\n canvas_div.addEventListener(\n 'keydown',\n on_keyboard_event_closure('key_press')\n );\n canvas_div.addEventListener(\n 'keyup',\n on_keyboard_event_closure('key_release')\n );\n\n this._canvas_extra_style(canvas_div);\n this.root.appendChild(canvas_div);\n\n var canvas = (this.canvas = document.createElement('canvas'));\n canvas.classList.add('mpl-canvas');\n canvas.setAttribute('style', 'box-sizing: content-box;');\n\n this.context = canvas.getContext('2d');\n\n var backingStore =\n this.context.backingStorePixelRatio ||\n this.context.webkitBackingStorePixelRatio ||\n this.context.mozBackingStorePixelRatio ||\n this.context.msBackingStorePixelRatio ||\n this.context.oBackingStorePixelRatio ||\n this.context.backingStorePixelRatio ||\n 1;\n\n this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n 'canvas'\n ));\n rubberband_canvas.setAttribute(\n 'style',\n 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n );\n\n // Apply a ponyfill if ResizeObserver is not implemented by browser.\n if (this.ResizeObserver === undefined) {\n if (window.ResizeObserver !== undefined) {\n this.ResizeObserver = window.ResizeObserver;\n } else {\n var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n this.ResizeObserver = obs.ResizeObserver;\n }\n }\n\n this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n var nentries = entries.length;\n for (var i = 0; i < nentries; i++) {\n var entry = entries[i];\n var width, height;\n if (entry.contentBoxSize) {\n if (entry.contentBoxSize instanceof Array) {\n // Chrome 84 implements new version of spec.\n width = entry.contentBoxSize[0].inlineSize;\n height = entry.contentBoxSize[0].blockSize;\n } else {\n // Firefox implements old version of spec.\n width = entry.contentBoxSize.inlineSize;\n height = entry.contentBoxSize.blockSize;\n }\n } else {\n // Chrome <84 implements even older version of spec.\n width = entry.contentRect.width;\n height = entry.contentRect.height;\n }\n\n // Keep the size of the canvas and rubber band canvas in sync with\n // the canvas container.\n if (entry.devicePixelContentBoxSize) {\n // Chrome 84 implements new version of spec.\n canvas.setAttribute(\n 'width',\n entry.devicePixelContentBoxSize[0].inlineSize\n );\n canvas.setAttribute(\n 'height',\n entry.devicePixelContentBoxSize[0].blockSize\n );\n } else {\n canvas.setAttribute('width', width * fig.ratio);\n canvas.setAttribute('height', height * fig.ratio);\n }\n canvas.setAttribute(\n 'style',\n 'width: ' + width + 'px; height: ' + height + 'px;'\n );\n\n rubberband_canvas.setAttribute('width', width);\n rubberband_canvas.setAttribute('height', height);\n\n // And update the size in Python. We ignore the initial 0/0 size\n // that occurs as the element is placed into the DOM, which should\n // otherwise not happen due to the minimum size styling.\n if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n fig.request_resize(width, height);\n }\n }\n });\n this.resizeObserverInstance.observe(canvas_div);\n\n function on_mouse_event_closure(name) {\n return function (event) {\n return fig.mouse_event(event, name);\n };\n }\n\n rubberband_canvas.addEventListener(\n 'mousedown',\n on_mouse_event_closure('button_press')\n );\n rubberband_canvas.addEventListener(\n 'mouseup',\n on_mouse_event_closure('button_release')\n );\n // Throttle sequential mouse events to 1 every 20ms.\n rubberband_canvas.addEventListener(\n 'mousemove',\n on_mouse_event_closure('motion_notify')\n );\n\n rubberband_canvas.addEventListener(\n 'mouseenter',\n on_mouse_event_closure('figure_enter')\n );\n rubberband_canvas.addEventListener(\n 'mouseleave',\n on_mouse_event_closure('figure_leave')\n );\n\n canvas_div.addEventListener('wheel', function (event) {\n if (event.deltaY < 0) {\n event.step = 1;\n } else {\n event.step = -1;\n }\n on_mouse_event_closure('scroll')(event);\n });\n\n canvas_div.appendChild(canvas);\n canvas_div.appendChild(rubberband_canvas);\n\n this.rubberband_context = rubberband_canvas.getContext('2d');\n this.rubberband_context.strokeStyle = '#000000';\n\n this._resize_canvas = function (width, height, forward) {\n if (forward) {\n canvas_div.style.width = width + 'px';\n canvas_div.style.height = height + 'px';\n }\n };\n\n // Disable right mouse context menu.\n this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n event.preventDefault();\n return false;\n });\n\n function set_focus() {\n canvas.focus();\n canvas_div.focus();\n }\n\n window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'mpl-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n continue;\n }\n\n var button = (fig.buttons[name] = document.createElement('button'));\n button.classList = 'mpl-widget';\n button.setAttribute('role', 'button');\n button.setAttribute('aria-disabled', 'false');\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n var icon_img = document.createElement('img');\n icon_img.src = '_images/' + image + '.png';\n icon_img.srcset = '_images/' + image + '_large.png 2x';\n icon_img.alt = tooltip;\n button.appendChild(icon_img);\n\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n var fmt_picker = document.createElement('select');\n fmt_picker.classList = 'mpl-widget';\n toolbar.appendChild(fmt_picker);\n this.format_dropdown = fmt_picker;\n\n for (var ind in mpl.extensions) {\n var fmt = mpl.extensions[ind];\n var option = document.createElement('option');\n option.selected = fmt === mpl.default_extension;\n option.innerHTML = fmt;\n fmt_picker.appendChild(option);\n }\n\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n // which will in turn request a refresh of the image.\n this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n properties['type'] = type;\n properties['figure_id'] = this.id;\n this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n if (!this.waiting) {\n this.waiting = true;\n this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n var format_dropdown = fig.format_dropdown;\n var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n var size = msg['size'];\n if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n fig._resize_canvas(size[0], size[1], msg['forward']);\n fig.send_message('refresh', {});\n }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n var x0 = msg['x0'] / fig.ratio;\n var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n var x1 = msg['x1'] / fig.ratio;\n var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n x0 = Math.floor(x0) + 0.5;\n y0 = Math.floor(y0) + 0.5;\n x1 = Math.floor(x1) + 0.5;\n y1 = Math.floor(y1) + 0.5;\n var min_x = Math.min(x0, x1);\n var min_y = Math.min(y0, y1);\n var width = Math.abs(x1 - x0);\n var height = Math.abs(y1 - y0);\n\n fig.rubberband_context.clearRect(\n 0,\n 0,\n fig.canvas.width / fig.ratio,\n fig.canvas.height / fig.ratio\n );\n\n fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n // Updates the figure title.\n fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n var cursor = msg['cursor'];\n switch (cursor) {\n case 0:\n cursor = 'pointer';\n break;\n case 1:\n cursor = 'default';\n break;\n case 2:\n cursor = 'crosshair';\n break;\n case 3:\n cursor = 'move';\n break;\n }\n fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n // Request the server to send over a new figure.\n fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n for (var key in msg) {\n if (!(key in fig.buttons)) {\n continue;\n }\n fig.buttons[key].disabled = !msg[key];\n fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n if (msg['mode'] === 'PAN') {\n fig.buttons['Pan'].classList.add('active');\n fig.buttons['Zoom'].classList.remove('active');\n } else if (msg['mode'] === 'ZOOM') {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.add('active');\n } else {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.remove('active');\n }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Called whenever the canvas gets updated.\n this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n return function socket_on_message(evt) {\n if (evt.data instanceof Blob) {\n /* FIXME: We get \"Resource interpreted as Image but\n * transferred with MIME type text/plain:\" errors on\n * Chrome. But how to set the MIME type? It doesn't seem\n * to be part of the websocket stream */\n evt.data.type = 'image/png';\n\n /* Free the memory for the previous frames */\n if (fig.imageObj.src) {\n (window.URL || window.webkitURL).revokeObjectURL(\n fig.imageObj.src\n );\n }\n\n fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n evt.data\n );\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n } else if (\n typeof evt.data === 'string' &&\n evt.data.slice(0, 21) === 'data:image/png;base64'\n ) {\n fig.imageObj.src = evt.data;\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n }\n\n var msg = JSON.parse(evt.data);\n var msg_type = msg['type'];\n\n // Call the \"handle_{type}\" callback, which takes\n // the figure and JSON message as its only arguments.\n try {\n var callback = fig['handle_' + msg_type];\n } catch (e) {\n console.log(\n \"No handler for the '\" + msg_type + \"' message type: \",\n msg\n );\n return;\n }\n\n if (callback) {\n try {\n // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n callback(fig, msg);\n } catch (e) {\n console.log(\n \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n e,\n e.stack,\n msg\n );\n }\n }\n };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n //this section is from http://www.quirksmode.org/js/events_properties.html\n var targ;\n if (!e) {\n e = window.event;\n }\n if (e.target) {\n targ = e.target;\n } else if (e.srcElement) {\n targ = e.srcElement;\n }\n if (targ.nodeType === 3) {\n // defeat Safari bug\n targ = targ.parentNode;\n }\n\n // pageX,Y are the mouse positions relative to the document\n var boundingRect = targ.getBoundingClientRect();\n var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n return Object.keys(original).reduce(function (obj, key) {\n if (typeof original[key] !== 'object') {\n obj[key] = original[key];\n }\n return obj;\n }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n var canvas_pos = mpl.findpos(event);\n\n if (name === 'button_press') {\n this.canvas.focus();\n this.canvas_div.focus();\n }\n\n var x = canvas_pos.x * this.ratio;\n var y = canvas_pos.y * this.ratio;\n\n this.send_message(name, {\n x: x,\n y: y,\n button: event.button,\n step: event.step,\n guiEvent: simpleKeys(event),\n });\n\n /* This prevents the web browser from automatically changing to\n * the text insertion cursor when the button is pressed. We want\n * to control all of the cursor setting manually through the\n * 'cursor' event from matplotlib */\n event.preventDefault();\n return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n // Prevent repeat events\n if (name === 'key_press') {\n if (event.which === this._key) {\n return;\n } else {\n this._key = event.which;\n }\n }\n if (name === 'key_release') {\n this._key = null;\n }\n\n var value = '';\n if (event.ctrlKey && event.which !== 17) {\n value += 'ctrl+';\n }\n if (event.altKey && event.which !== 18) {\n value += 'alt+';\n }\n if (event.shiftKey && event.which !== 16) {\n value += 'shift+';\n }\n\n value += 'k';\n value += event.which.toString();\n\n this._key_event_extra(event, name);\n\n this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n if (name === 'download') {\n this.handle_save(this, null);\n } else {\n this.send_message('toolbar_button', { name: name });\n }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\nmpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n\nmpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n // Create a \"websocket\"-like object which calls the given IPython comm\n // object with the appropriate methods. Currently this is a non binary\n // socket, so there is still some room for performance tuning.\n var ws = {};\n\n ws.close = function () {\n comm.close();\n };\n ws.send = function (m) {\n //console.log('sending', m);\n comm.send(m);\n };\n // Register the callback with on_msg.\n comm.on_msg(function (msg) {\n //console.log('receiving', msg['content']['data'], msg);\n // Pass the mpl event to the overridden (by mpl) onmessage function.\n ws.onmessage(msg['content']['data']);\n });\n return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n // This is the function which gets called when the mpl process\n // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n var id = msg.content.data.id;\n // Get hold of the div created by the display call when the Comm\n // socket was opened in Python.\n var element = document.getElementById(id);\n var ws_proxy = comm_websocket_adapter(comm);\n\n function ondownload(figure, _format) {\n window.open(figure.canvas.toDataURL());\n }\n\n var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n // web socket which is closed, not our websocket->open comm proxy.\n ws_proxy.onopen();\n\n fig.parent_element = element;\n fig.cell_info = mpl.find_output_cell(\"
\");\n if (!fig.cell_info) {\n console.error('Failed to find cell for figure', id, fig);\n return;\n }\n fig.cell_info[0].output_area.element.on(\n 'cleared',\n { fig: fig },\n fig._remove_fig_handler\n );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n var width = fig.canvas.width / fig.ratio;\n fig.cell_info[0].output_area.element.off(\n 'cleared',\n fig._remove_fig_handler\n );\n fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n // Update the output cell to use the data from the current canvas.\n fig.push_to_output();\n var dataURL = fig.canvas.toDataURL();\n // Re-enable the keyboard manager in IPython - without this line, in FF,\n // the notebook keyboard shortcuts fail.\n IPython.keyboard_manager.enable();\n fig.parent_element.innerHTML =\n '';\n fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n fig.send_message('closing', msg);\n // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n // Turn the data on the canvas into data in the output cell.\n var width = this.canvas.width / this.ratio;\n var dataURL = this.canvas.toDataURL();\n this.cell_info[1]['text/html'] =\n '';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Tell IPython that the notebook contents must change.\n IPython.notebook.set_dirty(true);\n this.send_message('ack', {});\n var fig = this;\n // Wait a second, then push the new image to the DOM so\n // that it is saved nicely (might be nice to debounce this).\n setTimeout(function () {\n fig.push_to_output();\n }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'btn-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n var button;\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n continue;\n }\n\n button = fig.buttons[name] = document.createElement('button');\n button.classList = 'btn btn-default';\n button.href = '#';\n button.title = name;\n button.innerHTML = '';\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n // Add the status bar.\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message pull-right';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n\n // Add the close button to the window.\n var buttongrp = document.createElement('div');\n buttongrp.classList = 'btn-group inline pull-right';\n button = document.createElement('button');\n button.classList = 'btn btn-mini btn-primary';\n button.href = '#';\n button.title = 'Stop Interaction';\n button.innerHTML = '';\n button.addEventListener('click', function (_evt) {\n fig.handle_close(fig, {});\n });\n button.addEventListener(\n 'mouseover',\n on_mouseover_closure('Stop Interaction')\n );\n buttongrp.appendChild(button);\n var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n var fig = event.data.fig;\n if (event.target !== this) {\n // Ignore bubbled events from children.\n return;\n }\n fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n // this is important to make the div 'focusable\n el.setAttribute('tabindex', 0);\n // reach out to IPython and tell the keyboard manager to turn it's self\n // off when our div gets focus\n\n // location in version 3\n if (IPython.notebook.keyboard_manager) {\n IPython.notebook.keyboard_manager.register_events(el);\n } else {\n // location in version 2\n IPython.keyboard_manager.register_events(el);\n }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n var manager = IPython.notebook.keyboard_manager;\n if (!manager) {\n manager = IPython.keyboard_manager;\n }\n\n // Check for shift+enter\n if (event.shiftKey && event.which === 13) {\n this.canvas_div.blur();\n // select the cell after this one\n var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n IPython.notebook.select(index + 1);\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n // Return the cell and output element which can be found *uniquely* in the notebook.\n // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n // IPython event is triggered only after the cells have been serialised, which for\n // our purposes (turning an active figure into a static one), is too late.\n var cells = IPython.notebook.get_cells();\n var ncells = cells.length;\n for (var i = 0; i < ncells; i++) {\n var cell = cells[i];\n if (cell.cell_type === 'code') {\n for (var j = 0; j < cell.output_area.outputs.length; j++) {\n var data = cell.output_area.outputs[j];\n if (data.data) {\n // IPython >= 3 moved mimebundle to data attribute of output\n data = data.data;\n }\n if (data['text/html'] === html_output) {\n return [cell, data, j];\n }\n }\n }\n }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n IPython.notebook.kernel.comm_manager.register_target(\n 'matplotlib',\n mpl.mpl_figure_comm\n );\n}\n", "text/plain": [ "" ] diff --git a/Tutorials/tuto_Optimization_Bayes_machine_SCIM.ipynb b/Tutorials/tuto_Optimization_Bayes_machine_SCIM.ipynb index c2bff9424..74942dac9 100644 --- a/Tutorials/tuto_Optimization_Bayes_machine_SCIM.ipynb +++ b/Tutorials/tuto_Optimization_Bayes_machine_SCIM.ipynb @@ -139,17 +139,17 @@ "metadata": {}, "source": [ "### Design variables\n", - "We use the object [**OptiDesignVar**](https://www.pyleecan.org/pyleecan.Classes.OptiDesignVar.html) to define the design variables. \n", + "We use the object [**OptiDesignVarInterval**](https://www.pyleecan.org/pyleecan.Classes.OptiDesignVarInterval.html) or [**OptiDesignVarSet**](https://www.pyleecan.org/pyleecan.Classes.OptiDesignVarSet.html) to define the design variables. \n", "\n", + "OptiDesignVarInterval is for continuous variables.\n", + "OptiDesignVarSet is for discret variables.\n", "\n", - "To define a design variable, we have to specify different attributes: \n", + "\n", + "To define a design variable, we have to specify different attributes (both objects have the same attributes but different use): \n", "\n", "- *name* to define the design variable name\n", "- *symbol* to access to the variable / for plot (must be unique)\n", "- *unit* to define the variable unit\n", - "- *type_var* to specify the variable \"type\": \n", - " - *interval* for continuous variables \n", - " - *set* for discrete variables \n", "- *space* to set the variable bound\n", "- *setter* to access to the variable in the simu object. This attribute **must begin by \"simu\"**. \n", "- *get_value* to define the variable for the first generation, the function takes the space in argument and returns the variable value \n", @@ -163,7 +163,7 @@ "metadata": {}, "outputs": [], "source": [ - "from pyleecan.Classes.OptiDesignVar import OptiDesignVar\n", + "from pyleecan.Classes.OptiDesignVarInterval import OptiDesignVarInterval\n", "import random\n", "\n", "my_vars = []\n", @@ -176,10 +176,9 @@ "\n", "for i in range(30):\n", " my_vars.append(\n", - " OptiDesignVar(\n", + " OptiDesignVarInterval(\n", " name=\"Ir({})\".format(i),\n", " symbol=\"var_\" + str(i),\n", - " type_var=\"interval\",\n", " space=[0, 1],\n", " get_value=lambda space: np.random.uniform(*space),\n", " setter=gen_setter(i),\n", @@ -205,7 +204,7 @@ " - \">=\" \n", " - \">\" \n", "- value: value to compare \n", - "- get_variable: function which takes output in argument and returns the constraint value \n", + "- keeper: function which takes output in argument and returns the constraint value \n", "\n", "We also store the constraints into a dict." ] @@ -224,7 +223,7 @@ " name = \"const1\",\n", " type_const = \"<=\",\n", " value = 700,\n", - " get_variable = \"lambda output: abs(output.mag.Tem_rip_pp)\",\n", + " keeper = \"lambda output: abs(output.mag.Tem_rip_pp)\",\n", " )\n", "]" ] @@ -419,7 +418,7 @@ }, { "data": { - "image/png": "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\n", + "image/png": "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", "text/plain": [ "
" ] From 3597ffe28902cf83913fcab10f3efccdd2ff94dd Mon Sep 17 00:00:00 2001 From: BenjaminGabet Date: Fri, 9 Dec 2022 13:46:14 +0100 Subject: [PATCH 07/10] [BC] Bug correction for VarOpti (default value for list attributes) --- pyleecan/Classes/Class_Dict.json | 4 +- pyleecan/Functions/Load/retrocompatibility.py | 38 ++++++++++--------- .../ClassesRef/Simulation/VarOpti.csv | 4 +- .../Simulation/VarOpti/get_full_solver.py | 5 ++- 4 files changed, 27 insertions(+), 24 deletions(-) diff --git a/pyleecan/Classes/Class_Dict.json b/pyleecan/Classes/Class_Dict.json index baeb29eb4..afefd7c14 100644 --- a/pyleecan/Classes/Class_Dict.json +++ b/pyleecan/Classes/Class_Dict.json @@ -15844,7 +15844,7 @@ "name": "objective_list", "type": "[OptiObjective]", "unit": "-", - "value": -1 + "value": "" }, { "as_dict": "", @@ -15854,7 +15854,7 @@ "name": "constraint_list", "type": "[OptiConstraint]", "unit": "-", - "value": -1 + "value": "" }, { "as_dict": "", diff --git a/pyleecan/Functions/Load/retrocompatibility.py b/pyleecan/Functions/Load/retrocompatibility.py index 8c63d3e09..a562663b9 100644 --- a/pyleecan/Functions/Load/retrocompatibility.py +++ b/pyleecan/Functions/Load/retrocompatibility.py @@ -346,13 +346,10 @@ def convert_Winding(wind_dict): def is_VarParam_dict(obj_dict): """Check if the object need to be updated for Winding""" - return ( - "__class__" in obj_dict.keys() - and obj_dict["__class__"] - in [ - "VarParam", - ] - ) + return "__class__" in obj_dict.keys() and obj_dict["__class__"] in [ + "VarParam", + ] + def rename_varparam(varparam_dict): """Update the old VarParam class to VarParamSweep""" @@ -384,6 +381,7 @@ def is_OptiConstraint_dict(obj_dict): and "get_variable" in obj_dict.keys() ) + def convert_opticonstraint(opticonstraint_dict): """Update the old OptiConstraint to the new one inherited from DataKeeper without get_variable""" getLogger(GUI_LOG_NAME).info( @@ -407,13 +405,10 @@ def convert_opticonstraint(opticonstraint_dict): def is_OptiDesignVar_dict(obj_dict): """Check if the object need to be updated for OptiDesignVar""" - return ( - "__class__" in obj_dict.keys() - and obj_dict["__class__"] - in [ - "OptiDesignVar", - ] - ) + return "__class__" in obj_dict.keys() and obj_dict["__class__"] in [ + "OptiDesignVar", + ] + def convert_optidesignvar(optidesignvar_dict): """Update the old OptiDesignVar to the new ones OptiDesignVarSet & OptiDesignVarInterval""" @@ -422,16 +417,19 @@ def convert_optidesignvar(optidesignvar_dict): ) # Copy dict to keep original version optidesignvar_dict_new = optidesignvar_dict.copy() - + if optidesignvar_dict_new["type_var"] == "set": del optidesignvar_dict_new["type_var"] OptiDesignVarSet = import_class("pyleecan.Classes", "OptiDesignVarSet") return OptiDesignVarSet(init_dict=optidesignvar_dict_new) else: del optidesignvar_dict_new["type_var"] - OptiDesignVarInterval = import_class("pyleecan.Classes", "OptiDesignVarInterval") + OptiDesignVarInterval = import_class( + "pyleecan.Classes", "OptiDesignVarInterval" + ) return OptiDesignVarInterval(init_dict=optidesignvar_dict_new) + def is_before_version(ref_version, check_version): """Check if a version str is before another version str @@ -496,6 +494,10 @@ def create_update_dict(file_version): update_dict["OP_matrix"] = is_before_version(OP_MAT_VERSION, file_version) update_dict["Yoke_Notch"] = is_before_version(Yoke_Notch_VERSION, file_version) update_dict["VarParam"] = is_before_version(VARPARAM_VERSION, file_version) - update_dict["OptiConstraint"] = is_before_version(OptiConstraint_VERSION, file_version) - update_dict["OptiDesignVar"] = is_before_version(OptiDesignVar_VERSION, file_version) + update_dict["OptiConstraint"] = is_before_version( + OptiConstraint_VERSION, file_version + ) + update_dict["OptiDesignVar"] = is_before_version( + OptiDesignVar_VERSION, file_version + ) return update_dict diff --git a/pyleecan/Generator/ClassesRef/Simulation/VarOpti.csv b/pyleecan/Generator/ClassesRef/Simulation/VarOpti.csv index 1a8056c68..714481eb4 100644 --- a/pyleecan/Generator/ClassesRef/Simulation/VarOpti.csv +++ b/pyleecan/Generator/ClassesRef/Simulation/VarOpti.csv @@ -1,4 +1,4 @@ Variable name,Unit,Description (EN),Size,Type,Default value,Minimum value,Maximum value,,Package,Inherit,Methods,Constant Name,Constant Value,Class description -objective_list,-,List containing OptiObjective objects,0,[OptiObjective],-1,,,,Simulation,VarParam,check,VERSION,1,Handle Optimization multisimulation by varying parameters -constraint_list,-,List containing OptiConstraint objects,0,[OptiConstraint],-1,,,,,,run,NAME,"""Optimization""", +objective_list,-,List containing OptiObjective objects,0,[OptiObjective],,,,,Simulation,VarParam,check,VERSION,1,Handle Optimization multisimulation by varying parameters +constraint_list,-,List containing OptiConstraint objects,0,[OptiConstraint],,,,,,,run,NAME,"""Optimization""", solver,-,Object that solve an OptiProblem,0,OptiSolver,None,,,,,,get_full_solver,,, diff --git a/pyleecan/Methods/Simulation/VarOpti/get_full_solver.py b/pyleecan/Methods/Simulation/VarOpti/get_full_solver.py index 1dead4982..bd512ae83 100644 --- a/pyleecan/Methods/Simulation/VarOpti/get_full_solver.py +++ b/pyleecan/Methods/Simulation/VarOpti/get_full_solver.py @@ -1,5 +1,6 @@ from ....Classes.OptiProblem import OptiProblem + def get_full_solver(self): """Method to return a fully setted solver""" @@ -11,7 +12,7 @@ def get_full_solver(self): # Creation of the problem problem = OptiProblem( - simu=ref_simu, + simu=ref_simu, design_var=self.paramexplorer_list, obj_func=self.objective_list, datakeeper_list=self.datakeeper_list, @@ -22,4 +23,4 @@ def get_full_solver(self): solver = self.solver.copy() solver.problem = problem - return solver \ No newline at end of file + return solver From 09aa18d640d2b7267f0708f4310985f8b29cf57e Mon Sep 17 00:00:00 2001 From: Bonneel Pierre Date: Tue, 3 Jan 2023 13:34:38 +0100 Subject: [PATCH 08/10] [VI] Remove unused quadpy requirement --- Exe_gen/pyleecan.spec | 3 +-- pyleecan/Methods/Mesh/FPGNTri/get_gauss_points.py | 3 +-- requirements-full.txt | 1 - requirements.txt | 1 - setup.py | 1 - 5 files changed, 2 insertions(+), 7 deletions(-) diff --git a/Exe_gen/pyleecan.spec b/Exe_gen/pyleecan.spec index 8a8576d35..296a37b03 100644 --- a/Exe_gen/pyleecan.spec +++ b/Exe_gen/pyleecan.spec @@ -7,8 +7,7 @@ block_cipher = None a = Analysis([SPECPATH + '/pyleecan/run_GUI.py'], pathex=[SPECPATH], binaries=[], - datas=[(SPECPATH + '\\Exenv\\Lib\\site-packages\\quadpy', '.\\quadpy'), - (SPECPATH + '\\Exenv\\Lib\\site-packages\\pyvista','.\\pyvista'), + datas=[(SPECPATH + '\\Exenv\\Lib\\site-packages\\pyvista','.\\pyvista'), (SPECPATH + '\\Exenv\\Lib\\site-packages\\scipy','.\\scipy'), (SPECPATH + '\\Exenv\\Lib\\site-packages\\scipy.libs','.\\scipy.libs'), (SPECPATH + '\\Exenv\\Lib\\site-packages\\matplotlib','.\\matplotlib'), diff --git a/pyleecan/Methods/Mesh/FPGNTri/get_gauss_points.py b/pyleecan/Methods/Mesh/FPGNTri/get_gauss_points.py index 4c19ee1b4..54c4e27f7 100644 --- a/pyleecan/Methods/Mesh/FPGNTri/get_gauss_points.py +++ b/pyleecan/Methods/Mesh/FPGNTri/get_gauss_points.py @@ -1,11 +1,10 @@ # -*- coding: utf-8 -*- -import quadpy - def get_gauss_points(self): """Return the gauss points and weights for Triangle3 cell""" + raise Exception("Quadpy is not possible to use anymore, need to rewrite this method") nb_gauss_points = self.nb_gauss_point scheme = quadpy.tn.grundmann_moeller(2, nb_gauss_points) gauss_pts = scheme.points diff --git a/requirements-full.txt b/requirements-full.txt index ffc2112e8..b791ac6e4 100644 --- a/requirements-full.txt +++ b/requirements-full.txt @@ -9,7 +9,6 @@ pyfemm>=0.1.3 PySide2>=5.15.2 pyuff>=1.25 pyvista>=0.25.3,<=0.31.3 -quadpy SciDataTool>=2.5.0 scipy>=1.4.1 setuptools diff --git a/requirements.txt b/requirements.txt index a29b8244f..c1787f311 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,7 +9,6 @@ pyfemm>=0.1.3 PySide2>=5.15.2 pyuff>=1.25 pyvista>=0.25.3,<=0.31.3 -quadpy SciDataTool>=2.5.0 scipy>=1.4.1 setuptools diff --git a/setup.py b/setup.py index 90d70a0ce..bce5e9c04 100644 --- a/setup.py +++ b/setup.py @@ -44,7 +44,6 @@ "PySide2>=5.15.2", "pyuff>=1.25", "pyvista>=0.25.3,<=0.31.3", - "quadpy", "SciDataTool>=2.5.0", "scipy>=1.4.1", "setuptools", From 3958cdc99c36b321c2f94b7ba91197af5d08c7c5 Mon Sep 17 00:00:00 2001 From: Bonneel Pierre Date: Tue, 3 Jan 2023 13:34:57 +0100 Subject: [PATCH 09/10] [CC] Updating retro test --- .../Data/Retrocompatibility/OP_matrix/new/test_multi_multi.json | 2 +- .../Data/Retrocompatibility/OP_matrix/old/test_multi_multi.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/Data/Retrocompatibility/OP_matrix/new/test_multi_multi.json b/Tests/Data/Retrocompatibility/OP_matrix/new/test_multi_multi.json index 480ae2cb6..f81d7b846 100644 --- a/Tests/Data/Retrocompatibility/OP_matrix/new/test_multi_multi.json +++ b/Tests/Data/Retrocompatibility/OP_matrix/new/test_multi_multi.json @@ -1196,7 +1196,7 @@ "postproc_list": [], "struct": null, "var_simu": { - "__class__": "VarParam", + "__class__": "VarParamSweep", "datakeeper_list": [ { "__class__": "DataKeeper", diff --git a/Tests/Data/Retrocompatibility/OP_matrix/old/test_multi_multi.json b/Tests/Data/Retrocompatibility/OP_matrix/old/test_multi_multi.json index a065e616f..c13a07cf0 100644 --- a/Tests/Data/Retrocompatibility/OP_matrix/old/test_multi_multi.json +++ b/Tests/Data/Retrocompatibility/OP_matrix/old/test_multi_multi.json @@ -1196,7 +1196,7 @@ "postproc_list": [], "struct": null, "var_simu": { - "__class__": "VarParam", + "__class__": "VarParamSweep", "datakeeper_list": [ { "__class__": "DataKeeper", From 2fefa12eac449ee1ff6c701b867263e02c9ad1c2 Mon Sep 17 00:00:00 2001 From: Bonneel Pierre Date: Tue, 3 Jan 2023 13:39:49 +0100 Subject: [PATCH 10/10] [CC] Updating version before release --- pyleecan/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyleecan/__init__.py b/pyleecan/__init__.py index fd171707c..44a74e395 100644 --- a/pyleecan/__init__.py +++ b/pyleecan/__init__.py @@ -11,6 +11,6 @@ else: USER_DIR = os.environ["HOME"] + "/.local/share/" + PACKAGE_NAME -__version__ = "1.4.1" +__version__ = "1.4.2" init_default_log()