From cc22ee181570e4429e7a0cb7df0aa898316c7002 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Fri, 12 May 2023 14:53:45 -0700 Subject: [PATCH 001/131] Move merge table outside v1 --- src/spyglass/lfp/lfp_merge.py | 49 +++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 src/spyglass/lfp/lfp_merge.py diff --git a/src/spyglass/lfp/lfp_merge.py b/src/spyglass/lfp/lfp_merge.py new file mode 100644 index 000000000..0bc5cf8cd --- /dev/null +++ b/src/spyglass/lfp/lfp_merge.py @@ -0,0 +1,49 @@ +import datajoint as dj +from spyglass.lfp.v1 import LFP, ImportedLFP + +schema = dj.schema("lfp") + + +@schema +class LFPOutput(dj.Manual): + definition = """ + lfp_id: uuid + """ + + class LFP(dj.Part): + definition = """ + -> master + -> LFP + """ + + class ImportedLFP(dj.Part): + definition = """ + -> master + -> ImportedLFP + """ + + @staticmethod + def get_lfp_object(key: dict): + """Returns the lfp object corresponding to the key + + Parameters + ---------- + key : dict + A dictionary containing some combination of + uuid, + nwb_file_name, + lfp_electrode_group_name, + interval_list_name, + fir_filter_name + + Returns + ------- + lfp_object + The entry or entries in the LFPOutput part table that corresponds to the key + """ + # first check if this returns anything from the LFP table + lfp_object = LFPOutput.LFP & key + if lfp_object is not None: + return LFP & lfp_object.fetch("KEY") + else: + return ImportedLFP & (LFPOutput.ImportedLFP & key).fetch("KEY") From 4170ef4983d6de06c631e09028cd75f770dd62d1 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Fri, 12 May 2023 14:53:54 -0700 Subject: [PATCH 002/131] Add vscode settings --- .vscode/settings.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index dcc463ea8..7a5a4f696 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,7 +4,10 @@ "files.trimFinalNewlines": true, "editor.multiCursorModifier": "ctrlCmd", "autoDocstring.docstringFormat": "numpy", - "python.formatting.provider": "black", + "python.formatting.provider": "none", "remote.SSH.remoteServerListenOnSocket": true, "git.confirmSync": false, + "[python]": { + "editor.defaultFormatter": "ms-python.black-formatter" + }, } \ No newline at end of file From 6fcf2e65867a006a26ed2831ed00d2e25ffceeec Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Fri, 12 May 2023 14:54:43 -0700 Subject: [PATCH 003/131] Change back --- src/spyglass/lfp/lfp_merge.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/spyglass/lfp/lfp_merge.py b/src/spyglass/lfp/lfp_merge.py index 0bc5cf8cd..40fca723c 100644 --- a/src/spyglass/lfp/lfp_merge.py +++ b/src/spyglass/lfp/lfp_merge.py @@ -12,13 +12,13 @@ class LFPOutput(dj.Manual): class LFP(dj.Part): definition = """ - -> master + -> LFPOutput -> LFP """ class ImportedLFP(dj.Part): definition = """ - -> master + -> LFPOutput -> ImportedLFP """ From 8093e1593595423a08e3c07090cc8f8e582b59b4 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Wed, 17 May 2023 11:07:11 -0700 Subject: [PATCH 004/131] Add more info to merge table. --- src/spyglass/lfp/lfp_merge.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/spyglass/lfp/lfp_merge.py b/src/spyglass/lfp/lfp_merge.py index 40fca723c..404a0d6e5 100644 --- a/src/spyglass/lfp/lfp_merge.py +++ b/src/spyglass/lfp/lfp_merge.py @@ -8,17 +8,21 @@ class LFPOutput(dj.Manual): definition = """ lfp_id: uuid + --- + stream: varchar(40) """ class LFP(dj.Part): definition = """ -> LFPOutput + --- -> LFP """ class ImportedLFP(dj.Part): definition = """ -> LFPOutput + --- -> ImportedLFP """ From 522509fa7b3d6fcbe8a7faf17028c63d42c6de26 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Thu, 18 May 2023 11:17:20 -0700 Subject: [PATCH 005/131] Change variable name to reflect that it is a constant --- src/spyglass/lfp/v1/lfp.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/spyglass/lfp/v1/lfp.py b/src/spyglass/lfp/v1/lfp.py index ed94b55fe..af7f6fce9 100644 --- a/src/spyglass/lfp/v1/lfp.py +++ b/src/spyglass/lfp/v1/lfp.py @@ -26,7 +26,7 @@ schema = dj.schema("lfp_v1") -min_lfp_interval_length = 1.0 # 1 second minimum interval length +MIN_LFP_INTERVAL_DURATION = 1.0 # 1 second minimum interval duration @schema @@ -120,10 +120,10 @@ def make(self, key): } ).fetch1("valid_times") valid_times = interval_list_intersect( - user_valid_times, raw_valid_times, min_length=min_lfp_interval_length + user_valid_times, raw_valid_times, min_length=MIN_LFP_INTERVAL_DURATION ) print( - f"LFP: found {len(valid_times)} intervals > {min_lfp_interval_length} sec long." + f"LFP: found {len(valid_times)} intervals > {MIN_LFP_INTERVAL_DURATION} sec long." ) # target 1 KHz sampling rate From 12965de21d09ff44eebd4ee2fcda83b8ef932949 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Thu, 18 May 2023 11:17:56 -0700 Subject: [PATCH 006/131] Remove unused import --- src/spyglass/lfp/v1/lfp.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/spyglass/lfp/v1/lfp.py b/src/spyglass/lfp/v1/lfp.py index af7f6fce9..4f28b5373 100644 --- a/src/spyglass/lfp/v1/lfp.py +++ b/src/spyglass/lfp/v1/lfp.py @@ -7,7 +7,6 @@ import numpy as np import pandas as pd import pynwb -import scipy.stats as stats from spyglass.common.common_ephys import Electrode, Raw from spyglass.common.common_filter import FirFilter From 21197ed84fb28aa8959e40f572ebd6bd784646a8 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Thu, 18 May 2023 11:20:27 -0700 Subject: [PATCH 007/131] Use string method --- src/spyglass/lfp/v1/lfp.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/spyglass/lfp/v1/lfp.py b/src/spyglass/lfp/v1/lfp.py index 4f28b5373..15c71c815 100644 --- a/src/spyglass/lfp/v1/lfp.py +++ b/src/spyglass/lfp/v1/lfp.py @@ -172,12 +172,12 @@ def make(self, key): # finally, we need to censor the valid times to account for the downsampling lfp_valid_times = interval_list_censor(valid_times, timestamp_interval) # add an interval list for the LFP valid times, skipping duplicates - key["interval_list_name"] = ( - key["lfp_electrode_group_name"] - + "_" - + key["target_interval_list_name"] - + "_" - + "valid times" + key["interval_list_name"] = "_".join( + ( + key["lfp_electrode_group_name"], + key["target_interval_list_name"], + "valid times", + ) ) IntervalList.insert1( { From 2ed327eb7f5a120dce5fff302615a5aed2c7c2bf Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Thu, 18 May 2023 11:29:59 -0700 Subject: [PATCH 008/131] Remove LFPOutput from v1 --- src/spyglass/lfp/__init__.py | 1 + src/spyglass/lfp/v1/__init__.py | 3 +- src/spyglass/lfp/v1/lfp.py | 51 ++++----------------------------- 3 files changed, 8 insertions(+), 47 deletions(-) create mode 100644 src/spyglass/lfp/__init__.py diff --git a/src/spyglass/lfp/__init__.py b/src/spyglass/lfp/__init__.py new file mode 100644 index 000000000..f0b973f5b --- /dev/null +++ b/src/spyglass/lfp/__init__.py @@ -0,0 +1 @@ +from spyglass.lfp.lfp_merge import LFPOutput diff --git a/src/spyglass/lfp/v1/__init__.py b/src/spyglass/lfp/v1/__init__.py index 63b7f7bdd..a8b424686 100644 --- a/src/spyglass/lfp/v1/__init__.py +++ b/src/spyglass/lfp/v1/__init__.py @@ -1,5 +1,5 @@ # flake8: noqa -from .lfp import ( +from spyglass.lfp import ( LFP, ImportedLFP, LFPArtifactDetection, @@ -9,6 +9,5 @@ LFPBand, LFPBandSelection, LFPElectrodeGroup, - LFPOutput, LFPSelection, ) diff --git a/src/spyglass/lfp/v1/lfp.py b/src/spyglass/lfp/v1/lfp.py index 15c71c815..aec9d6f61 100644 --- a/src/spyglass/lfp/v1/lfp.py +++ b/src/spyglass/lfp/v1/lfp.py @@ -95,6 +95,8 @@ class LFP(dj.Computed): """ def make(self, key): + from spyglass.lfp.lfp_merge import LFPOutput + # get the NWB object with the data nwbf_key = {"nwb_file_name": key["nwb_file_name"]} rawdata = (Raw & nwbf_key).fetch_nwb()[0]["raw"] @@ -220,51 +222,6 @@ class ImportedLFP(dj.Imported): """ -@schema -class LFPOutput(dj.Manual): - definition = """ - lfp_id: uuid - """ - - class LFP(dj.Part): - definition = """ - -> LFPOutput - -> LFP - """ - - class ImportedLFP(dj.Part): - definition = """ - -> LFPOutput - -> ImportedLFP - """ - - @staticmethod - def get_lfp_object(key: dict): - """Returns the lfp object corresponding to the key - - Parameters - ---------- - key : dict - A dictionary containing some combination of - uuid, - nwb_file_name, - lfp_electrode_group_name, - interval_list_name, - fir_filter_name - - Returns - ------- - lfp_object - The entry or entries in the LFPOutput part table that corresponds to the key - """ - # first check if this returns anything from the LFP table - lfp_object = LFPOutput.LFP & key - if lfp_object is not None: - return LFP & lfp_object.fetch("KEY") - else: - return ImportedLFP & (LFPOutput.ImportedLFP & key).fetch("KEY") - - # add artifact detection @schema class LFPArtifactDetectionParameters(dj.Manual): @@ -656,6 +613,8 @@ def set_lfp_band_electrodes( """ # Error checks on parameters # electrode_list + from spyglass.lfp.lfp_merge import LFPOutput + lfp_object = LFPOutput.get_lfp_object({"lfp_id": lfp_id}) print(lfp_object) lfp_key = lfp_object.fetch1("KEY") @@ -751,6 +710,8 @@ class LFPBand(dj.Computed): """ def make(self, key): + from spyglass.lfp.lfp_merge import LFPOutput + # get the NWB object with the lfp data; FIX: change to fetch with additional infrastructure lfp_object = (LFP() & {"nwb_file_name": key["nwb_file_name"]}).fetch_nwb()[0][ "lfp" From 4622e32e23c801c1a5667b2ebf897aaddc33fc28 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Mon, 22 May 2023 15:24:03 -0700 Subject: [PATCH 009/131] Use versioning for LFP and ImportedLFPV1 --- src/spyglass/lfp/lfp_merge.py | 12 ++++++------ src/spyglass/lfp/v1/lfp.py | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/spyglass/lfp/lfp_merge.py b/src/spyglass/lfp/lfp_merge.py index 404a0d6e5..2485b55b0 100644 --- a/src/spyglass/lfp/lfp_merge.py +++ b/src/spyglass/lfp/lfp_merge.py @@ -1,5 +1,5 @@ import datajoint as dj -from spyglass.lfp.v1 import LFP, ImportedLFP +from spyglass.lfp.v1 import LFPV1, ImportedLFPV1 schema = dj.schema("lfp") @@ -12,18 +12,18 @@ class LFPOutput(dj.Manual): stream: varchar(40) """ - class LFP(dj.Part): + class LFPV1(dj.Part): definition = """ -> LFPOutput --- - -> LFP + -> LFPV1 """ class ImportedLFP(dj.Part): definition = """ -> LFPOutput --- - -> ImportedLFP + -> ImportedLFPV1 """ @staticmethod @@ -48,6 +48,6 @@ def get_lfp_object(key: dict): # first check if this returns anything from the LFP table lfp_object = LFPOutput.LFP & key if lfp_object is not None: - return LFP & lfp_object.fetch("KEY") + return LFPV1 & lfp_object.fetch("KEY") else: - return ImportedLFP & (LFPOutput.ImportedLFP & key).fetch("KEY") + return ImportedLFPV1 & (LFPOutput.ImportedLFP & key).fetch("KEY") diff --git a/src/spyglass/lfp/v1/lfp.py b/src/spyglass/lfp/v1/lfp.py index aec9d6f61..183d8212c 100644 --- a/src/spyglass/lfp/v1/lfp.py +++ b/src/spyglass/lfp/v1/lfp.py @@ -84,7 +84,7 @@ class LFPSelection(dj.Manual): @schema -class LFP(dj.Computed): +class LFPV1(dj.Computed): definition = """ -> LFPSelection --- @@ -211,7 +211,7 @@ def fetch1_dataframe(self, *attrs, **kwargs): @schema -class ImportedLFP(dj.Imported): +class ImportedLFPV1(dj.Imported): definition = """ -> Session -> LFPElectrodeGroup From 63d8220c54420b68d22cee077cd39ac46e60f5b3 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Thu, 25 May 2023 14:18:32 -0700 Subject: [PATCH 010/131] Remove unused imports --- src/spyglass/lfp/v1/lfp.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/spyglass/lfp/v1/lfp.py b/src/spyglass/lfp/v1/lfp.py index e0b2cd3cd..db5108948 100644 --- a/src/spyglass/lfp/v1/lfp.py +++ b/src/spyglass/lfp/v1/lfp.py @@ -7,9 +7,7 @@ import numpy as np import pandas as pd import pynwb -import scipy.stats as stats from scipy.signal import hilbert -import math from spyglass.common.common_ephys import Electrode, Raw from spyglass.common.common_filter import FirFilterParameters @@ -946,7 +944,7 @@ def compute_analytic_signal(self, electrode_list, **kwargs): def compute_signal_phase(self, electrode_list=[], **kwargs): analytic_signal_df = self.compute_analytic_signal(electrode_list, **kwargs) return pd.DataFrame( - np.angle(analytic_signal_df) + math.pi, + np.angle(analytic_signal_df) + np.pi, columns=analytic_signal_df.columns, index=analytic_signal_df.index, ) From 9eb4f6213c4a7201a1f50fbfbec843f3883e612f Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Thu, 25 May 2023 14:26:24 -0700 Subject: [PATCH 011/131] Fix table names --- src/spyglass/lfp/v1/lfp.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/spyglass/lfp/v1/lfp.py b/src/spyglass/lfp/v1/lfp.py index db5108948..f1bacc348 100644 --- a/src/spyglass/lfp/v1/lfp.py +++ b/src/spyglass/lfp/v1/lfp.py @@ -287,7 +287,7 @@ def make(self, key): ) # get LFP data - lfp_eseries = (LFP() & key).fetch_nwb()[0]["lfp"] + lfp_eseries = (LFPV1() & key).fetch_nwb()[0]["lfp"] artifact_removed_valid_times, artifact_times = _get_artifact_times( lfp_eseries, @@ -470,7 +470,7 @@ def _get_artifact_times( artifact_intervals_s = reduce(_union_concat, artifact_intervals_s) # im not sure how to get the key in this function - sampling_frequency = (LFP() & key).fetch("lfp_sampling_rate")[0] + sampling_frequency = (LFPV1() & key).fetch("lfp_sampling_rate")[0] valid_intervals = get_valid_intervals( valid_timestamps, sampling_frequency, 1.5, 0.000001 @@ -717,7 +717,7 @@ def make(self, key): from spyglass.lfp.lfp_merge import LFPOutput # get the NWB object with the lfp data; FIX: change to fetch with additional infrastructure - lfp_object = (LFP() & {"nwb_file_name": key["nwb_file_name"]}).fetch_nwb()[0][ + lfp_object = (LFPV1() & {"nwb_file_name": key["nwb_file_name"]}).fetch_nwb()[0][ "lfp" ] From 170c510cb0c3e0399087bf2e49bc0437bdf0b32a Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Fri, 26 May 2023 11:43:33 -0700 Subject: [PATCH 012/131] Reorganize pipeline --- src/spyglass/lfp/lfp_merge.py | 36 +- src/spyglass/lfp/v1/__init__.py | 11 +- src/spyglass/lfp/v1/filtered_lfp.py | 405 ++++++++++++++ src/spyglass/lfp/v1/lfp.py | 827 ++-------------------------- src/spyglass/lfp/v1/lfp_artifact.py | 366 ++++++++++++ 5 files changed, 851 insertions(+), 794 deletions(-) create mode 100644 src/spyglass/lfp/v1/filtered_lfp.py create mode 100644 src/spyglass/lfp/v1/lfp_artifact.py diff --git a/src/spyglass/lfp/lfp_merge.py b/src/spyglass/lfp/lfp_merge.py index 2485b55b0..42a05f9f3 100644 --- a/src/spyglass/lfp/lfp_merge.py +++ b/src/spyglass/lfp/lfp_merge.py @@ -1,5 +1,9 @@ import datajoint as dj -from spyglass.lfp.v1 import LFPV1, ImportedLFPV1 +import pandas as pd + +from spyglass.common.common_nwbfile import AnalysisNwbfile +from spyglass.lfp.v1.lfp import LFPV1, ImportedLFPV1 +from spyglass.utils.dj_helper_fn import fetch_nwb schema = dj.schema("lfp") @@ -15,17 +19,43 @@ class LFPOutput(dj.Manual): class LFPV1(dj.Part): definition = """ -> LFPOutput - --- -> LFPV1 + --- + -> AnalysisNwbfile """ + def fetch_nwb(self, *attrs, **kwargs): + return fetch_nwb( + self, (AnalysisNwbfile, "analysis_file_abs_path"), *attrs, **kwargs + ) + + def fetch1_dataframe(self, *attrs, **kwargs): + nwb_lfp = self.fetch_nwb()[0] + return pd.DataFrame( + nwb_lfp["lfp"].data, + index=pd.Index(nwb_lfp["lfp"].timestamps, name="time"), + ) + class ImportedLFP(dj.Part): definition = """ -> LFPOutput - --- -> ImportedLFPV1 + --- + -> AnalysisNwbfile """ + def fetch_nwb(self, *attrs, **kwargs): + return fetch_nwb( + self, (AnalysisNwbfile, "analysis_file_abs_path"), *attrs, **kwargs + ) + + def fetch1_dataframe(self, *attrs, **kwargs): + nwb_lfp = self.fetch_nwb()[0] + return pd.DataFrame( + nwb_lfp["lfp"].data, + index=pd.Index(nwb_lfp["lfp"].timestamps, name="time"), + ) + @staticmethod def get_lfp_object(key: dict): """Returns the lfp object corresponding to the key diff --git a/src/spyglass/lfp/v1/__init__.py b/src/spyglass/lfp/v1/__init__.py index a8b424686..81b4aada3 100644 --- a/src/spyglass/lfp/v1/__init__.py +++ b/src/spyglass/lfp/v1/__init__.py @@ -1,13 +1,10 @@ # flake8: noqa -from spyglass.lfp import ( - LFP, - ImportedLFP, +from spyglass.lfp.v1.lfp import LFPV1, ImportedLFPV1, LFPElectrodeGroup, LFPSelection +from spyglass.lfp.v1.lfp_artifact import ( LFPArtifactDetection, LFPArtifactDetectionParameters, LFPArtifactDetectionSelection, LFPArtifactRemovedIntervalList, - LFPBand, - LFPBandSelection, - LFPElectrodeGroup, - LFPSelection, ) + +# from spyglass.lfp.v1.filtered_lfp import LFPBand, LFPBandSelection diff --git a/src/spyglass/lfp/v1/filtered_lfp.py b/src/spyglass/lfp/v1/filtered_lfp.py new file mode 100644 index 000000000..ca3afa934 --- /dev/null +++ b/src/spyglass/lfp/v1/filtered_lfp.py @@ -0,0 +1,405 @@ +import datajoint as dj +import numpy as np +import pandas as pd +import pynwb +from scipy.signal import hilbert + +from spyglass.common.common_ephys import Electrode +from spyglass.common.common_filter import FirFilterParameters +from spyglass.common.common_interval import ( + IntervalList, + interval_list_censor, + interval_list_contains_ind, + interval_list_intersect, +) +from spyglass.common.common_nwbfile import AnalysisNwbfile +from spyglass.lfp.lfp_merge import LFPOutput +from spyglass.lfp.v1.lfp import LFPElectrodeGroup +from spyglass.utils.dj_helper_fn import fetch_nwb # dj_replace +from spyglass.utils.nwb_helper_fn import get_electrode_indices + +schema = dj.schema("lfp_v1") + + +@schema +class LFPBandSelection(dj.Manual): + definition = """ + -> LFPOutput + -> FirFilterParameters # the filter to use for the data + -> IntervalList.proj(target_interval_list_name='interval_list_name') # the original set of times to be filtered + lfp_band_sampling_rate: int # the sampling rate for this band + --- + min_interval_len = 1.0: float # the minimum length of a valid interval to filter + """ + + class LFPBandElectrode(dj.Part): + definition = """ + -> LFPBandSelection + -> LFPElectrodeGroup.LFPElectrode # the LFP electrode to be filtered + reference_elect_id = -1: int # the reference electrode to use; -1 for no reference + --- + """ + + def set_lfp_band_electrodes( + self, + nwb_file_name, + lfp_id, + electrode_list, + filter_name, + interval_list_name, + reference_electrode_list, + lfp_band_sampling_rate, + ): + # TODO: fix docstring to match normal format. + """ + Adds an entry for each electrode in the electrode_list with the specified filter, interval_list, and + reference electrode. + :param nwb_file_name: string - the name of the nwb file for the desired session + :param lfp_id: uuid - the uuid for the LFPOutput to use + :param electrode_list: list of LFP electrodes (electrode ids) to be filtered + :param filter_name: the name of the filter (from the FirFilterParameters schema) + :param interval_name: the name of the interval list (from the IntervalList schema) + :param reference_electrode_list: A single electrode id corresponding to the reference to use for all + electrodes or a list with one element per entry in the electrode_list + :param lfp_band_sampling_rate: The output sampling rate to be used for the filtered data; must be an + integer divisor of the LFP sampling rate + :return: none + """ + # Error checks on parameters + # electrode_list + + lfp_object = LFPOutput.get_lfp_object({"lfp_id": lfp_id}) + print(lfp_object) + lfp_key = lfp_object.fetch1("KEY") + query = LFPElectrodeGroup().LFPElectrode() & lfp_key + available_electrodes = query.fetch("electrode_id") + if not np.all(np.isin(electrode_list, available_electrodes)): + raise ValueError( + "All elements in electrode_list must be valid electrode_ids in the LFPElectodeGroup table" + ) + # sampling rate + print(lfp_object) + lfp_sampling_rate = (lfp_object & lfp_key).fetch1("lfp_sampling_rate") + decimation = lfp_sampling_rate // lfp_band_sampling_rate + if lfp_sampling_rate // decimation != lfp_band_sampling_rate: + raise ValueError( + f"lfp_band_sampling rate {lfp_band_sampling_rate} is not an integer divisor of lfp " + f"samping rate {lfp_sampling_rate}" + ) + # filter + query = FirFilterParameters() & { + "filter_name": filter_name, + "filter_sampling_rate": lfp_sampling_rate, + } + if not query: + raise ValueError( + f"filter {filter_name}, sampling rate {lfp_sampling_rate} is not in the FirFilterParameters table" + ) + # interval_list + query = IntervalList() & { + "nwb_file_name": nwb_file_name, + "interval_name": interval_list_name, + } + if not query: + raise ValueError( + f"interval list {interval_list_name} is not in the IntervalList table; the list must be " + "added before this function is called" + ) + # reference_electrode_list + if len(reference_electrode_list) != 1 and len(reference_electrode_list) != len( + electrode_list + ): + raise ValueError( + "reference_electrode_list must contain either 1 or len(electrode_list) elements" + ) + # add a -1 element to the list to allow for the no reference option + available_electrodes = np.append(available_electrodes, [-1]) + if not np.all(np.isin(reference_electrode_list, available_electrodes)): + raise ValueError( + "All elements in reference_electrode_list must be valid electrode_ids in the LFPSelection " + "table" + ) + + # make a list of all the references + ref_list = np.zeros((len(electrode_list),)) + ref_list[:] = reference_electrode_list + + key = dict() + key["nwb_file_name"] = nwb_file_name + key["lfp_id"] = lfp_id + key["filter_name"] = filter_name + key["filter_sampling_rate"] = lfp_sampling_rate + key["target_interval_list_name"] = interval_list_name + key["lfp_band_sampling_rate"] = lfp_sampling_rate // decimation + # insert an entry into the main LFPBandSelectionTable + self.insert1(key, skip_duplicates=True) + + key["lfp_electrode_group_name"] = lfp_object.fetch1("lfp_electrode_group_name") + # iterate through all of the new elements and add them + for e, r in zip(electrode_list, ref_list): + elect_key = ( + LFPElectrodeGroup.LFPElectrode + & { + "nwb_file_name": nwb_file_name, + "lfp_electrode_group_name": key["lfp_electrode_group_name"], + "electrode_id": e, + } + ).fetch1("KEY") + for item in elect_key: + key[item] = elect_key[item] + query = Electrode & {"nwb_file_name": nwb_file_name, "electrode_id": e} + key["reference_elect_id"] = r + self.LFPBandElectrode().insert1(key, skip_duplicates=True) + + +@schema +class LFPBand(dj.Computed): + definition = """ + -> LFPBandSelection + --- + -> AnalysisNwbfile + -> IntervalList + filtered_data_object_id: varchar(40) # the NWB object ID for loading this object from the file + """ + + def make(self, key): + # get the NWB object with the lfp data; FIX: change to fetch with additional infrastructure + lfp_object = ( + LFPOutput() & {"nwb_file_name": key["nwb_file_name"]} + ).fetch_nwb()[0]["lfp"] + + # get the electrodes to be filtered and their references + lfp_band_elect_id, lfp_band_ref_id = ( + LFPBandSelection().LFPBandElectrode() & key + ).fetch("electrode_id", "reference_elect_id") + + # sort the electrodes to make sure they are in ascending order + lfp_band_elect_id = np.asarray(lfp_band_elect_id) + lfp_band_ref_id = np.asarray(lfp_band_ref_id) + lfp_sort_order = np.argsort(lfp_band_elect_id) + lfp_band_elect_id = lfp_band_elect_id[lfp_sort_order] + lfp_band_ref_id = lfp_band_ref_id[lfp_sort_order] + + lfp_sampling_rate = ( + LFPOutput() + .get_lfp_object({"lfp_id": key["lfp_id"]}) + .fetch1("lfp_sampling_rate") + ) + interval_list_name, lfp_band_sampling_rate = (LFPBandSelection() & key).fetch1( + "target_interval_list_name", "lfp_band_sampling_rate" + ) + valid_times = ( + IntervalList() + & { + "nwb_file_name": key["nwb_file_name"], + "interval_list_name": interval_list_name, + } + ).fetch1("valid_times") + # the valid_times for this interval may be slightly beyond the valid times for the lfp itself, + # so we have to intersect the two + lfp_interval_list = ( + LFPOutput() + .get_lfp_object({"lfp_id": key["lfp_id"]}) + .fetch1("interval_list_name") + ) + lfp_valid_times = ( + IntervalList() + & { + "nwb_file_name": key["nwb_file_name"], + "interval_list_name": lfp_interval_list, + } + ).fetch1("valid_times") + min_length = (LFPBandSelection & key).fetch1("min_interval_len") + lfp_band_valid_times = interval_list_intersect( + valid_times, lfp_valid_times, min_length=min_length + ) + + filter_name, filter_sampling_rate, lfp_band_sampling_rate = ( + LFPBandSelection() & key + ).fetch1("filter_name", "filter_sampling_rate", "lfp_band_sampling_rate") + + decimation = int(lfp_sampling_rate) // lfp_band_sampling_rate + + # load in the timestamps + timestamps = np.asarray(lfp_object.timestamps) + # get the indices of the first timestamp and the last timestamp that are within the valid times + included_indices = interval_list_contains_ind(lfp_band_valid_times, timestamps) + # pad the indices by 1 on each side to avoid message in filter_data + if included_indices[0] > 0: + included_indices[0] -= 1 + if included_indices[-1] != len(timestamps) - 1: + included_indices[-1] += 1 + + timestamps = timestamps[included_indices[0] : included_indices[-1]] + + # load all the data to speed filtering + lfp_data = np.asarray( + lfp_object.data[included_indices[0] : included_indices[-1], :], + dtype=type(lfp_object.data[0][0]), + ) + + # get the indices of the electrodes to be filtered and the references + lfp_band_elect_index = get_electrode_indices(lfp_object, lfp_band_elect_id) + lfp_band_ref_index = get_electrode_indices(lfp_object, lfp_band_ref_id) + + # subtract off the references for the selected channels + for index, elect_index in enumerate(lfp_band_elect_index): + if lfp_band_ref_id[index] != -1: + lfp_data[:, elect_index] = ( + lfp_data[:, elect_index] - lfp_data[:, lfp_band_ref_index[index]] + ) + + # get the LFP filter that matches the raw data + filter = ( + FirFilterParameters() + & {"filter_name": filter_name} + & {"filter_sampling_rate": filter_sampling_rate} + ).fetch(as_dict=True) + if len(filter) == 0: + raise ValueError( + f"Filter {filter_name} and sampling_rate {lfp_band_sampling_rate} does not exit in the " + "FirFilterParameters table" + ) + + filter_coeff = filter[0]["filter_coeff"] + if len(filter_coeff) == 0: + print( + f"Error in LFPBand: no filter found with data sampling rate of {lfp_band_sampling_rate}" + ) + return None + + # create the analysis nwb file to store the results. + lfp_band_file_name = AnalysisNwbfile().create(key["nwb_file_name"]) + lfp_band_file_abspath = AnalysisNwbfile().get_abs_path(lfp_band_file_name) + # filter the data and write to an the nwb file + filtered_data, new_timestamps = FirFilterParameters().filter_data( + timestamps, + lfp_data, + filter_coeff, + lfp_band_valid_times, + lfp_band_elect_index, + decimation, + ) + + # now that the LFP is filtered, we create an electrical series for it and add it to the file + with pynwb.NWBHDF5IO( + path=lfp_band_file_abspath, mode="a", load_namespaces=True + ) as io: + nwbf = io.read() + # get the indices of the electrodes in the electrode table of the file to get the right values + elect_index = get_electrode_indices(nwbf, lfp_band_elect_id) + electrode_table_region = nwbf.create_electrode_table_region( + elect_index, "filtered electrode table" + ) + eseries_name = "filtered data" + # TODO: use datatype of data + es = pynwb.ecephys.ElectricalSeries( + name=eseries_name, + data=filtered_data, + electrodes=electrode_table_region, + timestamps=new_timestamps, + ) + lfp = pynwb.ecephys.LFP(electrical_series=es) + ecephys_module = nwbf.create_processing_module( + name="ecephys", description=f"LFP data processed with {filter_name}" + ) + ecephys_module.add(lfp) + io.write(nwbf) + filtered_data_object_id = es.object_id + # + # add the file to the AnalysisNwbfile table + AnalysisNwbfile().add(key["nwb_file_name"], lfp_band_file_name) + key["analysis_file_name"] = lfp_band_file_name + key["filtered_data_object_id"] = filtered_data_object_id + + # finally, we need to censor the valid times to account for the downsampling if this is the first time we've + # downsampled these data + key["interval_list_name"] = ( + interval_list_name + " lfp band " + str(lfp_band_sampling_rate) + "Hz" + ) + tmp_valid_times = ( + IntervalList + & { + "nwb_file_name": key["nwb_file_name"], + "interval_list_name": key["interval_list_name"], + } + ).fetch("valid_times") + if len(tmp_valid_times) == 0: + lfp_band_valid_times = interval_list_censor( + lfp_band_valid_times, new_timestamps + ) + # add an interval list for the LFP valid times + IntervalList.insert1( + { + "nwb_file_name": key["nwb_file_name"], + "interval_list_name": key["interval_list_name"], + "valid_times": lfp_band_valid_times, + } + ) + else: + # check that the valid times are the same + assert np.isclose( + tmp_valid_times[0], lfp_band_valid_times + ).all(), "previously saved lfp band times do not match current times" + + self.insert1(key) + + def fetch_nwb(self, *attrs, **kwargs): + return fetch_nwb( + self, (AnalysisNwbfile, "analysis_file_abs_path"), *attrs, **kwargs + ) + + def fetch1_dataframe(self, *attrs, **kwargs): + filtered_nwb = self.fetch_nwb()[0] + return pd.DataFrame( + filtered_nwb["filtered_data"].data, + index=pd.Index(filtered_nwb["filtered_data"].timestamps, name="time"), + ) + + def compute_analytic_signal(self, electrode_list, **kwargs): + """Computes the hilbert transform of a given LFPBand signal using scipy.signal.hilbert + + Parameters + ---------- + electrode_list: list + A list of the electrodes to compute the hilbert transform of + + Returns + ------- + analytic_signal_df: pd.DataFrame + DataFrame containing hilbert transform of signal + + Raises + ------ + ValueError + If any electrodes passed to electrode_list are invalid for the dataset + """ + + filtered_band = self.fetch_nwb()[0]["filtered_data"] + electrode_index = np.isin(filtered_band.electrodes.data[:], electrode_list) + if len(electrode_list) != np.sum(electrode_index): + raise ValueError( + "Some of the electrodes specified in electrode_list are missing in the current LFPBand table." + ) + analytic_signal_df = pd.DataFrame( + hilbert(filtered_band.data[:, electrode_index], axis=0), + index=pd.Index(filtered_band.timestamps, name="time"), + columns=[f"electrode {e}" for e in electrode_list], + ) + return analytic_signal_df + + def compute_signal_phase(self, electrode_list=[], **kwargs): + analytic_signal_df = self.compute_analytic_signal(electrode_list, **kwargs) + return pd.DataFrame( + np.angle(analytic_signal_df) + np.pi, + columns=analytic_signal_df.columns, + index=analytic_signal_df.index, + ) + + def compute_signal_power(self, electrode_list=[], **kwargs): + analytic_signal_df = self.compute_analytic_signal(electrode_list, **kwargs) + return pd.DataFrame( + np.abs(analytic_signal_df) ** 2, + columns=analytic_signal_df.columns, + index=analytic_signal_df.index, + ) diff --git a/src/spyglass/lfp/v1/lfp.py b/src/spyglass/lfp/v1/lfp.py index f1bacc348..1c0f9a48a 100644 --- a/src/spyglass/lfp/v1/lfp.py +++ b/src/spyglass/lfp/v1/lfp.py @@ -1,80 +1,26 @@ import uuid -import warnings -from functools import reduce -from typing import Union +import copy import datajoint as dj import numpy as np import pandas as pd -import pynwb -from scipy.signal import hilbert from spyglass.common.common_ephys import Electrode, Raw from spyglass.common.common_filter import FirFilterParameters -from spyglass.common.common_interval import interval_list_censor # noqa: F401 from spyglass.common.common_interval import ( IntervalList, - _union_concat, - interval_from_inds, - interval_list_contains_ind, + interval_list_censor, interval_list_intersect, ) from spyglass.common.common_nwbfile import AnalysisNwbfile from spyglass.common.common_session import Session # noqa: F401 from spyglass.utils.dj_helper_fn import fetch_nwb # dj_replace -from spyglass.utils.nwb_helper_fn import get_electrode_indices, get_valid_intervals schema = dj.schema("lfp_v1") MIN_LFP_INTERVAL_DURATION = 1.0 # 1 second minimum interval duration -@schema -class LFPElectrodeGroup(dj.Manual): - definition = """ - -> Session - lfp_electrode_group_name: varchar(200) - """ - - class LFPElectrode(dj.Part): - definition = """ - -> LFPElectrodeGroup - -> Electrode - """ - - @staticmethod - def create_lfp_electrode_group(nwb_file_name, group_name, electrode_list): - """Adds an LFPElectrodeGroup and the individual electrodes - - Parameters - ---------- - nwb_file_name : str - The name of the nwb file (e.g. the session) - group_name : str - The name of this group (< 200 char) - electrode_list : list - A list of the electrode ids to include in this group. - """ - # remove the session and then recreate the session and Electrode list - # check to see if the user allowed the deletion - key = {"nwb_file_name": nwb_file_name, "lfp_electrode_group_name": group_name} - LFPElectrodeGroup().insert1(key, skip_duplicates=True) - - # TODO: do this in a better way - all_electrodes = (Electrode() & {"nwb_file_name": nwb_file_name}).fetch( - as_dict=True - ) - primary_key = Electrode.primary_key - for e in all_electrodes: - # create a dictionary so we can insert the electrodes - if e["electrode_id"] in electrode_list: - lfpelectdict = {k: v for k, v in e.items() if k in primary_key} - lfpelectdict["lfp_electrode_group_name"] = group_name - LFPElectrodeGroup().LFPElectrode.insert1( - lfpelectdict, skip_duplicates=True - ) - - @schema class LFPSelection(dj.Manual): definition = """ @@ -96,8 +42,6 @@ class LFPV1(dj.Computed): """ def make(self, key): - from spyglass.lfp.lfp_merge import LFPOutput - # get the NWB object with the data nwbf_key = {"nwb_file_name": key["nwb_file_name"]} rawdata = (Raw & nwbf_key).fetch_nwb()[0]["raw"] @@ -108,7 +52,7 @@ def make(self, key): # to get the list of valid times, we need to combine those from the user with those from the # raw data - orig_key = key.copy() + orig_key = copy.deepcopy(key) orig_key["interval_list_name"] = key["target_interval_list_name"] user_valid_times = (IntervalList() & orig_key).fetch1("valid_times") # we remove the extra entry so we can insert this into the LFPOutput table. @@ -136,13 +80,13 @@ def make(self, key): FirFilterParameters() & {"filter_name": key["filter_name"]} & {"filter_sampling_rate": sampling_rate} - ).fetch(as_dict=True) + ).fetch1(as_dict=True) # there should only be one filter that matches, so we take the first of the dictionaries - key["filter_name"] = filter[0]["filter_name"] - key["filter_sampling_rate"] = filter[0]["filter_sampling_rate"] + key["filter_name"] = filter["filter_name"] + key["filter_sampling_rate"] = filter["filter_sampling_rate"] - filter_coeff = filter[0]["filter_coeff"] + filter_coeff = filter["filter_coeff"] if len(filter_coeff) == 0: print( f"Error in LFP: no filter found with data sampling rate of {sampling_rate}" @@ -174,6 +118,7 @@ def make(self, key): # finally, we need to censor the valid times to account for the downsampling lfp_valid_times = interval_list_censor(valid_times, timestamp_interval) + # add an interval list for the LFP valid times, skipping duplicates key["interval_list_name"] = "_".join( ( @@ -191,7 +136,10 @@ def make(self, key): replace=True, ) self.insert1(key) + # finally, we insert this into the LFP output table. + from spyglass.lfp.lfp_merge import LFPOutput + lfp_id = uuid.uuid1() lfp_o_key = {"lfp_id": lfp_id} LFPOutput.insert1(lfp_o_key) @@ -223,736 +171,47 @@ class ImportedLFPV1(dj.Imported): """ -# add artifact detection @schema -class LFPArtifactDetectionParameters(dj.Manual): - definition = """ - # Parameters for detecting LFP artifact times within a LFP group. - artifact_params_name: varchar(200) - --- - artifact_params: blob # dictionary of parameters - """ - - def insert_default(self): - """Insert the default artifact parameters with an appropriate parameter dict.""" - artifact_params = {} - # all electrodes of sort group - artifact_params["amplitude_thresh_1st"] = 500 # must be None or >= 0 - artifact_params["proportion_above_thresh_1st"] = 0.1 - artifact_params["amplitude_thresh_2nd"] = 1000 # must be None or >= 0 - artifact_params["proportion_above_thresh_1st"] = 0.05 - artifact_params["removal_window_ms"] = 10.0 # in milliseconds - artifact_params["local_window_ms"] = 40.0 # in milliseconds - self.insert1(["default", artifact_params], skip_duplicates=True) - - artifact_params_none = {} - artifact_params["amplitude_thresh_1st"] = None - artifact_params["proportion_above_thresh_1st"] = None - artifact_params["amplitude_thresh_2nd"] = None - artifact_params["proportion_above_thresh_1st"] = None - artifact_params["removal_window_ms"] = None - artifact_params["local_window_ms"] = None - self.insert1(["none", artifact_params_none], skip_duplicates=True) - - -@schema -class LFPArtifactDetectionSelection(dj.Manual): - definition = """ - # Specifies artifact detection parameters to apply to a sort group's recording. - -> LFP - -> LFPArtifactDetectionParameters - --- - custom_artifact_detection=0 : tinyint - """ - - -@schema -class LFPArtifactDetection(dj.Computed): - definition = """ - # Stores artifact times and valid no-artifact times as intervals. - -> LFPArtifactDetectionSelection - --- - artifact_times: longblob # np array of artifact intervals - artifact_removed_valid_times: longblob # np array of valid no-artifact intervals - artifact_removed_interval_list_name: varchar(200) # name of the array of no-artifact valid time intervals - """ - - def make(self, key): - if not (LFPArtifactDetectionSelection & key).fetch1( - "custom_artifact_detection" - ): - # get the dict of artifact params associated with this artifact_params_name - artifact_params = (LFPArtifactDetectionParameters & key).fetch1( - "artifact_params" - ) - - # get LFP data - lfp_eseries = (LFPV1() & key).fetch_nwb()[0]["lfp"] - - artifact_removed_valid_times, artifact_times = _get_artifact_times( - lfp_eseries, - key, - **artifact_params, - ) - - key["artifact_times"] = artifact_times - key["artifact_removed_valid_times"] = artifact_removed_valid_times - - # set up a name for no-artifact times using recording id - # we need some name here for recording_name - key["artifact_removed_interval_list_name"] = ( - key["nwb_file_name"] - + "_" - + key["target_interval_list_name"] - + "_LFP_" - + key["artifact_params_name"] - + "_artifact_removed_valid_times" - ) - - LFPArtifactRemovedIntervalList.insert1(key, replace=True) - - # also insert into IntervalList - tmp_key = {} - tmp_key["nwb_file_name"] = key["nwb_file_name"] - tmp_key["interval_list_name"] = key["artifact_removed_interval_list_name"] - tmp_key["valid_times"] = key["artifact_removed_valid_times"] - IntervalList.insert1(tmp_key, replace=True) - - # insert into computed table - self.insert1(key) - - -@schema -class LFPArtifactRemovedIntervalList(dj.Manual): - definition = """ - # Stores intervals without detected artifacts. - # Note that entries can come from either ArtifactDetection() or alternative artifact removal analyses. - artifact_removed_interval_list_name: varchar(200) - --- - -> LFPArtifactDetectionSelection - artifact_removed_valid_times: longblob - artifact_times: longblob # np array of artifact intervals - """ - - -def _get_artifact_times( - recording: None, - key: None, - amplitude_thresh_1st: Union[float, None] = None, - amplitude_thresh_2nd: Union[float, None] = None, - proportion_above_thresh_1st: float = 1.0, - proportion_above_thresh_2nd: float = 1.0, - removal_window_ms: float = 1.0, - local_window_ms: float = 1.0, - # verbose: bool = False, - # **job_kwargs, -): - """Detects times during which artifacts do and do not occur. - Artifacts are defined as periods where the absolute value of the change in LFP exceeds - amplitude change thresholds on the proportion of channels specified, - with the period extended by the removal_window_ms/2 on each side. amplitude change - threshold values of None are ignored. - - Parameters - ---------- - recording : lfp eseries - zscore_thresh : float, optional - Stdev threshold for exclusion, should be >=0, defaults to None - amplitude_thresh : float, optional - Amplitude (ad units) threshold for exclusion, should be >=0, defaults to None - proportion_above_thresh : float, optional, should be>0 and <=1 - Proportion of electrodes that need to have threshold crossings, defaults to 1 - removal_window_ms : float, optional - Width of the window in milliseconds to mask out per artifact - (window/2 removed on each side of threshold crossing), defaults to 1 ms - - Returns - ------- - artifact_removed_valid_times : np.ndarray - Intervals of valid times where artifacts were not detected, unit: seconds - artifact_intervals : np.ndarray - Intervals in which artifacts are detected (including removal windows), unit: seconds - """ - - valid_timestamps = recording.timestamps - - local_window = np.int(local_window_ms / 2) - - # if both thresholds are None, we skip artifact detection - if amplitude_thresh_1st is None: - recording_interval = np.asarray([valid_timestamps[0], valid_timestamps[-1]]) - artifact_times_empty = np.asarray([]) - print("Amplitude threshold is None, skipping artifact detection") - return recording_interval, artifact_times_empty - - # verify threshold parameters - ( - amplitude_thresh_1st, - amplitude_thresh_2nd, - proportion_above_thresh_1st, - proportion_above_thresh_2nd, - ) = _check_artifact_thresholds( - amplitude_thresh_1st, - amplitude_thresh_2nd, - proportion_above_thresh_1st, - proportion_above_thresh_2nd, - ) - - # want to detect frames without parallel processing - # compute the number of electrodes that have to be above threshold - nelect_above_1st = np.ceil(proportion_above_thresh_1st * recording.data.shape[1]) - nelect_above_2nd = np.ceil(proportion_above_thresh_2nd * recording.data.shape[1]) - - # find the artifact occurrences using one or both thresholds, across channels - # replace with LFP artifact code - # is this supposed to be indices?? - if amplitude_thresh_1st is not None: - # first find times with large amp change - artifact_boolean = np.sum( - (np.abs(np.diff(recording.data, axis=0)) > amplitude_thresh_1st), axis=1 - ) - above_thresh_1st = np.where(artifact_boolean >= nelect_above_1st)[0] - - # second, find artifacts with large baseline change - big_artifacts = np.zeros((recording.data.shape[1], above_thresh_1st.shape[0])) - for art_count in np.arange(above_thresh_1st.shape[0]): - if above_thresh_1st[art_count] <= local_window: - local_min = local_max = above_thresh_1st[art_count] - else: - local_max = np.max( - recording.data[ - above_thresh_1st[art_count] - - local_window : above_thresh_1st[art_count] - + local_window, - :, - ], - axis=0, - ) - local_min = np.min( - recording.data[ - above_thresh_1st[art_count] - - local_window : above_thresh_1st[art_count] - + local_window, - :, - ], - axis=0, - ) - big_artifacts[:, art_count] = ( - np.abs(local_max - local_min) > amplitude_thresh_2nd - ) - - # sum columns in big artficat, then compare to nelect_above_2nd - above_thresh = above_thresh_1st[ - np.sum(big_artifacts, axis=0) >= nelect_above_2nd - ] - - # artifact_frames = executor.run() - artifact_frames = above_thresh.copy() - print("detected ", artifact_frames.shape[0], " artifacts") - - # turn ms to remove total into s to remove from either side of each detected artifact - half_removal_window_s = removal_window_ms / 1000 * 0.5 - - if len(artifact_frames) == 0: - recording_interval = np.asarray([[valid_timestamps[0], valid_timestamps[-1]]]) - artifact_times_empty = np.asarray([]) - print("No artifacts detected.") - return recording_interval, artifact_times_empty - - artifact_intervals = interval_from_inds(artifact_frames) - - artifact_intervals_s = np.zeros((len(artifact_intervals), 2), dtype=np.float64) - for interval_idx, interval in enumerate(artifact_intervals): - artifact_intervals_s[interval_idx] = [ - valid_timestamps[interval[0]] - half_removal_window_s, - valid_timestamps[interval[1]] + half_removal_window_s, - ] - artifact_intervals_s = reduce(_union_concat, artifact_intervals_s) - - # im not sure how to get the key in this function - sampling_frequency = (LFPV1() & key).fetch("lfp_sampling_rate")[0] - - valid_intervals = get_valid_intervals( - valid_timestamps, sampling_frequency, 1.5, 0.000001 - ) - - # these are artifact times - need to subtract these from valid timestamps - artifact_valid_times = interval_list_intersect( - valid_intervals, artifact_intervals_s - ) - - # note: this is a slow step - list_triggers = [] - for interval in artifact_valid_times: - list_triggers.append( - np.arange( - np.searchsorted(valid_timestamps, interval[0]), - np.searchsorted(valid_timestamps, interval[1]), - ) - ) - - new_array = np.array(np.concatenate(list_triggers)) - - new_timestamps = np.delete(valid_timestamps, new_array) - - artifact_removed_valid_times = get_valid_intervals( - new_timestamps, sampling_frequency, 1.5, 0.000001 - ) - - return artifact_removed_valid_times, artifact_intervals_s - - -def _check_artifact_thresholds( - amplitude_thresh_1st, - amplitude_thresh_2nd, - proportion_above_thresh_1st, - proportion_above_thresh_2nd, -): - """Alerts user to likely unintended parameters. Not an exhaustive verification. - - Parameters - ---------- - amplitude_thresh_1st: float - amplitude_thresh_2nd: float - proportion_above_thresh_1st: float - proportion_above_thresh_2nd: float - - Return - ------ - amplitude_thresh_1st: float - amplitude_thresh_2nd: float - proportion_above_thresh_1st: float - proportion_above_thresh_2nd: float - - Raise - ------ - ValueError: if signal thresholds are negative - """ - # amplitude or zscore thresholds should be not negative, as they are applied to an absolute signal - signal_thresholds = [ - t for t in [amplitude_thresh_1st, amplitude_thresh_1st] if t is not None - ] - for t in signal_thresholds: - if t < 0: - raise ValueError("Amplitude thresholds must be >= 0, or None") - - # proportion_above_threshold should be in [0:1] inclusive - if proportion_above_thresh_1st < 0: - warnings.warn( - "Warning: proportion_above_thresh must be a proportion >0 and <=1." - f" Using proportion_above_thresh = 0.01 instead of {str(proportion_above_thresh_1st)}" - ) - proportion_above_thresh_1st = 0.01 - elif proportion_above_thresh_1st > 1: - warnings.warn( - "Warning: proportion_above_thresh must be a proportion >0 and <=1. " - f"Using proportion_above_thresh = 1 instead of {str(proportion_above_thresh_1st)}" - ) - proportion_above_thresh_1st = 1 - # proportion_above_threshold should be in [0:1] inclusive - if proportion_above_thresh_2nd < 0: - warnings.warn( - "Warning: proportion_above_thresh must be a proportion >0 and <=1." - f" Using proportion_above_thresh = 0.01 instead of {str(proportion_above_thresh_2nd)}" - ) - proportion_above_thresh_2nd = 0.01 - elif proportion_above_thresh_2nd > 1: - warnings.warn( - "Warning: proportion_above_thresh must be a proportion >0 and <=1. " - f"Using proportion_above_thresh = 1 instead of {str(proportion_above_thresh_2nd)}" - ) - proportion_above_thresh_2nd = 1 - - return ( - amplitude_thresh_1st, - amplitude_thresh_2nd, - proportion_above_thresh_1st, - proportion_above_thresh_2nd, - ) - - -@schema -class LFPBandSelection(dj.Manual): +class LFPElectrodeGroup(dj.Manual): definition = """ - -> LFPOutput - -> FirFilterParameters # the filter to use for the data - -> IntervalList.proj(target_interval_list_name='interval_list_name') # the original set of times to be filtered - lfp_band_sampling_rate: int # the sampling rate for this band - --- - min_interval_len = 1.0: float # the minimum length of a valid interval to filter - """ + -> Session + lfp_electrode_group_name: varchar(200) + """ - class LFPBandElectrode(dj.Part): + class LFPElectrode(dj.Part): definition = """ - -> LFPBandSelection - -> LFPElectrodeGroup.LFPElectrode # the LFP electrode to be filtered - reference_elect_id = -1: int # the reference electrode to use; -1 for no reference - --- - """ - - def set_lfp_band_electrodes( - self, - nwb_file_name, - lfp_id, - electrode_list, - filter_name, - interval_list_name, - reference_electrode_list, - lfp_band_sampling_rate, - ): - # TODO: fix docstring to match normal format. - """ - Adds an entry for each electrode in the electrode_list with the specified filter, interval_list, and - reference electrode. - :param nwb_file_name: string - the name of the nwb file for the desired session - :param lfp_id: uuid - the uuid for the LFPOutput to use - :param electrode_list: list of LFP electrodes (electrode ids) to be filtered - :param filter_name: the name of the filter (from the FirFilterParameters schema) - :param interval_name: the name of the interval list (from the IntervalList schema) - :param reference_electrode_list: A single electrode id corresponding to the reference to use for all - electrodes or a list with one element per entry in the electrode_list - :param lfp_band_sampling_rate: The output sampling rate to be used for the filtered data; must be an - integer divisor of the LFP sampling rate - :return: none + -> LFPElectrodeGroup + -> Electrode """ - # Error checks on parameters - # electrode_list - from spyglass.lfp.lfp_merge import LFPOutput - - lfp_object = LFPOutput.get_lfp_object({"lfp_id": lfp_id}) - print(lfp_object) - lfp_key = lfp_object.fetch1("KEY") - query = LFPElectrodeGroup().LFPElectrode() & lfp_key - available_electrodes = query.fetch("electrode_id") - if not np.all(np.isin(electrode_list, available_electrodes)): - raise ValueError( - "All elements in electrode_list must be valid electrode_ids in the LFPElectodeGroup table" - ) - # sampling rate - print(lfp_object) - lfp_sampling_rate = (lfp_object & lfp_key).fetch1("lfp_sampling_rate") - decimation = lfp_sampling_rate // lfp_band_sampling_rate - if lfp_sampling_rate // decimation != lfp_band_sampling_rate: - raise ValueError( - f"lfp_band_sampling rate {lfp_band_sampling_rate} is not an integer divisor of lfp " - f"samping rate {lfp_sampling_rate}" - ) - # filter - query = FirFilterParameters() & { - "filter_name": filter_name, - "filter_sampling_rate": lfp_sampling_rate, - } - if not query: - raise ValueError( - f"filter {filter_name}, sampling rate {lfp_sampling_rate} is not in the FirFilterParameters table" - ) - # interval_list - query = IntervalList() & { - "nwb_file_name": nwb_file_name, - "interval_name": interval_list_name, - } - if not query: - raise ValueError( - f"interval list {interval_list_name} is not in the IntervalList table; the list must be " - "added before this function is called" - ) - # reference_electrode_list - if len(reference_electrode_list) != 1 and len(reference_electrode_list) != len( - electrode_list - ): - raise ValueError( - "reference_electrode_list must contain either 1 or len(electrode_list) elements" - ) - # add a -1 element to the list to allow for the no reference option - available_electrodes = np.append(available_electrodes, [-1]) - if not np.all(np.isin(reference_electrode_list, available_electrodes)): - raise ValueError( - "All elements in reference_electrode_list must be valid electrode_ids in the LFPSelection " - "table" - ) - - # make a list of all the references - ref_list = np.zeros((len(electrode_list),)) - ref_list[:] = reference_electrode_list - - key = dict() - key["nwb_file_name"] = nwb_file_name - key["lfp_id"] = lfp_id - key["filter_name"] = filter_name - key["filter_sampling_rate"] = lfp_sampling_rate - key["target_interval_list_name"] = interval_list_name - key["lfp_band_sampling_rate"] = lfp_sampling_rate // decimation - # insert an entry into the main LFPBandSelectionTable - self.insert1(key, skip_duplicates=True) - - key["lfp_electrode_group_name"] = lfp_object.fetch1("lfp_electrode_group_name") - # iterate through all of the new elements and add them - for e, r in zip(electrode_list, ref_list): - elect_key = ( - LFPElectrodeGroup.LFPElectrode - & { - "nwb_file_name": nwb_file_name, - "lfp_electrode_group_name": key["lfp_electrode_group_name"], - "electrode_id": e, - } - ).fetch1("KEY") - for item in elect_key: - key[item] = elect_key[item] - query = Electrode & {"nwb_file_name": nwb_file_name, "electrode_id": e} - key["reference_elect_id"] = r - self.LFPBandElectrode().insert1(key, skip_duplicates=True) - - -@schema -class LFPBand(dj.Computed): - definition = """ - -> LFPBandSelection - --- - -> AnalysisNwbfile - -> IntervalList - filtered_data_object_id: varchar(40) # the NWB object ID for loading this object from the file - """ - - def make(self, key): - from spyglass.lfp.lfp_merge import LFPOutput - - # get the NWB object with the lfp data; FIX: change to fetch with additional infrastructure - lfp_object = (LFPV1() & {"nwb_file_name": key["nwb_file_name"]}).fetch_nwb()[0][ - "lfp" - ] - - # get the electrodes to be filtered and their references - lfp_band_elect_id, lfp_band_ref_id = ( - LFPBandSelection().LFPBandElectrode() & key - ).fetch("electrode_id", "reference_elect_id") - - # sort the electrodes to make sure they are in ascending order - lfp_band_elect_id = np.asarray(lfp_band_elect_id) - lfp_band_ref_id = np.asarray(lfp_band_ref_id) - lfp_sort_order = np.argsort(lfp_band_elect_id) - lfp_band_elect_id = lfp_band_elect_id[lfp_sort_order] - lfp_band_ref_id = lfp_band_ref_id[lfp_sort_order] - - lfp_sampling_rate = ( - LFPOutput() - .get_lfp_object({"lfp_id": key["lfp_id"]}) - .fetch1("lfp_sampling_rate") - ) - interval_list_name, lfp_band_sampling_rate = (LFPBandSelection() & key).fetch1( - "target_interval_list_name", "lfp_band_sampling_rate" - ) - valid_times = ( - IntervalList() - & { - "nwb_file_name": key["nwb_file_name"], - "interval_list_name": interval_list_name, - } - ).fetch1("valid_times") - # the valid_times for this interval may be slightly beyond the valid times for the lfp itself, - # so we have to intersect the two - lfp_interval_list = ( - LFPOutput() - .get_lfp_object({"lfp_id": key["lfp_id"]}) - .fetch1("interval_list_name") - ) - lfp_valid_times = ( - IntervalList() - & { - "nwb_file_name": key["nwb_file_name"], - "interval_list_name": lfp_interval_list, - } - ).fetch1("valid_times") - min_length = (LFPBandSelection & key).fetch1("min_interval_len") - lfp_band_valid_times = interval_list_intersect( - valid_times, lfp_valid_times, min_length=min_length - ) - - filter_name, filter_sampling_rate, lfp_band_sampling_rate = ( - LFPBandSelection() & key - ).fetch1("filter_name", "filter_sampling_rate", "lfp_band_sampling_rate") - - decimation = int(lfp_sampling_rate) // lfp_band_sampling_rate - - # load in the timestamps - timestamps = np.asarray(lfp_object.timestamps) - # get the indices of the first timestamp and the last timestamp that are within the valid times - included_indices = interval_list_contains_ind(lfp_band_valid_times, timestamps) - # pad the indices by 1 on each side to avoid message in filter_data - if included_indices[0] > 0: - included_indices[0] -= 1 - if included_indices[-1] != len(timestamps) - 1: - included_indices[-1] += 1 - - timestamps = timestamps[included_indices[0] : included_indices[-1]] - - # load all the data to speed filtering - lfp_data = np.asarray( - lfp_object.data[included_indices[0] : included_indices[-1], :], - dtype=type(lfp_object.data[0][0]), - ) - - # get the indices of the electrodes to be filtered and the references - lfp_band_elect_index = get_electrode_indices(lfp_object, lfp_band_elect_id) - lfp_band_ref_index = get_electrode_indices(lfp_object, lfp_band_ref_id) - - # subtract off the references for the selected channels - for index, elect_index in enumerate(lfp_band_elect_index): - if lfp_band_ref_id[index] != -1: - lfp_data[:, elect_index] = ( - lfp_data[:, elect_index] - lfp_data[:, lfp_band_ref_index[index]] - ) - - # get the LFP filter that matches the raw data - filter = ( - FirFilterParameters() - & {"filter_name": filter_name} - & {"filter_sampling_rate": filter_sampling_rate} - ).fetch(as_dict=True) - if len(filter) == 0: - raise ValueError( - f"Filter {filter_name} and sampling_rate {lfp_band_sampling_rate} does not exit in the " - "FirFilterParameters table" - ) - - filter_coeff = filter[0]["filter_coeff"] - if len(filter_coeff) == 0: - print( - f"Error in LFPBand: no filter found with data sampling rate of {lfp_band_sampling_rate}" - ) - return None - - # create the analysis nwb file to store the results. - lfp_band_file_name = AnalysisNwbfile().create(key["nwb_file_name"]) - lfp_band_file_abspath = AnalysisNwbfile().get_abs_path(lfp_band_file_name) - # filter the data and write to an the nwb file - filtered_data, new_timestamps = FirFilterParameters().filter_data( - timestamps, - lfp_data, - filter_coeff, - lfp_band_valid_times, - lfp_band_elect_index, - decimation, - ) - - # now that the LFP is filtered, we create an electrical series for it and add it to the file - with pynwb.NWBHDF5IO( - path=lfp_band_file_abspath, mode="a", load_namespaces=True - ) as io: - nwbf = io.read() - # get the indices of the electrodes in the electrode table of the file to get the right values - elect_index = get_electrode_indices(nwbf, lfp_band_elect_id) - electrode_table_region = nwbf.create_electrode_table_region( - elect_index, "filtered electrode table" - ) - eseries_name = "filtered data" - # TODO: use datatype of data - es = pynwb.ecephys.ElectricalSeries( - name=eseries_name, - data=filtered_data, - electrodes=electrode_table_region, - timestamps=new_timestamps, - ) - lfp = pynwb.ecephys.LFP(electrical_series=es) - ecephys_module = nwbf.create_processing_module( - name="ecephys", description=f"LFP data processed with {filter_name}" - ) - ecephys_module.add(lfp) - io.write(nwbf) - filtered_data_object_id = es.object_id - # - # add the file to the AnalysisNwbfile table - AnalysisNwbfile().add(key["nwb_file_name"], lfp_band_file_name) - key["analysis_file_name"] = lfp_band_file_name - key["filtered_data_object_id"] = filtered_data_object_id - - # finally, we need to censor the valid times to account for the downsampling if this is the first time we've - # downsampled these data - key["interval_list_name"] = ( - interval_list_name + " lfp band " + str(lfp_band_sampling_rate) + "Hz" - ) - tmp_valid_times = ( - IntervalList - & { - "nwb_file_name": key["nwb_file_name"], - "interval_list_name": key["interval_list_name"], - } - ).fetch("valid_times") - if len(tmp_valid_times) == 0: - lfp_band_valid_times = interval_list_censor( - lfp_band_valid_times, new_timestamps - ) - # add an interval list for the LFP valid times - IntervalList.insert1( - { - "nwb_file_name": key["nwb_file_name"], - "interval_list_name": key["interval_list_name"], - "valid_times": lfp_band_valid_times, - } - ) - else: - # check that the valid times are the same - assert np.isclose( - tmp_valid_times[0], lfp_band_valid_times - ).all(), "previously saved lfp band times do not match current times" - - self.insert1(key) - - def fetch_nwb(self, *attrs, **kwargs): - return fetch_nwb( - self, (AnalysisNwbfile, "analysis_file_abs_path"), *attrs, **kwargs - ) - def fetch1_dataframe(self, *attrs, **kwargs): - filtered_nwb = self.fetch_nwb()[0] - return pd.DataFrame( - filtered_nwb["filtered_data"].data, - index=pd.Index(filtered_nwb["filtered_data"].timestamps, name="time"), - ) - - def compute_analytic_signal(self, electrode_list, **kwargs): - """Computes the hilbert transform of a given LFPBand signal using scipy.signal.hilbert + @staticmethod + def create_lfp_electrode_group(nwb_file_name, group_name, electrode_list): + """Adds an LFPElectrodeGroup and the individual electrodes Parameters ---------- - electrode_list: list - A list of the electrodes to compute the hilbert transform of - - Returns - ------- - analytic_signal_df: pd.DataFrame - DataFrame containing hilbert transform of signal - - Raises - ------ - ValueError - If any electrodes passed to electrode_list are invalid for the dataset + nwb_file_name : str + The name of the nwb file (e.g. the session) + group_name : str + The name of this group (< 200 char) + electrode_list : list + A list of the electrode ids to include in this group. """ + # remove the session and then recreate the session and Electrode list + # check to see if the user allowed the deletion + key = {"nwb_file_name": nwb_file_name, "lfp_electrode_group_name": group_name} + LFPElectrodeGroup().insert1(key, skip_duplicates=True) - filtered_band = self.fetch_nwb()[0]["filtered_data"] - electrode_index = np.isin(filtered_band.electrodes.data[:], electrode_list) - if len(electrode_list) != np.sum(electrode_index): - raise ValueError( - "Some of the electrodes specified in electrode_list are missing in the current LFPBand table." - ) - analytic_signal_df = pd.DataFrame( - hilbert(filtered_band.data[:, electrode_index], axis=0), - index=pd.Index(filtered_band.timestamps, name="time"), - columns=[f"electrode {e}" for e in electrode_list], - ) - return analytic_signal_df - - def compute_signal_phase(self, electrode_list=[], **kwargs): - analytic_signal_df = self.compute_analytic_signal(electrode_list, **kwargs) - return pd.DataFrame( - np.angle(analytic_signal_df) + np.pi, - columns=analytic_signal_df.columns, - index=analytic_signal_df.index, - ) - - def compute_signal_power(self, electrode_list=[], **kwargs): - analytic_signal_df = self.compute_analytic_signal(electrode_list, **kwargs) - return pd.DataFrame( - np.abs(analytic_signal_df) ** 2, - columns=analytic_signal_df.columns, - index=analytic_signal_df.index, + # TODO: do this in a better way + all_electrodes = (Electrode() & {"nwb_file_name": nwb_file_name}).fetch( + as_dict=True ) + primary_key = Electrode.primary_key + for e in all_electrodes: + # create a dictionary so we can insert the electrodes + if e["electrode_id"] in electrode_list: + lfpelectdict = {k: v for k, v in e.items() if k in primary_key} + lfpelectdict["lfp_electrode_group_name"] = group_name + LFPElectrodeGroup().LFPElectrode.insert1( + lfpelectdict, skip_duplicates=True + ) diff --git a/src/spyglass/lfp/v1/lfp_artifact.py b/src/spyglass/lfp/v1/lfp_artifact.py new file mode 100644 index 000000000..d5d49216b --- /dev/null +++ b/src/spyglass/lfp/v1/lfp_artifact.py @@ -0,0 +1,366 @@ +import warnings +from functools import reduce +from typing import Union + +import datajoint as dj +import numpy as np + +from spyglass.common.common_interval import ( + IntervalList, + _union_concat, + interval_from_inds, + interval_list_intersect, +) +from spyglass.utils.nwb_helper_fn import get_valid_intervals +from spyglass.lfp.v1.lfp import LFPV1 + +schema = dj.schema("lfp_v1") + +MIN_LFP_INTERVAL_DURATION = 1.0 # 1 second minimum interval duration + + +@schema +class LFPArtifactDetectionParameters(dj.Manual): + definition = """ + # Parameters for detecting LFP artifact times within a LFP group. + artifact_params_name: varchar(200) + --- + artifact_params: blob # dictionary of parameters + """ + + def insert_default(self): + """Insert the default artifact parameters with an appropriate parameter dict.""" + artifact_params = {} + # all electrodes of sort group + artifact_params["amplitude_thresh_1st"] = 500 # must be None or >= 0 + artifact_params["proportion_above_thresh_1st"] = 0.1 + artifact_params["amplitude_thresh_2nd"] = 1000 # must be None or >= 0 + artifact_params["proportion_above_thresh_1st"] = 0.05 + artifact_params["removal_window_ms"] = 10.0 # in milliseconds + artifact_params["local_window_ms"] = 40.0 # in milliseconds + self.insert1(["default", artifact_params], skip_duplicates=True) + + artifact_params_none = {} + artifact_params["amplitude_thresh_1st"] = None + artifact_params["proportion_above_thresh_1st"] = None + artifact_params["amplitude_thresh_2nd"] = None + artifact_params["proportion_above_thresh_1st"] = None + artifact_params["removal_window_ms"] = None + artifact_params["local_window_ms"] = None + self.insert1(["none", artifact_params_none], skip_duplicates=True) + + +@schema +class LFPArtifactDetectionSelection(dj.Manual): + definition = """ + # Specifies artifact detection parameters to apply to a sort group's recording. + -> LFP + -> LFPArtifactDetectionParameters + --- + custom_artifact_detection=0 : tinyint + """ + + +@schema +class LFPArtifactDetection(dj.Computed): + definition = """ + # Stores artifact times and valid no-artifact times as intervals. + -> LFPArtifactDetectionSelection + --- + artifact_times: longblob # np array of artifact intervals + artifact_removed_valid_times: longblob # np array of valid no-artifact intervals + artifact_removed_interval_list_name: varchar(200) # name of the array of no-artifact valid time intervals + """ + + def make(self, key): + if not (LFPArtifactDetectionSelection & key).fetch1( + "custom_artifact_detection" + ): + # get the dict of artifact params associated with this artifact_params_name + artifact_params = (LFPArtifactDetectionParameters & key).fetch1( + "artifact_params" + ) + + # get LFP data + lfp_eseries = (LFPV1() & key).fetch_nwb()[0]["lfp"] + + artifact_removed_valid_times, artifact_times = _get_artifact_times( + lfp_eseries, + key, + **artifact_params, + ) + + key["artifact_times"] = artifact_times + key["artifact_removed_valid_times"] = artifact_removed_valid_times + + # set up a name for no-artifact times using recording id + # we need some name here for recording_name + key["artifact_removed_interval_list_name"] = ( + key["nwb_file_name"] + + "_" + + key["target_interval_list_name"] + + "_LFP_" + + key["artifact_params_name"] + + "_artifact_removed_valid_times" + ) + + LFPArtifactRemovedIntervalList.insert1(key, replace=True) + + # also insert into IntervalList + tmp_key = {} + tmp_key["nwb_file_name"] = key["nwb_file_name"] + tmp_key["interval_list_name"] = key["artifact_removed_interval_list_name"] + tmp_key["valid_times"] = key["artifact_removed_valid_times"] + IntervalList.insert1(tmp_key, replace=True) + + # insert into computed table + self.insert1(key) + + +@schema +class LFPArtifactRemovedIntervalList(dj.Manual): + definition = """ + # Stores intervals without detected artifacts. + # Note that entries can come from either ArtifactDetection() or alternative artifact removal analyses. + artifact_removed_interval_list_name: varchar(200) + --- + -> LFPArtifactDetectionSelection + artifact_removed_valid_times: longblob + artifact_times: longblob # np array of artifact intervals + """ + + +def _get_artifact_times( + recording: None, + key: None, + amplitude_thresh_1st: Union[float, None] = None, + amplitude_thresh_2nd: Union[float, None] = None, + proportion_above_thresh_1st: float = 1.0, + proportion_above_thresh_2nd: float = 1.0, + removal_window_ms: float = 1.0, + local_window_ms: float = 1.0, + # verbose: bool = False, + # **job_kwargs, +): + """Detects times during which artifacts do and do not occur. + Artifacts are defined as periods where the absolute value of the change in LFP exceeds + amplitude change thresholds on the proportion of channels specified, + with the period extended by the removal_window_ms/2 on each side. amplitude change + threshold values of None are ignored. + + Parameters + ---------- + recording : lfp eseries + zscore_thresh : float, optional + Stdev threshold for exclusion, should be >=0, defaults to None + amplitude_thresh : float, optional + Amplitude (ad units) threshold for exclusion, should be >=0, defaults to None + proportion_above_thresh : float, optional, should be>0 and <=1 + Proportion of electrodes that need to have threshold crossings, defaults to 1 + removal_window_ms : float, optional + Width of the window in milliseconds to mask out per artifact + (window/2 removed on each side of threshold crossing), defaults to 1 ms + + Returns + ------- + artifact_removed_valid_times : np.ndarray + Intervals of valid times where artifacts were not detected, unit: seconds + artifact_intervals : np.ndarray + Intervals in which artifacts are detected (including removal windows), unit: seconds + """ + + valid_timestamps = recording.timestamps + + local_window = np.int(local_window_ms / 2) + + # if both thresholds are None, we skip artifact detection + if amplitude_thresh_1st is None: + recording_interval = np.asarray([valid_timestamps[0], valid_timestamps[-1]]) + artifact_times_empty = np.asarray([]) + print("Amplitude threshold is None, skipping artifact detection") + return recording_interval, artifact_times_empty + + # verify threshold parameters + ( + amplitude_thresh_1st, + amplitude_thresh_2nd, + proportion_above_thresh_1st, + proportion_above_thresh_2nd, + ) = _check_artifact_thresholds( + amplitude_thresh_1st, + amplitude_thresh_2nd, + proportion_above_thresh_1st, + proportion_above_thresh_2nd, + ) + + # want to detect frames without parallel processing + # compute the number of electrodes that have to be above threshold + nelect_above_1st = np.ceil(proportion_above_thresh_1st * recording.data.shape[1]) + nelect_above_2nd = np.ceil(proportion_above_thresh_2nd * recording.data.shape[1]) + + # find the artifact occurrences using one or both thresholds, across channels + # replace with LFP artifact code + # is this supposed to be indices?? + if amplitude_thresh_1st is not None: + # first find times with large amp change + artifact_boolean = np.sum( + (np.abs(np.diff(recording.data, axis=0)) > amplitude_thresh_1st), axis=1 + ) + above_thresh_1st = np.where(artifact_boolean >= nelect_above_1st)[0] + + # second, find artifacts with large baseline change + big_artifacts = np.zeros((recording.data.shape[1], above_thresh_1st.shape[0])) + for art_count in np.arange(above_thresh_1st.shape[0]): + if above_thresh_1st[art_count] <= local_window: + local_min = local_max = above_thresh_1st[art_count] + else: + local_max = np.max( + recording.data[ + above_thresh_1st[art_count] + - local_window : above_thresh_1st[art_count] + + local_window, + :, + ], + axis=0, + ) + local_min = np.min( + recording.data[ + above_thresh_1st[art_count] + - local_window : above_thresh_1st[art_count] + + local_window, + :, + ], + axis=0, + ) + big_artifacts[:, art_count] = ( + np.abs(local_max - local_min) > amplitude_thresh_2nd + ) + + # sum columns in big artficat, then compare to nelect_above_2nd + above_thresh = above_thresh_1st[ + np.sum(big_artifacts, axis=0) >= nelect_above_2nd + ] + + # artifact_frames = executor.run() + artifact_frames = above_thresh.copy() + print("detected ", artifact_frames.shape[0], " artifacts") + + # turn ms to remove total into s to remove from either side of each detected artifact + half_removal_window_s = removal_window_ms / 1000 * 0.5 + + if len(artifact_frames) == 0: + recording_interval = np.asarray([[valid_timestamps[0], valid_timestamps[-1]]]) + artifact_times_empty = np.asarray([]) + print("No artifacts detected.") + return recording_interval, artifact_times_empty + + artifact_intervals = interval_from_inds(artifact_frames) + + artifact_intervals_s = np.zeros((len(artifact_intervals), 2), dtype=np.float64) + for interval_idx, interval in enumerate(artifact_intervals): + artifact_intervals_s[interval_idx] = [ + valid_timestamps[interval[0]] - half_removal_window_s, + valid_timestamps[interval[1]] + half_removal_window_s, + ] + artifact_intervals_s = reduce(_union_concat, artifact_intervals_s) + + # im not sure how to get the key in this function + sampling_frequency = (LFPV1() & key).fetch("lfp_sampling_rate")[0] + + valid_intervals = get_valid_intervals( + valid_timestamps, sampling_frequency, 1.5, 0.000001 + ) + + # these are artifact times - need to subtract these from valid timestamps + artifact_valid_times = interval_list_intersect( + valid_intervals, artifact_intervals_s + ) + + # note: this is a slow step + list_triggers = [] + for interval in artifact_valid_times: + list_triggers.append( + np.arange( + np.searchsorted(valid_timestamps, interval[0]), + np.searchsorted(valid_timestamps, interval[1]), + ) + ) + + new_array = np.array(np.concatenate(list_triggers)) + + new_timestamps = np.delete(valid_timestamps, new_array) + + artifact_removed_valid_times = get_valid_intervals( + new_timestamps, sampling_frequency, 1.5, 0.000001 + ) + + return artifact_removed_valid_times, artifact_intervals_s + + +def _check_artifact_thresholds( + amplitude_thresh_1st, + amplitude_thresh_2nd, + proportion_above_thresh_1st, + proportion_above_thresh_2nd, +): + """Alerts user to likely unintended parameters. Not an exhaustive verification. + + Parameters + ---------- + amplitude_thresh_1st: float + amplitude_thresh_2nd: float + proportion_above_thresh_1st: float + proportion_above_thresh_2nd: float + + Return + ------ + amplitude_thresh_1st: float + amplitude_thresh_2nd: float + proportion_above_thresh_1st: float + proportion_above_thresh_2nd: float + + Raise + ------ + ValueError: if signal thresholds are negative + """ + # amplitude or zscore thresholds should be not negative, as they are applied to an absolute signal + signal_thresholds = [ + t for t in [amplitude_thresh_1st, amplitude_thresh_1st] if t is not None + ] + for t in signal_thresholds: + if t < 0: + raise ValueError("Amplitude thresholds must be >= 0, or None") + + # proportion_above_threshold should be in [0:1] inclusive + if proportion_above_thresh_1st < 0: + warnings.warn( + "Warning: proportion_above_thresh must be a proportion >0 and <=1." + f" Using proportion_above_thresh = 0.01 instead of {str(proportion_above_thresh_1st)}" + ) + proportion_above_thresh_1st = 0.01 + elif proportion_above_thresh_1st > 1: + warnings.warn( + "Warning: proportion_above_thresh must be a proportion >0 and <=1. " + f"Using proportion_above_thresh = 1 instead of {str(proportion_above_thresh_1st)}" + ) + proportion_above_thresh_1st = 1 + # proportion_above_threshold should be in [0:1] inclusive + if proportion_above_thresh_2nd < 0: + warnings.warn( + "Warning: proportion_above_thresh must be a proportion >0 and <=1." + f" Using proportion_above_thresh = 0.01 instead of {str(proportion_above_thresh_2nd)}" + ) + proportion_above_thresh_2nd = 0.01 + elif proportion_above_thresh_2nd > 1: + warnings.warn( + "Warning: proportion_above_thresh must be a proportion >0 and <=1. " + f"Using proportion_above_thresh = 1 instead of {str(proportion_above_thresh_2nd)}" + ) + proportion_above_thresh_2nd = 1 + + return ( + amplitude_thresh_1st, + amplitude_thresh_2nd, + proportion_above_thresh_1st, + proportion_above_thresh_2nd, + ) From 493c2440fb9846a4847d2792662c66cf132c51f8 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Fri, 26 May 2023 11:55:48 -0700 Subject: [PATCH 013/131] Change schema name --- src/spyglass/lfp/lfp_merge.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spyglass/lfp/lfp_merge.py b/src/spyglass/lfp/lfp_merge.py index 42a05f9f3..4d5c2b727 100644 --- a/src/spyglass/lfp/lfp_merge.py +++ b/src/spyglass/lfp/lfp_merge.py @@ -5,7 +5,7 @@ from spyglass.lfp.v1.lfp import LFPV1, ImportedLFPV1 from spyglass.utils.dj_helper_fn import fetch_nwb -schema = dj.schema("lfp") +schema = dj.schema("lfp_merge") @schema From a4705513082cd05ea4f8342ab3641744854e136f Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Fri, 26 May 2023 12:06:22 -0700 Subject: [PATCH 014/131] Add V1 to table --- src/spyglass/lfp/lfp_merge.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spyglass/lfp/lfp_merge.py b/src/spyglass/lfp/lfp_merge.py index 4d5c2b727..d269b8e38 100644 --- a/src/spyglass/lfp/lfp_merge.py +++ b/src/spyglass/lfp/lfp_merge.py @@ -36,7 +36,7 @@ def fetch1_dataframe(self, *attrs, **kwargs): index=pd.Index(nwb_lfp["lfp"].timestamps, name="time"), ) - class ImportedLFP(dj.Part): + class ImportedLFPV1(dj.Part): definition = """ -> LFPOutput -> ImportedLFPV1 From 500dd39a27997a757cf3f9a21ac2bfa08a6d1a27 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Fri, 26 May 2023 12:06:33 -0700 Subject: [PATCH 015/131] Add object id as secondary key --- src/spyglass/lfp/lfp_merge.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/spyglass/lfp/lfp_merge.py b/src/spyglass/lfp/lfp_merge.py index d269b8e38..59b52acad 100644 --- a/src/spyglass/lfp/lfp_merge.py +++ b/src/spyglass/lfp/lfp_merge.py @@ -22,6 +22,7 @@ class LFPV1(dj.Part): -> LFPV1 --- -> AnalysisNwbfile + lfp_object_id: varchar(40) """ def fetch_nwb(self, *attrs, **kwargs): @@ -42,6 +43,7 @@ class ImportedLFPV1(dj.Part): -> ImportedLFPV1 --- -> AnalysisNwbfile + lfp_object_id: varchar(40) """ def fetch_nwb(self, *attrs, **kwargs): From 98ee13704a6b1d8e084adee946b9030e0b054758 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Fri, 26 May 2023 14:37:31 -0700 Subject: [PATCH 016/131] Fix method --- src/spyglass/lfp/v1/lfp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spyglass/lfp/v1/lfp.py b/src/spyglass/lfp/v1/lfp.py index 1c0f9a48a..3c8064679 100644 --- a/src/spyglass/lfp/v1/lfp.py +++ b/src/spyglass/lfp/v1/lfp.py @@ -80,7 +80,7 @@ def make(self, key): FirFilterParameters() & {"filter_name": key["filter_name"]} & {"filter_sampling_rate": sampling_rate} - ).fetch1(as_dict=True) + ).fetch(as_dict=True)[0] # there should only be one filter that matches, so we take the first of the dictionaries key["filter_name"] = filter["filter_name"] From f6f3e41e455c6cdc7f83a96d53ad98ff80304f84 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Fri, 26 May 2023 14:37:42 -0700 Subject: [PATCH 017/131] Add lfp to interval list name --- src/spyglass/lfp/v1/lfp.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/spyglass/lfp/v1/lfp.py b/src/spyglass/lfp/v1/lfp.py index 3c8064679..2b4c97b83 100644 --- a/src/spyglass/lfp/v1/lfp.py +++ b/src/spyglass/lfp/v1/lfp.py @@ -122,6 +122,7 @@ def make(self, key): # add an interval list for the LFP valid times, skipping duplicates key["interval_list_name"] = "_".join( ( + "lfp", key["lfp_electrode_group_name"], key["target_interval_list_name"], "valid times", From ab71fd92f303c88c1bd4769d7ac3702e9ba046a7 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Fri, 26 May 2023 14:38:02 -0700 Subject: [PATCH 018/131] Make consistent with position pipeline --- src/spyglass/lfp/v1/lfp.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/spyglass/lfp/v1/lfp.py b/src/spyglass/lfp/v1/lfp.py index 2b4c97b83..187789c41 100644 --- a/src/spyglass/lfp/v1/lfp.py +++ b/src/spyglass/lfp/v1/lfp.py @@ -142,11 +142,15 @@ def make(self, key): from spyglass.lfp.lfp_merge import LFPOutput lfp_id = uuid.uuid1() - lfp_o_key = {"lfp_id": lfp_id} + lfp_o_key = {"lfp_id": lfp_id, "source": "LFP", "version": 1} LFPOutput.insert1(lfp_o_key) orig_key.update(lfp_o_key) - LFPOutput.LFP.insert1(orig_key) + del orig_key["source"] + del orig_key["version"] + orig_key["analysis_file_name"] = lfp_file_name + orig_key["lfp_object_id"] = lfp_object_id + LFPOutput.LFPV1.insert1(orig_key) def fetch_nwb(self, *attrs, **kwargs): return fetch_nwb( From 77111760a5f5e6a1722c081ce97707379bd50d81 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Fri, 26 May 2023 14:38:17 -0700 Subject: [PATCH 019/131] Make consistent with position pipeline --- src/spyglass/lfp/lfp_merge.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/spyglass/lfp/lfp_merge.py b/src/spyglass/lfp/lfp_merge.py index 59b52acad..93e73a88f 100644 --- a/src/spyglass/lfp/lfp_merge.py +++ b/src/spyglass/lfp/lfp_merge.py @@ -13,7 +13,9 @@ class LFPOutput(dj.Manual): definition = """ lfp_id: uuid --- - stream: varchar(40) + source: varchar(40) + version: int + """ class LFPV1(dj.Part): From 37bf2563eb47d53eddc596d7a9bb9562aea6902c Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Fri, 26 May 2023 15:52:23 -0700 Subject: [PATCH 020/131] Fix table name --- src/spyglass/lfp/v1/lfp_artifact.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/spyglass/lfp/v1/lfp_artifact.py b/src/spyglass/lfp/v1/lfp_artifact.py index d5d49216b..fd48a7728 100644 --- a/src/spyglass/lfp/v1/lfp_artifact.py +++ b/src/spyglass/lfp/v1/lfp_artifact.py @@ -11,8 +11,8 @@ interval_from_inds, interval_list_intersect, ) -from spyglass.utils.nwb_helper_fn import get_valid_intervals from spyglass.lfp.v1.lfp import LFPV1 +from spyglass.utils.nwb_helper_fn import get_valid_intervals schema = dj.schema("lfp_v1") @@ -54,7 +54,7 @@ def insert_default(self): class LFPArtifactDetectionSelection(dj.Manual): definition = """ # Specifies artifact detection parameters to apply to a sort group's recording. - -> LFP + -> LFPV1 -> LFPArtifactDetectionParameters --- custom_artifact_detection=0 : tinyint From e66331168902bdae9091f4cde8953179e67c5d5b Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Sat, 27 May 2023 11:19:08 -0700 Subject: [PATCH 021/131] Fix variable name --- src/spyglass/common/common_ripple.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spyglass/common/common_ripple.py b/src/spyglass/common/common_ripple.py index dce0c0479..209a52f5d 100644 --- a/src/spyglass/common/common_ripple.py +++ b/src/spyglass/common/common_ripple.py @@ -250,7 +250,7 @@ def get_ripple_lfps_and_position_info(key): ) position_info = interpolate_to_new_time( - valid_position_info, interval_ripple_lfps.index + position_info, interval_ripple_lfps.index ) return ( From 2b842fc14246e63422569e1ffd97e171f55e90ad Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Sat, 27 May 2023 11:21:07 -0700 Subject: [PATCH 022/131] Keep in old pipeline --- src/spyglass/common/common_ripple.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spyglass/common/common_ripple.py b/src/spyglass/common/common_ripple.py index 209a52f5d..518d39033 100644 --- a/src/spyglass/common/common_ripple.py +++ b/src/spyglass/common/common_ripple.py @@ -8,7 +8,7 @@ IntervalList, # noqa IntervalPositionInfo, ) -from spyglass.lfp.v1 import LFPBand, LFPBandSelection +from spyglass.common import LFPBand, LFPBandSelection from spyglass.common.common_nwbfile import AnalysisNwbfile from spyglass.utils.dj_helper_fn import fetch_nwb From 34c8735d165df00bb8ace11b15bcd5220cbd99f5 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Sat, 27 May 2023 11:36:31 -0700 Subject: [PATCH 023/131] Initial move of schema --- src/spyglass/ripple/__init__.py | 0 src/spyglass/ripple/ripple_merge.py | 39 ++++ src/spyglass/ripple/v1/__init__.py | 0 src/spyglass/ripple/v1/ripple.py | 343 ++++++++++++++++++++++++++++ 4 files changed, 382 insertions(+) create mode 100644 src/spyglass/ripple/__init__.py create mode 100644 src/spyglass/ripple/ripple_merge.py create mode 100644 src/spyglass/ripple/v1/__init__.py create mode 100644 src/spyglass/ripple/v1/ripple.py diff --git a/src/spyglass/ripple/__init__.py b/src/spyglass/ripple/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/spyglass/ripple/ripple_merge.py b/src/spyglass/ripple/ripple_merge.py new file mode 100644 index 000000000..44b9a36c1 --- /dev/null +++ b/src/spyglass/ripple/ripple_merge.py @@ -0,0 +1,39 @@ +import datajoint as dj + +from spyglass.common.common_nwbfile import AnalysisNwbfile +from spyglass.ripple.v1.ripple import RippleTimesV1 # noqa F401 +from spyglass.utils.dj_helper_fn import fetch_nwb + +schema = dj.schema("ripple_merge") + + +@schema +class RippleTimesOutput(dj.Manual): + definition = """ + ripple_id: uuid + --- + source: varchar(40) + version: int + + """ + + class RippleTimesOutput(dj.Part): + definition = """ + -> RippleTimesOutput + -> RippleTimesV1 + --- + -> AnalysisNwbfile + lfp_object_id: varchar(40) + """ + + def fetch_nwb(self, *attrs, **kwargs): + return fetch_nwb( + self, (AnalysisNwbfile, "analysis_file_abs_path"), *attrs, **kwargs + ) + + def fetch1_dataframe(self): + """Convenience function for returning the marks in a readable format""" + return self.fetch_dataframe()[0] + + def fetch_dataframe(self): + return [data["ripple_times"] for data in self.fetch_nwb()] diff --git a/src/spyglass/ripple/v1/__init__.py b/src/spyglass/ripple/v1/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/spyglass/ripple/v1/ripple.py b/src/spyglass/ripple/v1/ripple.py new file mode 100644 index 000000000..632a74096 --- /dev/null +++ b/src/spyglass/ripple/v1/ripple.py @@ -0,0 +1,343 @@ +import copy + +import datajoint as dj +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd +from ripple_detection import Karlsson_ripple_detector, Kay_ripple_detector +from ripple_detection.core import gaussian_smooth, get_envelope + +from spyglass.common import IntervalList # noqa +from spyglass.common.common_nwbfile import AnalysisNwbfile +from spyglass.lfp.v1.filtered_lfp import LFPBand, LFPBandSelection +from spyglass.position import PositionOutput +from spyglass.utils.dj_helper_fn import fetch_nwb + +schema = dj.schema("ripple_v1") + +RIPPLE_DETECTION_ALGORITHMS = { + "Kay_ripple_detector": Kay_ripple_detector, + "Karlsson_ripple_detector": Karlsson_ripple_detector, +} + + +def interpolate_to_new_time(df, new_time, upsampling_interpolation_method="linear"): + old_time = df.index + new_index = pd.Index(np.unique(np.concatenate((old_time, new_time))), name="time") + return ( + df.reindex(index=new_index) + .interpolate(method=upsampling_interpolation_method) + .reindex(index=new_time) + ) + + +@schema +class RippleLFPSelection(dj.Manual): + definition = """ + -> LFPBand + group_name = 'CA1' : varchar(80) + """ + + class RippleLFPElectrode(dj.Part): + definition = """ + -> RippleLFPSelection + -> LFPBandSelection.LFPBandElectrode + """ + + def insert1(self, key, **kwargs): + filter_name = (LFPBand & key).fetch1("filter_name") + if "ripple" not in filter_name.lower(): + raise UserWarning("Please use a ripple filter") + super().insert1(key, **kwargs) + + @staticmethod + def set_lfp_electrodes( + key, + electrode_list=None, + group_name="CA1", + **kwargs, + ): + """Removes all electrodes for the specified nwb file and then adds back the electrodes in the list + + Parameters + ---------- + key : dict + dictionary corresponding to the LFPBand entry to use for ripple detection + electrode_list : list + list of electrodes from LFPBandSelection.LFPBandElectrode + to be used as the ripple LFP during detection + group_name : str, optional + description of the electrode group, by default "CA1" + """ + + RippleLFPSelection().insert1( + {**key, "group_name": group_name}, + skip_duplicates=True, + **kwargs, + ) + if not electrode_list: + electrode_list = ( + (LFPBandSelection.LFPBandElectrode() & key) + .fetch("electrode_id") + .tolist() + ) + electrode_list.sort() + electrode_keys = ( + pd.DataFrame(LFPBandSelection.LFPBandElectrode() & key) + .set_index("electrode_id") + .loc[electrode_list] + .reset_index() + .loc[:, LFPBandSelection.LFPBandElectrode.primary_key] + ) + electrode_keys["group_name"] = group_name + electrode_keys = electrode_keys.sort_values(by=["electrode_id"]) + RippleLFPSelection().RippleLFPElectrode.insert( + electrode_keys.to_dict(orient="records"), + replace=True, + **kwargs, + ) + + +@schema +class RippleParameters(dj.Lookup): + definition = """ + ripple_param_name : varchar(80) # a name for this set of parameters + ---- + ripple_param_dict : BLOB # dictionary of parameters + """ + + def insert_default(self): + """Insert the default parameter set""" + default_dict = { + "speed_name": "head_speed", + "ripple_detection_algorithm": "Kay_ripple_detector", + "ripple_detection_params": dict( + speed_threshold=4.0, # cm/s + minimum_duration=0.015, # sec + zscore_threshold=2.0, # std + smoothing_sigma=0.004, # sec + close_ripple_threshold=0.0, # sec + ), + } + self.insert1( + {"ripple_param_name": "default", "ripple_param_dict": default_dict}, + skip_duplicates=True, + ) + + +@schema +class RippleTimesV1(dj.Computed): + definition = """ + -> RippleParameters + -> RippleLFPSelection + -> IntervalPositionInfo + --- + -> AnalysisNwbfile + ripple_times_object_id : varchar(40) + """ + + def make(self, key): + print(f"Computing ripple times for: {key}") + ripple_params = ( + RippleParameters & {"ripple_param_name": key["ripple_param_name"]} + ).fetch1("ripple_param_dict") + + ripple_detection_algorithm = ripple_params["ripple_detection_algorithm"] + ripple_detection_params = ripple_params["ripple_detection_params"] + + ( + speed, + interval_ripple_lfps, + sampling_frequency, + ) = self.get_ripple_lfps_and_position_info(key) + + ripple_times = RIPPLE_DETECTION_ALGORITHMS[ripple_detection_algorithm]( + time=np.asarray(interval_ripple_lfps.index), + filtered_lfps=np.asarray(interval_ripple_lfps), + speed=np.asarray(speed), + sampling_frequency=sampling_frequency, + **ripple_detection_params, + ) + + # Insert into analysis nwb file + nwb_analysis_file = AnalysisNwbfile() + key["analysis_file_name"] = nwb_analysis_file.create(key["nwb_file_name"]) + key["ripple_times_object_id"] = nwb_analysis_file.add_nwb_object( + analysis_file_name=key["analysis_file_name"], + nwb_object=ripple_times, + ) + nwb_analysis_file.add( + nwb_file_name=key["nwb_file_name"], + analysis_file_name=key["analysis_file_name"], + ) + + self.insert1(key) + + def fetch_nwb(self, *attrs, **kwargs): + return fetch_nwb( + self, (AnalysisNwbfile, "analysis_file_abs_path"), *attrs, **kwargs + ) + + def fetch1_dataframe(self): + """Convenience function for returning the marks in a readable format""" + return self.fetch_dataframe()[0] + + def fetch_dataframe(self): + return [data["ripple_times"] for data in self.fetch_nwb()] + + @staticmethod + def get_ripple_lfps_and_position_info(key): + nwb_file_name = key["nwb_file_name"] + interval_list_name = key["target_interval_list_name"] + position_info_param_name = key["position_info_param_name"] + ripple_params = ( + RippleParameters & {"ripple_param_name": key["ripple_param_name"]} + ).fetch1("ripple_param_dict") + + speed_name = ripple_params["speed_name"] + + electrode_keys = (RippleLFPSelection.RippleLFPElectrode() & key).fetch( + "electrode_id" + ) + + # warn/validate that there is only one wire per electrode + lfp_key = copy.deepcopy(key) + del lfp_key["interval_list_name"] + ripple_lfp_nwb = (LFPBand & lfp_key).fetch_nwb()[0] + ripple_lfp_electrodes = ripple_lfp_nwb["filtered_data"].electrodes.data[:] + elec_mask = np.full_like(ripple_lfp_electrodes, 0, dtype=bool) + elec_mask[ + [ + ind + for ind, elec in enumerate(ripple_lfp_electrodes) + if elec in electrode_keys + ] + ] = True + ripple_lfp = pd.DataFrame( + ripple_lfp_nwb["filtered_data"].data, + index=pd.Index(ripple_lfp_nwb["filtered_data"].timestamps, name="time"), + ) + sampling_frequency = ripple_lfp_nwb["lfp_band_sampling_rate"] + + ripple_lfp = ripple_lfp.loc[:, elec_mask] + + position_valid_times = ( + IntervalList + & {"nwb_file_name": nwb_file_name, "interval_list_name": interval_list_name} + ).fetch1("valid_times") + + position_info = ( + PositionOutput() + & { + "nwb_file_name": nwb_file_name, + "interval_list_name": interval_list_name, + "position_info_param_name": position_info_param_name, + } + ).fetch1_dataframe() + + position_info = pd.concat( + [ + position_info.loc[slice(valid_time[0], valid_time[1])] + for valid_time in position_valid_times + ], + axis=1, + ) + interval_ripple_lfps = pd.concat( + [ + ripple_lfp.loc[slice(valid_time[0], valid_time[1])] + for valid_time in position_valid_times + ], + axis=1, + ) + + position_info = interpolate_to_new_time( + position_info, interval_ripple_lfps.index + ) + + return ( + position_info[speed_name], + interval_ripple_lfps, + sampling_frequency, + ) + + @staticmethod + def get_Kay_ripple_consensus_trace( + ripple_filtered_lfps, sampling_frequency, smoothing_sigma=0.004 + ): + ripple_consensus_trace = np.full_like(ripple_filtered_lfps, np.nan) + not_null = np.all(pd.notnull(ripple_filtered_lfps), axis=1) + + ripple_consensus_trace[not_null] = get_envelope( + np.asarray(ripple_filtered_lfps)[not_null] + ) + ripple_consensus_trace = np.sum(ripple_consensus_trace**2, axis=1) + ripple_consensus_trace[not_null] = gaussian_smooth( + ripple_consensus_trace[not_null], smoothing_sigma, sampling_frequency + ) + return pd.DataFrame( + np.sqrt(ripple_consensus_trace), index=ripple_filtered_lfps.index + ) + + @staticmethod + def plot_ripple_consensus_trace( + ripple_consensus_trace, + ripple_times, + ripple_label=1, + offset=0.100, + relative=True, + ax=None, + ): + ripple_start = ripple_times.loc[ripple_label].start_time + ripple_end = ripple_times.loc[ripple_label].end_time + time_slice = slice(ripple_start - offset, ripple_end + offset) + + start_offset = ripple_start if relative else 0 + if ax is None: + fig, ax = plt.subplots(1, 1, figsize=(12, 1)) + ax.plot( + ripple_consensus_trace.loc[time_slice].index - start_offset, + ripple_consensus_trace.loc[time_slice], + ) + ax.axvspan( + ripple_start - start_offset, + ripple_end - start_offset, + zorder=-1, + alpha=0.5, + color="lightgrey", + ) + ax.set_xlabel("Time [s]") + ax.set_xlim((time_slice.start - start_offset, time_slice.stop - start_offset)) + + @staticmethod + def plot_ripple( + lfps, ripple_times, ripple_label=1, offset=0.100, relative=True, ax=None + ): + lfp_labels = lfps.columns + n_lfps = len(lfp_labels) + ripple_start = ripple_times.loc[ripple_label].start_time + ripple_end = ripple_times.loc[ripple_label].end_time + time_slice = slice(ripple_start - offset, ripple_end + offset) + if ax is None: + fig, ax = plt.subplots(1, 1, figsize=(12, n_lfps * 0.20)) + + start_offset = ripple_start if relative else 0 + + for lfp_ind, lfp_label in enumerate(lfp_labels): + lfp = lfps.loc[time_slice, lfp_label] + ax.plot( + lfp.index - start_offset, + lfp_ind + (lfp - lfp.mean()) / (lfp.max() - lfp.min()), + color="black", + ) + + ax.axvspan( + ripple_start - start_offset, + ripple_end - start_offset, + zorder=-1, + alpha=0.5, + color="lightgrey", + ) + ax.set_ylim((-1, n_lfps)) + ax.set_xlim((time_slice.start - start_offset, time_slice.stop - start_offset)) + ax.set_ylabel("LFPs") + ax.set_xlabel("Time [s]") From 08d43d48006ab6c4167c2b66e9a8bdbea0f61a55 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Sat, 27 May 2023 11:43:09 -0700 Subject: [PATCH 024/131] Fix imports and naming --- src/spyglass/ripple/__init__.py | 1 + src/spyglass/ripple/ripple_merge.py | 4 ++-- src/spyglass/ripple/v1/__init__.py | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/spyglass/ripple/__init__.py b/src/spyglass/ripple/__init__.py index e69de29bb..908fce6e5 100644 --- a/src/spyglass/ripple/__init__.py +++ b/src/spyglass/ripple/__init__.py @@ -0,0 +1 @@ +from spyglass.ripple.ripple_merge import RippleTimesOutput diff --git a/src/spyglass/ripple/ripple_merge.py b/src/spyglass/ripple/ripple_merge.py index 44b9a36c1..9ac973067 100644 --- a/src/spyglass/ripple/ripple_merge.py +++ b/src/spyglass/ripple/ripple_merge.py @@ -17,13 +17,13 @@ class RippleTimesOutput(dj.Manual): """ - class RippleTimesOutput(dj.Part): + class RippleTimesV1(dj.Part): definition = """ -> RippleTimesOutput -> RippleTimesV1 --- -> AnalysisNwbfile - lfp_object_id: varchar(40) + ripple_times_object_id : varchar(40) """ def fetch_nwb(self, *attrs, **kwargs): diff --git a/src/spyglass/ripple/v1/__init__.py b/src/spyglass/ripple/v1/__init__.py index e69de29bb..5a2d817d8 100644 --- a/src/spyglass/ripple/v1/__init__.py +++ b/src/spyglass/ripple/v1/__init__.py @@ -0,0 +1 @@ +from spyglass.ripple.v1 import RippleLFPSelection, RippleParameters, RippleTimesV1 From 17448bc19f6f881f71a355410a45660291d368c6 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Sat, 27 May 2023 12:04:15 -0700 Subject: [PATCH 025/131] Add insert to Output table --- src/spyglass/ripple/v1/ripple.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/spyglass/ripple/v1/ripple.py b/src/spyglass/ripple/v1/ripple.py index 632a74096..beaa97b69 100644 --- a/src/spyglass/ripple/v1/ripple.py +++ b/src/spyglass/ripple/v1/ripple.py @@ -1,4 +1,5 @@ import copy +import uuid import datajoint as dj import matplotlib.pyplot as plt @@ -173,6 +174,24 @@ def make(self, key): self.insert1(key) + # finally, we insert this into the LFP output table. + from spyglass.ripple.ripple_merge import RippleTimesOutput + + ripple_times_object_id = uuid.uuid1() + ripple_times_output_key = { + "lfp_id": ripple_times_object_id, + "source": "LFP", + "version": 1, + } + RippleTimesOutput.insert1(ripple_times_output_key) + + key.update(ripple_times_output_key) + del key["source"] + del key["version"] + + key["ripple_time_object_id"] = ripple_times_object_id + RippleTimesOutput.RippleTimesV1.insert1(key) + def fetch_nwb(self, *attrs, **kwargs): return fetch_nwb( self, (AnalysisNwbfile, "analysis_file_abs_path"), *attrs, **kwargs From 08072e086c1ba7f70872e12707104b7dd084585d Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Sat, 27 May 2023 21:31:38 -0700 Subject: [PATCH 026/131] Turn off pylance type checking --- .vscode/settings.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index 7a5a4f696..2c05895e3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,6 +7,7 @@ "python.formatting.provider": "none", "remote.SSH.remoteServerListenOnSocket": true, "git.confirmSync": false, + "python.analysis.typeCheckingMode": "off", "[python]": { "editor.defaultFormatter": "ms-python.black-formatter" }, From e012f82e13ba3e5d0f7c6959854134524ecde7d4 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Sun, 28 May 2023 09:18:04 -0700 Subject: [PATCH 027/131] Move LFPBand to its own pipeline --- src/spyglass/lfp_band/__init__.py | 0 src/spyglass/lfp_band/lfp_band_merge.py | 40 +++++++++++++++++++ .../v1/lfp_band.py} | 26 ++++++++---- 3 files changed, 59 insertions(+), 7 deletions(-) create mode 100644 src/spyglass/lfp_band/__init__.py create mode 100644 src/spyglass/lfp_band/lfp_band_merge.py rename src/spyglass/{lfp/v1/filtered_lfp.py => lfp_band/v1/lfp_band.py} (95%) diff --git a/src/spyglass/lfp_band/__init__.py b/src/spyglass/lfp_band/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/spyglass/lfp_band/lfp_band_merge.py b/src/spyglass/lfp_band/lfp_band_merge.py new file mode 100644 index 000000000..ecc7fec93 --- /dev/null +++ b/src/spyglass/lfp_band/lfp_band_merge.py @@ -0,0 +1,40 @@ +import datajoint as dj +import pandas as pd + +from spyglass.common.common_nwbfile import AnalysisNwbfile +from spyglass.lfp_band.v1.lfp_band import LFPBandV1 # noqa F401 +from spyglass.utils.dj_helper_fn import fetch_nwb + +schema = dj.schema("lfp_band_merge") + + +@schema +class LFPBandOutput(dj.Manual): + definition = """ + lfp_band_id: uuid + --- + source: varchar(40) + version: int + + """ + + class LFPBandV1(dj.Part): + definition = """ + -> LFPBandOutput + -> LFPBandV1 + --- + -> AnalysisNwbfile + lfp_band_object_id: varchar(40) + """ + + def fetch_nwb(self, *attrs, **kwargs): + return fetch_nwb( + self, (AnalysisNwbfile, "analysis_file_abs_path"), *attrs, **kwargs + ) + + def fetch1_dataframe(self, *attrs, **kwargs): + filtered_nwb = self.fetch_nwb()[0] + return pd.DataFrame( + filtered_nwb["filtered_data"].data, + index=pd.Index(filtered_nwb["filtered_data"].timestamps, name="time"), + ) diff --git a/src/spyglass/lfp/v1/filtered_lfp.py b/src/spyglass/lfp_band/v1/lfp_band.py similarity index 95% rename from src/spyglass/lfp/v1/filtered_lfp.py rename to src/spyglass/lfp_band/v1/lfp_band.py index ca3afa934..0d61f520e 100644 --- a/src/spyglass/lfp/v1/filtered_lfp.py +++ b/src/spyglass/lfp_band/v1/lfp_band.py @@ -1,3 +1,5 @@ +import uuid + import datajoint as dj import numpy as np import pandas as pd @@ -15,10 +17,10 @@ from spyglass.common.common_nwbfile import AnalysisNwbfile from spyglass.lfp.lfp_merge import LFPOutput from spyglass.lfp.v1.lfp import LFPElectrodeGroup -from spyglass.utils.dj_helper_fn import fetch_nwb # dj_replace +from spyglass.utils.dj_helper_fn import fetch_nwb from spyglass.utils.nwb_helper_fn import get_electrode_indices -schema = dj.schema("lfp_v1") +schema = dj.schema("lfp_band_v1") @schema @@ -153,13 +155,13 @@ def set_lfp_band_electrodes( @schema -class LFPBand(dj.Computed): +class LFPBandV1(dj.Computed): definition = """ -> LFPBandSelection --- -> AnalysisNwbfile -> IntervalList - filtered_data_object_id: varchar(40) # the NWB object ID for loading this object from the file + lfp_band_object_id: varchar(40) # the NWB object ID for loading this object from the file """ def make(self, key): @@ -305,12 +307,12 @@ def make(self, key): ) ecephys_module.add(lfp) io.write(nwbf) - filtered_data_object_id = es.object_id + lfp_band_object_id = es.object_id # # add the file to the AnalysisNwbfile table AnalysisNwbfile().add(key["nwb_file_name"], lfp_band_file_name) key["analysis_file_name"] = lfp_band_file_name - key["filtered_data_object_id"] = filtered_data_object_id + key["lfp_band_object_id"] = lfp_band_object_id # finally, we need to censor the valid times to account for the downsampling if this is the first time we've # downsampled these data @@ -342,7 +344,17 @@ def make(self, key): tmp_valid_times[0], lfp_band_valid_times ).all(), "previously saved lfp band times do not match current times" - self.insert1(key) + from spyglass.lfp_band.lfp_band_merge import LFPBandOutput + + lfp_band_output_key = { + "lfp_band_id": uuid.uuid1(), + "source": "LFPBand", + "version": "1", + "analysis_file_name": lfp_band_file_name, + "lfp_band_object_id": lfp_band_object_id, + } + LFPBandOutput.insert1(lfp_band_output_key) + LFPBandOutput.LFPBandV1.insert1(key) def fetch_nwb(self, *attrs, **kwargs): return fetch_nwb( From 3d25a90940a72d0737b36241d9047fa6c374f02a Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Sun, 28 May 2023 09:28:05 -0700 Subject: [PATCH 028/131] Fix import --- src/spyglass/ripple/v1/ripple.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spyglass/ripple/v1/ripple.py b/src/spyglass/ripple/v1/ripple.py index beaa97b69..21998cd86 100644 --- a/src/spyglass/ripple/v1/ripple.py +++ b/src/spyglass/ripple/v1/ripple.py @@ -10,7 +10,7 @@ from spyglass.common import IntervalList # noqa from spyglass.common.common_nwbfile import AnalysisNwbfile -from spyglass.lfp.v1.filtered_lfp import LFPBand, LFPBandSelection +from spyglass.lfp_band.v1.lfp_band import LFPBand, LFPBandSelection from spyglass.position import PositionOutput from spyglass.utils.dj_helper_fn import fetch_nwb From 2b72094724a750db35df9bc1f79725e5c1651ebb Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Wed, 31 May 2023 10:02:20 -0700 Subject: [PATCH 029/131] Update src/spyglass/lfp/v1/lfp_artifact.py Co-authored-by: Chris Brozdowski --- src/spyglass/lfp/v1/lfp_artifact.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/spyglass/lfp/v1/lfp_artifact.py b/src/spyglass/lfp/v1/lfp_artifact.py index fd48a7728..6dab0b1db 100644 --- a/src/spyglass/lfp/v1/lfp_artifact.py +++ b/src/spyglass/lfp/v1/lfp_artifact.py @@ -139,8 +139,6 @@ def _get_artifact_times( proportion_above_thresh_2nd: float = 1.0, removal_window_ms: float = 1.0, local_window_ms: float = 1.0, - # verbose: bool = False, - # **job_kwargs, ): """Detects times during which artifacts do and do not occur. Artifacts are defined as periods where the absolute value of the change in LFP exceeds From 573eb5a912641a8112a968b23ce6fb444de0b06e Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Wed, 31 May 2023 10:02:33 -0700 Subject: [PATCH 030/131] Update src/spyglass/lfp_band/v1/lfp_band.py Co-authored-by: Chris Brozdowski --- src/spyglass/lfp_band/v1/lfp_band.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/spyglass/lfp_band/v1/lfp_band.py b/src/spyglass/lfp_band/v1/lfp_band.py index 0d61f520e..ca31f8404 100644 --- a/src/spyglass/lfp_band/v1/lfp_band.py +++ b/src/spyglass/lfp_band/v1/lfp_band.py @@ -126,13 +126,14 @@ def set_lfp_band_electrodes( ref_list = np.zeros((len(electrode_list),)) ref_list[:] = reference_electrode_list - key = dict() - key["nwb_file_name"] = nwb_file_name - key["lfp_id"] = lfp_id - key["filter_name"] = filter_name - key["filter_sampling_rate"] = lfp_sampling_rate - key["target_interval_list_name"] = interval_list_name - key["lfp_band_sampling_rate"] = lfp_sampling_rate // decimation + key = dict( + nwb_file_name=nwb_file_name, + lfp_id=lfp_id, + filter_name=filter_name, + filter_sampling_rate=lfp_sampling_rate, + target_interval_list_name=interval_list_name, + lfp_band_sampling_rate=lfp_sampling_rate // decimation, + ) # insert an entry into the main LFPBandSelectionTable self.insert1(key, skip_duplicates=True) From 0a8e687d27abb93dad44cc32d3cb98b5fdb51834 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Wed, 31 May 2023 10:02:52 -0700 Subject: [PATCH 031/131] Update src/spyglass/lfp_band/v1/lfp_band.py Co-authored-by: Chris Brozdowski --- src/spyglass/lfp_band/v1/lfp_band.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/spyglass/lfp_band/v1/lfp_band.py b/src/spyglass/lfp_band/v1/lfp_band.py index ca31f8404..ce8df0039 100644 --- a/src/spyglass/lfp_band/v1/lfp_band.py +++ b/src/spyglass/lfp_band/v1/lfp_band.py @@ -89,20 +89,20 @@ def set_lfp_band_electrodes( f"samping rate {lfp_sampling_rate}" ) # filter - query = FirFilterParameters() & { + filter_query = FirFilterParameters() & { "filter_name": filter_name, "filter_sampling_rate": lfp_sampling_rate, } - if not query: + if not filter_query: raise ValueError( f"filter {filter_name}, sampling rate {lfp_sampling_rate} is not in the FirFilterParameters table" ) # interval_list - query = IntervalList() & { + interval_query = IntervalList() & { "nwb_file_name": nwb_file_name, "interval_name": interval_list_name, } - if not query: + if not interval_query: raise ValueError( f"interval list {interval_list_name} is not in the IntervalList table; the list must be " "added before this function is called" From 54cc500d807e37d40fff305ff423b2b3952b5027 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Thu, 1 Jun 2023 12:33:13 -0700 Subject: [PATCH 032/131] Add documentation --- src/spyglass/lfp/lfp_merge.py | 6 ++--- src/spyglass/lfp/v1/__init__.py | 2 -- src/spyglass/lfp/v1/lfp.py | 43 +++++++++++++++++++++++---------- 3 files changed, 33 insertions(+), 18 deletions(-) diff --git a/src/spyglass/lfp/lfp_merge.py b/src/spyglass/lfp/lfp_merge.py index 93e73a88f..33b519616 100644 --- a/src/spyglass/lfp/lfp_merge.py +++ b/src/spyglass/lfp/lfp_merge.py @@ -80,8 +80,8 @@ def get_lfp_object(key: dict): The entry or entries in the LFPOutput part table that corresponds to the key """ # first check if this returns anything from the LFP table - lfp_object = LFPOutput.LFP & key - if lfp_object is not None: - return LFPV1 & lfp_object.fetch("KEY") + query = LFPOutput.LFP & key + if query is not None: + return LFPV1 & query.fetch("KEY") else: return ImportedLFPV1 & (LFPOutput.ImportedLFP & key).fetch("KEY") diff --git a/src/spyglass/lfp/v1/__init__.py b/src/spyglass/lfp/v1/__init__.py index 81b4aada3..e18869574 100644 --- a/src/spyglass/lfp/v1/__init__.py +++ b/src/spyglass/lfp/v1/__init__.py @@ -6,5 +6,3 @@ LFPArtifactDetectionSelection, LFPArtifactRemovedIntervalList, ) - -# from spyglass.lfp.v1.filtered_lfp import LFPBand, LFPBandSelection diff --git a/src/spyglass/lfp/v1/lfp.py b/src/spyglass/lfp/v1/lfp.py index 187789c41..cf00fd19c 100644 --- a/src/spyglass/lfp/v1/lfp.py +++ b/src/spyglass/lfp/v1/lfp.py @@ -1,6 +1,6 @@ +import copy import uuid -import copy import datajoint as dj import numpy as np import pandas as pd @@ -23,15 +23,29 @@ @schema class LFPSelection(dj.Manual): + """The user's selection of LFP data to be filtered + + This table is used to select the LFP data to be filtered. The user can select + the LFP data by specifying the electrode group and the interval list to be used. + The interval list is used to select the times from the raw data that will be + filtered. The user can also specify the filter to be used. + + The LFP data is filtered and downsampled to 1 KHz. The filtered data is stored + in the AnalysisNwbfile table. The valid times for the filtered data are stored + in the IntervalList table. + """ + definition = """ - -> LFPElectrodeGroup + -> LFPElectrodeGroup # the group of electrodes to be filtered -> IntervalList.proj(target_interval_list_name='interval_list_name') # the original set of times to be filtered - -> FirFilterParameters + -> FirFilterParameters # the filter to be used """ @schema class LFPV1(dj.Computed): + """The filtered LFP data""" + definition = """ -> LFPSelection --- @@ -42,6 +56,7 @@ class LFPV1(dj.Computed): """ def make(self, key): + DECIMATION_FACTOR = 1000 # get the NWB object with the data nwbf_key = {"nwb_file_name": key["nwb_file_name"]} rawdata = (Raw & nwbf_key).fetch_nwb()[0]["raw"] @@ -73,7 +88,7 @@ def make(self, key): ) # target 1 KHz sampling rate - decimation = sampling_rate // 1000 + decimation = sampling_rate // DECIMATION_FACTOR # get the LFP filter that matches the raw data filter = ( @@ -167,30 +182,32 @@ def fetch1_dataframe(self, *attrs, **kwargs): @schema class ImportedLFPV1(dj.Imported): definition = """ - -> Session - -> LFPElectrodeGroup - -> IntervalList + -> Session # the session to which this LFP belongs + -> LFPElectrodeGroup # the group of electrodes to be filtered + -> IntervalList # the original set of times to be filtered lfp_object_id: varchar(40) # the NWB object ID for loading this object from the file --- - lfp_sampling_rate: float + lfp_sampling_rate: float # the sampling rate, in samples/sec """ @schema class LFPElectrodeGroup(dj.Manual): definition = """ - -> Session - lfp_electrode_group_name: varchar(200) + -> Session # the session to which this LFP belongs + lfp_electrode_group_name: varchar(200) # the name of this group of electrodes """ class LFPElectrode(dj.Part): definition = """ - -> LFPElectrodeGroup - -> Electrode + -> LFPElectrodeGroup # the group of electrodes to be filtered + -> Electrode # the electrode to be filtered """ @staticmethod - def create_lfp_electrode_group(nwb_file_name, group_name, electrode_list): + def create_lfp_electrode_group( + nwb_file_name: str, group_name: str, electrode_list: list[int] + ): """Adds an LFPElectrodeGroup and the individual electrodes Parameters From e9cf9c943997c122831cc4af1242c49deb3446a5 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Thu, 1 Jun 2023 12:42:04 -0700 Subject: [PATCH 033/131] Add docstrings and types --- src/spyglass/lfp_band/v1/lfp_band.py | 106 +++++++++++++++++++-------- 1 file changed, 74 insertions(+), 32 deletions(-) diff --git a/src/spyglass/lfp_band/v1/lfp_band.py b/src/spyglass/lfp_band/v1/lfp_band.py index ce8df0039..eda0ceb81 100644 --- a/src/spyglass/lfp_band/v1/lfp_band.py +++ b/src/spyglass/lfp_band/v1/lfp_band.py @@ -25,18 +25,20 @@ @schema class LFPBandSelection(dj.Manual): + """The user's selection of LFP data to be filtered in a given frequency band.""" + definition = """ - -> LFPOutput - -> FirFilterParameters # the filter to use for the data + -> LFPOutput # the LFP data to be filtered + -> FirFilterParameters # the filter to use for the data -> IntervalList.proj(target_interval_list_name='interval_list_name') # the original set of times to be filtered - lfp_band_sampling_rate: int # the sampling rate for this band + lfp_band_sampling_rate: int # the sampling rate for this band --- min_interval_len = 1.0: float # the minimum length of a valid interval to filter """ class LFPBandElectrode(dj.Part): definition = """ - -> LFPBandSelection + -> LFPBandSelection # the LFP band selection -> LFPElectrodeGroup.LFPElectrode # the LFP electrode to be filtered reference_elect_id = -1: int # the reference electrode to use; -1 for no reference --- @@ -44,28 +46,31 @@ class LFPBandElectrode(dj.Part): def set_lfp_band_electrodes( self, - nwb_file_name, - lfp_id, - electrode_list, - filter_name, - interval_list_name, - reference_electrode_list, - lfp_band_sampling_rate, + nwb_file_name: str, + lfp_id: int, + electrode_list: list[int], + filter_name: str, + interval_list_name: str, + reference_electrode_list: list[int], + lfp_band_sampling_rate: int, ): - # TODO: fix docstring to match normal format. - """ - Adds an entry for each electrode in the electrode_list with the specified filter, interval_list, and - reference electrode. - :param nwb_file_name: string - the name of the nwb file for the desired session - :param lfp_id: uuid - the uuid for the LFPOutput to use - :param electrode_list: list of LFP electrodes (electrode ids) to be filtered - :param filter_name: the name of the filter (from the FirFilterParameters schema) - :param interval_name: the name of the interval list (from the IntervalList schema) - :param reference_electrode_list: A single electrode id corresponding to the reference to use for all - electrodes or a list with one element per entry in the electrode_list - :param lfp_band_sampling_rate: The output sampling rate to be used for the filtered data; must be an - integer divisor of the LFP sampling rate - :return: none + """Sets the electrodes to be filtered for a given LFP + + Parameters + ---------- + nwb_file_name: str + The name of the NWB file containing the LFP data + lfp_id: int + The id of the LFP data to be filtered + electrode_list: list + A list of the electrodes to be filtered + filter_name: str + The name of the filter to be used + interval_list_name: str + The name of the interval list to be used + reference_electrode_list: list + A list of the reference electrodes to be used + lfp_band_sampling_rate: int """ # Error checks on parameters # electrode_list @@ -158,10 +163,10 @@ def set_lfp_band_electrodes( @schema class LFPBandV1(dj.Computed): definition = """ - -> LFPBandSelection + -> LFPBandSelection # the LFP band selection --- - -> AnalysisNwbfile - -> IntervalList + -> AnalysisNwbfile # the name of the nwb file with the lfp data + -> IntervalList # the final interval list of valid times for the data lfp_band_object_id: varchar(40) # the NWB object ID for loading this object from the file """ @@ -363,18 +368,19 @@ def fetch_nwb(self, *attrs, **kwargs): ) def fetch1_dataframe(self, *attrs, **kwargs): + """Fetches the filtered data as a dataframe""" filtered_nwb = self.fetch_nwb()[0] return pd.DataFrame( filtered_nwb["filtered_data"].data, index=pd.Index(filtered_nwb["filtered_data"].timestamps, name="time"), ) - def compute_analytic_signal(self, electrode_list, **kwargs): + def compute_analytic_signal(self, electrode_list: list[int], **kwargs): """Computes the hilbert transform of a given LFPBand signal using scipy.signal.hilbert Parameters ---------- - electrode_list: list + electrode_list: list[int] A list of the electrodes to compute the hilbert transform of Returns @@ -401,16 +407,52 @@ def compute_analytic_signal(self, electrode_list, **kwargs): ) return analytic_signal_df - def compute_signal_phase(self, electrode_list=[], **kwargs): + def compute_signal_phase( + self, electrode_list: list[int] = None, **kwargs + ) -> pd.DataFrame: + """Computes the phase of a given LFPBand signals using the hilbert transform + + Parameters + ---------- + electrode_list : list[int], optional + A list of the electrodes to compute the phase of, by default None + + Returns + ------- + signal_phase_df : pd.DataFrame + DataFrame containing the phase of the signals + """ + if electrode_list is None: + electrode_list = [] + analytic_signal_df = self.compute_analytic_signal(electrode_list, **kwargs) + return pd.DataFrame( np.angle(analytic_signal_df) + np.pi, columns=analytic_signal_df.columns, index=analytic_signal_df.index, ) - def compute_signal_power(self, electrode_list=[], **kwargs): + def compute_signal_power( + self, electrode_list: list[int] = None, **kwargs + ) -> pd.DataFrame: + """Computes the power of a given LFPBand signals using the hilbert transform + + Parameters + ---------- + electrode_list : list[int], optional + A list of the electrodes to compute the power of, by default None + + Returns + ------- + signal_power_df : pd.DataFrame + DataFrame containing the power of the signals + """ + if electrode_list is None: + electrode_list = [] + analytic_signal_df = self.compute_analytic_signal(electrode_list, **kwargs) + return pd.DataFrame( np.abs(analytic_signal_df) ** 2, columns=analytic_signal_df.columns, From e673bb1d8514602d7fdc6d6a8d728973f5e2806a Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Thu, 1 Jun 2023 12:55:36 -0700 Subject: [PATCH 034/131] Fix linting --- src/spyglass/lfp/v1/__init__.py | 7 ++++++- src/spyglass/lfp/v1/lfp.py | 17 ++++++++++++---- src/spyglass/lfp/v1/lfp_artifact.py | 31 +++++++++++++++++++++-------- 3 files changed, 42 insertions(+), 13 deletions(-) diff --git a/src/spyglass/lfp/v1/__init__.py b/src/spyglass/lfp/v1/__init__.py index e18869574..2530a2fc0 100644 --- a/src/spyglass/lfp/v1/__init__.py +++ b/src/spyglass/lfp/v1/__init__.py @@ -1,5 +1,10 @@ # flake8: noqa -from spyglass.lfp.v1.lfp import LFPV1, ImportedLFPV1, LFPElectrodeGroup, LFPSelection +from spyglass.lfp.v1.lfp import ( + LFPV1, + ImportedLFPV1, + LFPElectrodeGroup, + LFPSelection, +) from spyglass.lfp.v1.lfp_artifact import ( LFPArtifactDetection, LFPArtifactDetectionParameters, diff --git a/src/spyglass/lfp/v1/lfp.py b/src/spyglass/lfp/v1/lfp.py index cf00fd19c..1b33784f8 100644 --- a/src/spyglass/lfp/v1/lfp.py +++ b/src/spyglass/lfp/v1/lfp.py @@ -81,7 +81,9 @@ def make(self, key): } ).fetch1("valid_times") valid_times = interval_list_intersect( - user_valid_times, raw_valid_times, min_length=MIN_LFP_INTERVAL_DURATION + user_valid_times, + raw_valid_times, + min_length=MIN_LFP_INTERVAL_DURATION, ) print( f"LFP: found {len(valid_times)} intervals > {MIN_LFP_INTERVAL_DURATION} sec long." @@ -115,7 +117,10 @@ def make(self, key): lfp_file_name = AnalysisNwbfile().create(key["nwb_file_name"]) lfp_file_abspath = AnalysisNwbfile().get_abs_path(lfp_file_name) - lfp_object_id, timestamp_interval = FirFilterParameters().filter_data_nwb( + ( + lfp_object_id, + timestamp_interval, + ) = FirFilterParameters().filter_data_nwb( lfp_file_abspath, rawdata, filter_coeff, @@ -175,7 +180,8 @@ def fetch_nwb(self, *attrs, **kwargs): def fetch1_dataframe(self, *attrs, **kwargs): nwb_lfp = self.fetch_nwb()[0] return pd.DataFrame( - nwb_lfp["lfp"].data, index=pd.Index(nwb_lfp["lfp"].timestamps, name="time") + nwb_lfp["lfp"].data, + index=pd.Index(nwb_lfp["lfp"].timestamps, name="time"), ) @@ -221,7 +227,10 @@ def create_lfp_electrode_group( """ # remove the session and then recreate the session and Electrode list # check to see if the user allowed the deletion - key = {"nwb_file_name": nwb_file_name, "lfp_electrode_group_name": group_name} + key = { + "nwb_file_name": nwb_file_name, + "lfp_electrode_group_name": group_name, + } LFPElectrodeGroup().insert1(key, skip_duplicates=True) # TODO: do this in a better way diff --git a/src/spyglass/lfp/v1/lfp_artifact.py b/src/spyglass/lfp/v1/lfp_artifact.py index 6dab0b1db..99185f70f 100644 --- a/src/spyglass/lfp/v1/lfp_artifact.py +++ b/src/spyglass/lfp/v1/lfp_artifact.py @@ -109,7 +109,9 @@ def make(self, key): # also insert into IntervalList tmp_key = {} tmp_key["nwb_file_name"] = key["nwb_file_name"] - tmp_key["interval_list_name"] = key["artifact_removed_interval_list_name"] + tmp_key["interval_list_name"] = key[ + "artifact_removed_interval_list_name" + ] tmp_key["valid_times"] = key["artifact_removed_valid_times"] IntervalList.insert1(tmp_key, replace=True) @@ -173,7 +175,9 @@ def _get_artifact_times( # if both thresholds are None, we skip artifact detection if amplitude_thresh_1st is None: - recording_interval = np.asarray([valid_timestamps[0], valid_timestamps[-1]]) + recording_interval = np.asarray( + [valid_timestamps[0], valid_timestamps[-1]] + ) artifact_times_empty = np.asarray([]) print("Amplitude threshold is None, skipping artifact detection") return recording_interval, artifact_times_empty @@ -193,8 +197,12 @@ def _get_artifact_times( # want to detect frames without parallel processing # compute the number of electrodes that have to be above threshold - nelect_above_1st = np.ceil(proportion_above_thresh_1st * recording.data.shape[1]) - nelect_above_2nd = np.ceil(proportion_above_thresh_2nd * recording.data.shape[1]) + nelect_above_1st = np.ceil( + proportion_above_thresh_1st * recording.data.shape[1] + ) + nelect_above_2nd = np.ceil( + proportion_above_thresh_2nd * recording.data.shape[1] + ) # find the artifact occurrences using one or both thresholds, across channels # replace with LFP artifact code @@ -202,12 +210,15 @@ def _get_artifact_times( if amplitude_thresh_1st is not None: # first find times with large amp change artifact_boolean = np.sum( - (np.abs(np.diff(recording.data, axis=0)) > amplitude_thresh_1st), axis=1 + (np.abs(np.diff(recording.data, axis=0)) > amplitude_thresh_1st), + axis=1, ) above_thresh_1st = np.where(artifact_boolean >= nelect_above_1st)[0] # second, find artifacts with large baseline change - big_artifacts = np.zeros((recording.data.shape[1], above_thresh_1st.shape[0])) + big_artifacts = np.zeros( + (recording.data.shape[1], above_thresh_1st.shape[0]) + ) for art_count in np.arange(above_thresh_1st.shape[0]): if above_thresh_1st[art_count] <= local_window: local_min = local_max = above_thresh_1st[art_count] @@ -247,14 +258,18 @@ def _get_artifact_times( half_removal_window_s = removal_window_ms / 1000 * 0.5 if len(artifact_frames) == 0: - recording_interval = np.asarray([[valid_timestamps[0], valid_timestamps[-1]]]) + recording_interval = np.asarray( + [[valid_timestamps[0], valid_timestamps[-1]]] + ) artifact_times_empty = np.asarray([]) print("No artifacts detected.") return recording_interval, artifact_times_empty artifact_intervals = interval_from_inds(artifact_frames) - artifact_intervals_s = np.zeros((len(artifact_intervals), 2), dtype=np.float64) + artifact_intervals_s = np.zeros( + (len(artifact_intervals), 2), dtype=np.float64 + ) for interval_idx, interval in enumerate(artifact_intervals): artifact_intervals_s[interval_idx] = [ valid_timestamps[interval[0]] - half_removal_window_s, From 840d241435bb7d2296f0874804f62e81d781f4e8 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Thu, 1 Jun 2023 12:57:18 -0700 Subject: [PATCH 035/131] Fix linting --- src/spyglass/lfp/lfp_merge.py | 10 +++- src/spyglass/lfp_band/v1/lfp_band.py | 68 ++++++++++++++++++++-------- 2 files changed, 56 insertions(+), 22 deletions(-) diff --git a/src/spyglass/lfp/lfp_merge.py b/src/spyglass/lfp/lfp_merge.py index 33b519616..9491a3c94 100644 --- a/src/spyglass/lfp/lfp_merge.py +++ b/src/spyglass/lfp/lfp_merge.py @@ -29,7 +29,10 @@ class LFPV1(dj.Part): def fetch_nwb(self, *attrs, **kwargs): return fetch_nwb( - self, (AnalysisNwbfile, "analysis_file_abs_path"), *attrs, **kwargs + self, + (AnalysisNwbfile, "analysis_file_abs_path"), + *attrs, + **kwargs, ) def fetch1_dataframe(self, *attrs, **kwargs): @@ -50,7 +53,10 @@ class ImportedLFPV1(dj.Part): def fetch_nwb(self, *attrs, **kwargs): return fetch_nwb( - self, (AnalysisNwbfile, "analysis_file_abs_path"), *attrs, **kwargs + self, + (AnalysisNwbfile, "analysis_file_abs_path"), + *attrs, + **kwargs, ) def fetch1_dataframe(self, *attrs, **kwargs): diff --git a/src/spyglass/lfp_band/v1/lfp_band.py b/src/spyglass/lfp_band/v1/lfp_band.py index eda0ceb81..bf0af09e6 100644 --- a/src/spyglass/lfp_band/v1/lfp_band.py +++ b/src/spyglass/lfp_band/v1/lfp_band.py @@ -113,9 +113,9 @@ def set_lfp_band_electrodes( "added before this function is called" ) # reference_electrode_list - if len(reference_electrode_list) != 1 and len(reference_electrode_list) != len( - electrode_list - ): + if len(reference_electrode_list) != 1 and len( + reference_electrode_list + ) != len(electrode_list): raise ValueError( "reference_electrode_list must contain either 1 or len(electrode_list) elements" ) @@ -142,7 +142,9 @@ def set_lfp_band_electrodes( # insert an entry into the main LFPBandSelectionTable self.insert1(key, skip_duplicates=True) - key["lfp_electrode_group_name"] = lfp_object.fetch1("lfp_electrode_group_name") + key["lfp_electrode_group_name"] = lfp_object.fetch1( + "lfp_electrode_group_name" + ) # iterate through all of the new elements and add them for e, r in zip(electrode_list, ref_list): elect_key = ( @@ -155,7 +157,10 @@ def set_lfp_band_electrodes( ).fetch1("KEY") for item in elect_key: key[item] = elect_key[item] - query = Electrode & {"nwb_file_name": nwb_file_name, "electrode_id": e} + query = Electrode & { + "nwb_file_name": nwb_file_name, + "electrode_id": e, + } key["reference_elect_id"] = r self.LFPBandElectrode().insert1(key, skip_duplicates=True) @@ -193,9 +198,9 @@ def make(self, key): .get_lfp_object({"lfp_id": key["lfp_id"]}) .fetch1("lfp_sampling_rate") ) - interval_list_name, lfp_band_sampling_rate = (LFPBandSelection() & key).fetch1( - "target_interval_list_name", "lfp_band_sampling_rate" - ) + interval_list_name, lfp_band_sampling_rate = ( + LFPBandSelection() & key + ).fetch1("target_interval_list_name", "lfp_band_sampling_rate") valid_times = ( IntervalList() & { @@ -224,14 +229,18 @@ def make(self, key): filter_name, filter_sampling_rate, lfp_band_sampling_rate = ( LFPBandSelection() & key - ).fetch1("filter_name", "filter_sampling_rate", "lfp_band_sampling_rate") + ).fetch1( + "filter_name", "filter_sampling_rate", "lfp_band_sampling_rate" + ) decimation = int(lfp_sampling_rate) // lfp_band_sampling_rate # load in the timestamps timestamps = np.asarray(lfp_object.timestamps) # get the indices of the first timestamp and the last timestamp that are within the valid times - included_indices = interval_list_contains_ind(lfp_band_valid_times, timestamps) + included_indices = interval_list_contains_ind( + lfp_band_valid_times, timestamps + ) # pad the indices by 1 on each side to avoid message in filter_data if included_indices[0] > 0: included_indices[0] -= 1 @@ -247,14 +256,17 @@ def make(self, key): ) # get the indices of the electrodes to be filtered and the references - lfp_band_elect_index = get_electrode_indices(lfp_object, lfp_band_elect_id) + lfp_band_elect_index = get_electrode_indices( + lfp_object, lfp_band_elect_id + ) lfp_band_ref_index = get_electrode_indices(lfp_object, lfp_band_ref_id) # subtract off the references for the selected channels for index, elect_index in enumerate(lfp_band_elect_index): if lfp_band_ref_id[index] != -1: lfp_data[:, elect_index] = ( - lfp_data[:, elect_index] - lfp_data[:, lfp_band_ref_index[index]] + lfp_data[:, elect_index] + - lfp_data[:, lfp_band_ref_index[index]] ) # get the LFP filter that matches the raw data @@ -278,7 +290,9 @@ def make(self, key): # create the analysis nwb file to store the results. lfp_band_file_name = AnalysisNwbfile().create(key["nwb_file_name"]) - lfp_band_file_abspath = AnalysisNwbfile().get_abs_path(lfp_band_file_name) + lfp_band_file_abspath = AnalysisNwbfile().get_abs_path( + lfp_band_file_name + ) # filter the data and write to an the nwb file filtered_data, new_timestamps = FirFilterParameters().filter_data( timestamps, @@ -309,7 +323,8 @@ def make(self, key): ) lfp = pynwb.ecephys.LFP(electrical_series=es) ecephys_module = nwbf.create_processing_module( - name="ecephys", description=f"LFP data processed with {filter_name}" + name="ecephys", + description=f"LFP data processed with {filter_name}", ) ecephys_module.add(lfp) io.write(nwbf) @@ -323,7 +338,10 @@ def make(self, key): # finally, we need to censor the valid times to account for the downsampling if this is the first time we've # downsampled these data key["interval_list_name"] = ( - interval_list_name + " lfp band " + str(lfp_band_sampling_rate) + "Hz" + interval_list_name + + " lfp band " + + str(lfp_band_sampling_rate) + + "Hz" ) tmp_valid_times = ( IntervalList @@ -348,7 +366,9 @@ def make(self, key): # check that the valid times are the same assert np.isclose( tmp_valid_times[0], lfp_band_valid_times - ).all(), "previously saved lfp band times do not match current times" + ).all(), ( + "previously saved lfp band times do not match current times" + ) from spyglass.lfp_band.lfp_band_merge import LFPBandOutput @@ -372,7 +392,9 @@ def fetch1_dataframe(self, *attrs, **kwargs): filtered_nwb = self.fetch_nwb()[0] return pd.DataFrame( filtered_nwb["filtered_data"].data, - index=pd.Index(filtered_nwb["filtered_data"].timestamps, name="time"), + index=pd.Index( + filtered_nwb["filtered_data"].timestamps, name="time" + ), ) def compute_analytic_signal(self, electrode_list: list[int], **kwargs): @@ -395,7 +417,9 @@ def compute_analytic_signal(self, electrode_list: list[int], **kwargs): """ filtered_band = self.fetch_nwb()[0]["filtered_data"] - electrode_index = np.isin(filtered_band.electrodes.data[:], electrode_list) + electrode_index = np.isin( + filtered_band.electrodes.data[:], electrode_list + ) if len(electrode_list) != np.sum(electrode_index): raise ValueError( "Some of the electrodes specified in electrode_list are missing in the current LFPBand table." @@ -425,7 +449,9 @@ def compute_signal_phase( if electrode_list is None: electrode_list = [] - analytic_signal_df = self.compute_analytic_signal(electrode_list, **kwargs) + analytic_signal_df = self.compute_analytic_signal( + electrode_list, **kwargs + ) return pd.DataFrame( np.angle(analytic_signal_df) + np.pi, @@ -451,7 +477,9 @@ def compute_signal_power( if electrode_list is None: electrode_list = [] - analytic_signal_df = self.compute_analytic_signal(electrode_list, **kwargs) + analytic_signal_df = self.compute_analytic_signal( + electrode_list, **kwargs + ) return pd.DataFrame( np.abs(analytic_signal_df) ** 2, From ef0b94f7fa88aae0fcdb7bfc21e1cf42afe808e3 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Thu, 1 Jun 2023 12:58:13 -0700 Subject: [PATCH 036/131] Fix linting --- src/spyglass/lfp_band/lfp_band_merge.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/spyglass/lfp_band/lfp_band_merge.py b/src/spyglass/lfp_band/lfp_band_merge.py index ecc7fec93..d5f459204 100644 --- a/src/spyglass/lfp_band/lfp_band_merge.py +++ b/src/spyglass/lfp_band/lfp_band_merge.py @@ -29,12 +29,17 @@ class LFPBandV1(dj.Part): def fetch_nwb(self, *attrs, **kwargs): return fetch_nwb( - self, (AnalysisNwbfile, "analysis_file_abs_path"), *attrs, **kwargs + self, + (AnalysisNwbfile, "analysis_file_abs_path"), + *attrs, + **kwargs, ) def fetch1_dataframe(self, *attrs, **kwargs): filtered_nwb = self.fetch_nwb()[0] return pd.DataFrame( filtered_nwb["filtered_data"].data, - index=pd.Index(filtered_nwb["filtered_data"].timestamps, name="time"), + index=pd.Index( + filtered_nwb["filtered_data"].timestamps, name="time" + ), ) From d94e6734ecc345499800682d5094173250ece9b2 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Thu, 1 Jun 2023 17:24:20 -0700 Subject: [PATCH 037/131] Refactor LFP artifact to allow for multiple methods --- src/spyglass/lfp/v1/lfp.py | 2 +- src/spyglass/lfp/v1/lfp_artifact.py | 392 ++++-------------- .../lfp/v1/lfp_artifact_MAD_method.py | 198 +++++++++ .../lfp/v1/lfp_artifact_difference_method.py | 256 ++++++++++++ 4 files changed, 533 insertions(+), 315 deletions(-) create mode 100644 src/spyglass/lfp/v1/lfp_artifact_MAD_method.py create mode 100644 src/spyglass/lfp/v1/lfp_artifact_difference_method.py diff --git a/src/spyglass/lfp/v1/lfp.py b/src/spyglass/lfp/v1/lfp.py index 1b33784f8..13d847d77 100644 --- a/src/spyglass/lfp/v1/lfp.py +++ b/src/spyglass/lfp/v1/lfp.py @@ -47,7 +47,7 @@ class LFPV1(dj.Computed): """The filtered LFP data""" definition = """ - -> LFPSelection + -> LFPSelection # the user's selection of LFP data to be filtered --- -> AnalysisNwbfile # the name of the nwb file with the lfp data -> IntervalList # the final interval list of valid times for the data diff --git a/src/spyglass/lfp/v1/lfp_artifact.py b/src/spyglass/lfp/v1/lfp_artifact.py index 99185f70f..2225fa904 100644 --- a/src/spyglass/lfp/v1/lfp_artifact.py +++ b/src/spyglass/lfp/v1/lfp_artifact.py @@ -1,23 +1,21 @@ -import warnings -from functools import reduce -from typing import Union - import datajoint as dj -import numpy as np -from spyglass.common.common_interval import ( - IntervalList, - _union_concat, - interval_from_inds, - interval_list_intersect, -) +from spyglass.common.common_interval import IntervalList from spyglass.lfp.v1.lfp import LFPV1 -from spyglass.utils.nwb_helper_fn import get_valid_intervals +from spyglass.lfp.v1.lfp_artifact_difference_method import ( + difference_artifact_detector, +) +from spyglass.lfp.v1.lfp_artifact_MAD_method import mad_artifact_detector schema = dj.schema("lfp_v1") MIN_LFP_INTERVAL_DURATION = 1.0 # 1 second minimum interval duration +ARTIFACT_DETECTION_ALGORITHMS = { + "difference": difference_artifact_detector, + "mad": mad_artifact_detector, # MAD = median absolute deviation +} + @schema class LFPArtifactDetectionParameters(dj.Manual): @@ -30,23 +28,31 @@ class LFPArtifactDetectionParameters(dj.Manual): def insert_default(self): """Insert the default artifact parameters with an appropriate parameter dict.""" - artifact_params = {} - # all electrodes of sort group - artifact_params["amplitude_thresh_1st"] = 500 # must be None or >= 0 - artifact_params["proportion_above_thresh_1st"] = 0.1 - artifact_params["amplitude_thresh_2nd"] = 1000 # must be None or >= 0 - artifact_params["proportion_above_thresh_1st"] = 0.05 - artifact_params["removal_window_ms"] = 10.0 # in milliseconds - artifact_params["local_window_ms"] = 40.0 # in milliseconds + artifact_params = { + "artifact_detection_algorithm": "difference", + "artifact_detection_algorithm_params": { + "amplitude_thresh_1st": 500, # must be None or >= 0 + "proportion_above_thresh_1st": 0.1, + "amplitude_thresh_2nd": 1000, # must be None or >= 0 + "proportion_above_thresh_2nd": 0.05, + "removal_window_ms": 10.0, # in milliseconds + "local_window_ms": 40.0, # in milliseconds + }, + } + self.insert1(["default", artifact_params], skip_duplicates=True) - artifact_params_none = {} - artifact_params["amplitude_thresh_1st"] = None - artifact_params["proportion_above_thresh_1st"] = None - artifact_params["amplitude_thresh_2nd"] = None - artifact_params["proportion_above_thresh_1st"] = None - artifact_params["removal_window_ms"] = None - artifact_params["local_window_ms"] = None + artifact_params_none = { + "artifact_detection_algorithm": "difference", + "artifact_detection_algorithm_params": { + "amplitude_thresh_1st": None, # must be None or >= 0 + "proportion_above_thresh_1st": None, + "amplitude_thresh_2nd": None, # must be None or >= 0 + "proportion_above_thresh_2nd": None, + "removal_window_ms": None, # in milliseconds + "local_window_ms": None, # in milliseconds + }, + } self.insert1(["none", artifact_params_none], skip_duplicates=True) @@ -57,7 +63,6 @@ class LFPArtifactDetectionSelection(dj.Manual): -> LFPV1 -> LFPArtifactDetectionParameters --- - custom_artifact_detection=0 : tinyint """ @@ -73,50 +78,56 @@ class LFPArtifactDetection(dj.Computed): """ def make(self, key): - if not (LFPArtifactDetectionSelection & key).fetch1( - "custom_artifact_detection" - ): - # get the dict of artifact params associated with this artifact_params_name - artifact_params = (LFPArtifactDetectionParameters & key).fetch1( - "artifact_params" - ) - - # get LFP data - lfp_eseries = (LFPV1() & key).fetch_nwb()[0]["lfp"] + artifact_params = ( + LFPArtifactDetectionParameters + & {"artifact_params_name": key["artifact_params_name"]} + ).fetch1("artifact_params") - artifact_removed_valid_times, artifact_times = _get_artifact_times( - lfp_eseries, - key, - **artifact_params, - ) + artifact_detection_algorithm = artifact_params[ + "ripple_detection_algorithm" + ] + artifact_detection_params = artifact_params[ + "artifact_detection_algorithm_params" + ] - key["artifact_times"] = artifact_times - key["artifact_removed_valid_times"] = artifact_removed_valid_times + # get LFP data + lfp_eseries = (LFPV1() & key).fetch_nwb()[0]["lfp"] + sampling_frequency = (LFPV1() & key).fetch("lfp_sampling_rate")[0] + + ( + artifact_removed_valid_times, + artifact_times, + ) = ARTIFACT_DETECTION_ALGORITHMS[artifact_detection_algorithm]( + lfp_eseries, + **artifact_detection_params, + sampling_frequency=sampling_frequency, + ) - # set up a name for no-artifact times using recording id - # we need some name here for recording_name - key["artifact_removed_interval_list_name"] = ( - key["nwb_file_name"] - + "_" - + key["target_interval_list_name"] - + "_LFP_" - + key["artifact_params_name"] - + "_artifact_removed_valid_times" - ) + key["artifact_times"] = artifact_times + key["artifact_removed_valid_times"] = artifact_removed_valid_times + + # set up a name for no-artifact times using recording id + # we need some name here for recording_name + key["artifact_removed_interval_list_name"] = "_".join( + key["nwb_file_name"], + key["target_interval_list_name"], + "LFP", + key["artifact_params_name"], + "artifact_removed_valid_times", + ) - LFPArtifactRemovedIntervalList.insert1(key, replace=True) + LFPArtifactRemovedIntervalList.insert1(key, replace=True) - # also insert into IntervalList - tmp_key = {} - tmp_key["nwb_file_name"] = key["nwb_file_name"] - tmp_key["interval_list_name"] = key[ - "artifact_removed_interval_list_name" - ] - tmp_key["valid_times"] = key["artifact_removed_valid_times"] - IntervalList.insert1(tmp_key, replace=True) + # also insert into IntervalList + interval_key = { + "nwb_file_name": key["nwb_file_name"], + "interval_list_name": key["artifact_removed_interval_list_name"], + "valid_times": key["artifact_removed_valid_times"], + } + IntervalList.insert1(interval_key, replace=True) - # insert into computed table - self.insert1(key) + # insert into computed table + self.insert1(key) @schema @@ -128,252 +139,5 @@ class LFPArtifactRemovedIntervalList(dj.Manual): --- -> LFPArtifactDetectionSelection artifact_removed_valid_times: longblob - artifact_times: longblob # np array of artifact intervals - """ - - -def _get_artifact_times( - recording: None, - key: None, - amplitude_thresh_1st: Union[float, None] = None, - amplitude_thresh_2nd: Union[float, None] = None, - proportion_above_thresh_1st: float = 1.0, - proportion_above_thresh_2nd: float = 1.0, - removal_window_ms: float = 1.0, - local_window_ms: float = 1.0, -): - """Detects times during which artifacts do and do not occur. - Artifacts are defined as periods where the absolute value of the change in LFP exceeds - amplitude change thresholds on the proportion of channels specified, - with the period extended by the removal_window_ms/2 on each side. amplitude change - threshold values of None are ignored. - - Parameters - ---------- - recording : lfp eseries - zscore_thresh : float, optional - Stdev threshold for exclusion, should be >=0, defaults to None - amplitude_thresh : float, optional - Amplitude (ad units) threshold for exclusion, should be >=0, defaults to None - proportion_above_thresh : float, optional, should be>0 and <=1 - Proportion of electrodes that need to have threshold crossings, defaults to 1 - removal_window_ms : float, optional - Width of the window in milliseconds to mask out per artifact - (window/2 removed on each side of threshold crossing), defaults to 1 ms - - Returns - ------- - artifact_removed_valid_times : np.ndarray - Intervals of valid times where artifacts were not detected, unit: seconds - artifact_intervals : np.ndarray - Intervals in which artifacts are detected (including removal windows), unit: seconds - """ - - valid_timestamps = recording.timestamps - - local_window = np.int(local_window_ms / 2) - - # if both thresholds are None, we skip artifact detection - if amplitude_thresh_1st is None: - recording_interval = np.asarray( - [valid_timestamps[0], valid_timestamps[-1]] - ) - artifact_times_empty = np.asarray([]) - print("Amplitude threshold is None, skipping artifact detection") - return recording_interval, artifact_times_empty - - # verify threshold parameters - ( - amplitude_thresh_1st, - amplitude_thresh_2nd, - proportion_above_thresh_1st, - proportion_above_thresh_2nd, - ) = _check_artifact_thresholds( - amplitude_thresh_1st, - amplitude_thresh_2nd, - proportion_above_thresh_1st, - proportion_above_thresh_2nd, - ) - - # want to detect frames without parallel processing - # compute the number of electrodes that have to be above threshold - nelect_above_1st = np.ceil( - proportion_above_thresh_1st * recording.data.shape[1] - ) - nelect_above_2nd = np.ceil( - proportion_above_thresh_2nd * recording.data.shape[1] - ) - - # find the artifact occurrences using one or both thresholds, across channels - # replace with LFP artifact code - # is this supposed to be indices?? - if amplitude_thresh_1st is not None: - # first find times with large amp change - artifact_boolean = np.sum( - (np.abs(np.diff(recording.data, axis=0)) > amplitude_thresh_1st), - axis=1, - ) - above_thresh_1st = np.where(artifact_boolean >= nelect_above_1st)[0] - - # second, find artifacts with large baseline change - big_artifacts = np.zeros( - (recording.data.shape[1], above_thresh_1st.shape[0]) - ) - for art_count in np.arange(above_thresh_1st.shape[0]): - if above_thresh_1st[art_count] <= local_window: - local_min = local_max = above_thresh_1st[art_count] - else: - local_max = np.max( - recording.data[ - above_thresh_1st[art_count] - - local_window : above_thresh_1st[art_count] - + local_window, - :, - ], - axis=0, - ) - local_min = np.min( - recording.data[ - above_thresh_1st[art_count] - - local_window : above_thresh_1st[art_count] - + local_window, - :, - ], - axis=0, - ) - big_artifacts[:, art_count] = ( - np.abs(local_max - local_min) > amplitude_thresh_2nd - ) - - # sum columns in big artficat, then compare to nelect_above_2nd - above_thresh = above_thresh_1st[ - np.sum(big_artifacts, axis=0) >= nelect_above_2nd - ] - - # artifact_frames = executor.run() - artifact_frames = above_thresh.copy() - print("detected ", artifact_frames.shape[0], " artifacts") - - # turn ms to remove total into s to remove from either side of each detected artifact - half_removal_window_s = removal_window_ms / 1000 * 0.5 - - if len(artifact_frames) == 0: - recording_interval = np.asarray( - [[valid_timestamps[0], valid_timestamps[-1]]] - ) - artifact_times_empty = np.asarray([]) - print("No artifacts detected.") - return recording_interval, artifact_times_empty - - artifact_intervals = interval_from_inds(artifact_frames) - - artifact_intervals_s = np.zeros( - (len(artifact_intervals), 2), dtype=np.float64 - ) - for interval_idx, interval in enumerate(artifact_intervals): - artifact_intervals_s[interval_idx] = [ - valid_timestamps[interval[0]] - half_removal_window_s, - valid_timestamps[interval[1]] + half_removal_window_s, - ] - artifact_intervals_s = reduce(_union_concat, artifact_intervals_s) - - # im not sure how to get the key in this function - sampling_frequency = (LFPV1() & key).fetch("lfp_sampling_rate")[0] - - valid_intervals = get_valid_intervals( - valid_timestamps, sampling_frequency, 1.5, 0.000001 - ) - - # these are artifact times - need to subtract these from valid timestamps - artifact_valid_times = interval_list_intersect( - valid_intervals, artifact_intervals_s - ) - - # note: this is a slow step - list_triggers = [] - for interval in artifact_valid_times: - list_triggers.append( - np.arange( - np.searchsorted(valid_timestamps, interval[0]), - np.searchsorted(valid_timestamps, interval[1]), - ) - ) - - new_array = np.array(np.concatenate(list_triggers)) - - new_timestamps = np.delete(valid_timestamps, new_array) - - artifact_removed_valid_times = get_valid_intervals( - new_timestamps, sampling_frequency, 1.5, 0.000001 - ) - - return artifact_removed_valid_times, artifact_intervals_s - - -def _check_artifact_thresholds( - amplitude_thresh_1st, - amplitude_thresh_2nd, - proportion_above_thresh_1st, - proportion_above_thresh_2nd, -): - """Alerts user to likely unintended parameters. Not an exhaustive verification. - - Parameters - ---------- - amplitude_thresh_1st: float - amplitude_thresh_2nd: float - proportion_above_thresh_1st: float - proportion_above_thresh_2nd: float - - Return - ------ - amplitude_thresh_1st: float - amplitude_thresh_2nd: float - proportion_above_thresh_1st: float - proportion_above_thresh_2nd: float - - Raise - ------ - ValueError: if signal thresholds are negative + artifact_times: longblob # np.array of artifact intervals """ - # amplitude or zscore thresholds should be not negative, as they are applied to an absolute signal - signal_thresholds = [ - t for t in [amplitude_thresh_1st, amplitude_thresh_1st] if t is not None - ] - for t in signal_thresholds: - if t < 0: - raise ValueError("Amplitude thresholds must be >= 0, or None") - - # proportion_above_threshold should be in [0:1] inclusive - if proportion_above_thresh_1st < 0: - warnings.warn( - "Warning: proportion_above_thresh must be a proportion >0 and <=1." - f" Using proportion_above_thresh = 0.01 instead of {str(proportion_above_thresh_1st)}" - ) - proportion_above_thresh_1st = 0.01 - elif proportion_above_thresh_1st > 1: - warnings.warn( - "Warning: proportion_above_thresh must be a proportion >0 and <=1. " - f"Using proportion_above_thresh = 1 instead of {str(proportion_above_thresh_1st)}" - ) - proportion_above_thresh_1st = 1 - # proportion_above_threshold should be in [0:1] inclusive - if proportion_above_thresh_2nd < 0: - warnings.warn( - "Warning: proportion_above_thresh must be a proportion >0 and <=1." - f" Using proportion_above_thresh = 0.01 instead of {str(proportion_above_thresh_2nd)}" - ) - proportion_above_thresh_2nd = 0.01 - elif proportion_above_thresh_2nd > 1: - warnings.warn( - "Warning: proportion_above_thresh must be a proportion >0 and <=1. " - f"Using proportion_above_thresh = 1 instead of {str(proportion_above_thresh_2nd)}" - ) - proportion_above_thresh_2nd = 1 - - return ( - amplitude_thresh_1st, - amplitude_thresh_2nd, - proportion_above_thresh_1st, - proportion_above_thresh_2nd, - ) diff --git a/src/spyglass/lfp/v1/lfp_artifact_MAD_method.py b/src/spyglass/lfp/v1/lfp_artifact_MAD_method.py new file mode 100644 index 000000000..66c3cc6fe --- /dev/null +++ b/src/spyglass/lfp/v1/lfp_artifact_MAD_method.py @@ -0,0 +1,198 @@ +from scipy.stats import median_abs_deviation +from scipy.ndimage import labeled_comprehension, label, find_objects +import numpy as np + + +def mad_artifact_detector( + recording: None, + mad_thresh: float = 6.0, + proportion_above_thresh: float = 1.0, + removal_window_ms: float = 1.0, + sampling_frequency: float = 1000.0, +) -> tuple[np.ndarray, np.ndarray]: + """Detect LFP artifacts using the median absolute deviation method. + + Parameters + ---------- + recording : RecordingExtractor + The recording extractor object + mad_thresh : float, optional + Threshold on the median absolute deviation scaled LFPs, defaults to 6.0 + proportion_above_thresh : float, optional + Proportion of electrodes that need to be above the threshold, defaults to 1.0 + removal_window_ms : float, optional + Width of the window in milliseconds to mask out per artifact + (window/2 removed on each side of threshold crossing), defaults to 1 ms + sampling_frequency : float, optional + Sampling frequency of the recording extractor, defaults to 1000.0 + + Returns + ------- + artifact_removed_valid_times : np.ndarray + Intervals of valid times where artifacts were not detected, unit: seconds + artifact_intervals : np.ndarray + Intervals in which artifacts are detected (including removal windows), unit: seconds + + """ + + timestamps = np.asarray(recording.timestamps) + lfps = np.asarray(recording.data) + + mad = median_abs_deviation(lfps, axis=0, nan_policy="omit", scale="normal") + is_artifact = _is_above_proportion_thresh( + _mad_scale_lfps(lfps, mad), mad_thresh, proportion_above_thresh + ) + + MILLISECONDS_PER_SECOND = 1000.0 + half_removal_window_s = (removal_window_ms / MILLISECONDS_PER_SECOND) * 0.5 + half_removal_window_idx = int(half_removal_window_s * sampling_frequency) + is_artifact = _extend_array_by_window(is_artifact, half_removal_window_idx) + + artifact_intervals_s = _get_time_intervals_from_bool_array( + is_artifact, timestamps + ) + + artifact_removed_valid_times = _get_time_intervals_from_bool_array( + ~is_artifact, timestamps + ) + + return artifact_removed_valid_times, artifact_intervals_s + + +def _mad_scale_lfps(lfps: np.ndarray, mad: np.ndarray) -> np.ndarray: + """Scale LFPs by median absolute deviation. + + Parameters + ---------- + lfps : np.ndarray, shape (n_samples, n_electrodes) + LFPs to scale + mad : np.ndarray, shape (n_electrodes,) + Median absolute deviation of LFPs + + Returns + ------- + mad_scaled_lfps : np.ndarray, shape (n_samples, n_electrodes) + + """ + return np.abs(lfps - np.nanmedian(lfps, axis=0)) / mad + + +def _is_above_proportion_thresh( + mad_scaled_lfps: np.ndarray, + mad_thresh: np.ndarray, + proportion_above_thresh: float = 1.0, +) -> np.ndarray: + """Return whether each sample is above the threshold on the proportion of electrodes. + + Parameters + ---------- + mad_scaled_lfps : np.ndarray, shape (n_samples, n_electrodes) + LFPs scaled by median absolute deviation + mad_thresh : float + Threshold on the median absolute deviation scaled LFPs + proportion_above_thresh : float + Proportion of electrodes that need to be above the threshold + + Returns + ------- + is_above_thresh : np.ndarray, shape (n_samples,) + Whether each sample is above the threshold on the proportion of electrodes + """ + + return ( + np.mean(mad_scaled_lfps > mad_thresh, axis=1) > proportion_above_thresh + ) + + +def _get_time_intervals_from_bool_array( + bool_array: np.ndarray, timestamps: np.ndarray +) -> list[list[float]]: + """Return time intervals from a boolean array. + + Parameters + ---------- + bool_array : np.ndarray, shape (n_samples,) + Boolean array + timestamps : np.ndarray, shape (n_samples,) + Timestamps corresponding to the boolean array + + Returns + ------- + time_intervals : list[list[float]] + Time intervals corresponding to the boolean array + """ + labels, n_labels = label(bool_array) + + try: + return list( + labeled_comprehension( + timestamps, + labels, + range(1, n_labels + 1), + _get_range, + object, + None, + ), + ) + except ValueError: + return [] + + +def _get_range(x: np.ndarray) -> list[float]: + """Return the range of an array. + + Assumes the array is sorted. + + Parameters + ---------- + x : np.ndarray, shape (n_samples,) + Array to get the range of + + Returns + ------- + range : list[float] + Range of the array + """ + try: + return [x[0], x[-1]] + except IndexError: + return [] + + +def _extend_array_by_window( + bool_array: np.ndarray, window_size: int = 0 +) -> np.ndarray: + """Extend a boolean array by a window size on each side. + + Parameters + ---------- + bool_array : np.ndarray, shape (n_samples,) + Boolean array to extend + window_size : int, optional + Window size to extend by on each side, defaults to 0 + + Returns + ------- + new_bool_array : np.ndarray, shape (n_samples,) + Boolean array extended by the window size on each side + """ + labels, _ = label(bool_array) + + n_samples = len(bool_array) + + new_bool_array = np.zeros_like(bool_array) + + for loc in find_objects(labels): + start_ind, stop_ind = loc[0].start, loc[0].stop + + # extend the interval by window_size on each side + start_ind -= window_size + stop_ind += window_size + + # make sure the interval is within the array + start_ind = 0 if start_ind < 0 else start_ind + stop_ind = n_samples if stop_ind >= n_samples else stop_ind + + new_bool_array[start_ind:stop_ind] = True + + return new_bool_array diff --git a/src/spyglass/lfp/v1/lfp_artifact_difference_method.py b/src/spyglass/lfp/v1/lfp_artifact_difference_method.py new file mode 100644 index 000000000..f3d74ab3d --- /dev/null +++ b/src/spyglass/lfp/v1/lfp_artifact_difference_method.py @@ -0,0 +1,256 @@ +import warnings +from functools import reduce +from typing import Union + +import numpy as np + +from spyglass.common.common_interval import ( + _union_concat, + interval_from_inds, + interval_list_intersect, +) +from spyglass.utils.nwb_helper_fn import get_valid_intervals + + +def difference_artifact_detector( + recording: None, + amplitude_thresh_1st: Union[float, None] = None, + amplitude_thresh_2nd: Union[float, None] = None, + proportion_above_thresh_1st: float = 1.0, + proportion_above_thresh_2nd: float = 1.0, + removal_window_ms: float = 1.0, + local_window_ms: float = 1.0, + sampling_frequency: float = 1000.0, +): + """Detects times during which artifacts do and do not occur. + + Artifacts are defined as periods where the absolute value of the change in LFP exceeds + amplitude change thresholds on the proportion of channels specified, + with the period extended by the removal_window_ms/2 on each side. amplitude change + threshold values of None are ignored. + + Parameters + ---------- + recording : lfp eseries + zscore_thresh : float, optional + Stdev threshold for exclusion, should be >=0, defaults to None + amplitude_thresh : float, optional + Amplitude (ad units) threshold for exclusion, should be >=0, defaults to None + proportion_above_thresh : float, optional, should be>0 and <=1 + Proportion of electrodes that need to have threshold crossings, defaults to 1 + removal_window_ms : float, optional + Width of the window in milliseconds to mask out per artifact + (window/2 removed on each side of threshold crossing), defaults to 1 ms + + Returns + ------- + artifact_removed_valid_times : np.ndarray + Intervals of valid times where artifacts were not detected, unit: seconds + artifact_intervals : np.ndarray + Intervals in which artifacts are detected (including removal windows), unit: seconds + """ + + valid_timestamps = recording.timestamps + + local_window = np.int(local_window_ms / 2) + + # if both thresholds are None, we skip artifact detection + if amplitude_thresh_1st is None: + recording_interval = np.asarray( + [valid_timestamps[0], valid_timestamps[-1]] + ) + artifact_times_empty = np.asarray([]) + print("Amplitude threshold is None, skipping artifact detection") + return recording_interval, artifact_times_empty + + # verify threshold parameters + ( + amplitude_thresh_1st, + amplitude_thresh_2nd, + proportion_above_thresh_1st, + proportion_above_thresh_2nd, + ) = _check_artifact_thresholds( + amplitude_thresh_1st, + amplitude_thresh_2nd, + proportion_above_thresh_1st, + proportion_above_thresh_2nd, + ) + + # want to detect frames without parallel processing + # compute the number of electrodes that have to be above threshold + nelect_above_1st = np.ceil( + proportion_above_thresh_1st * recording.data.shape[1] + ) + nelect_above_2nd = np.ceil( + proportion_above_thresh_2nd * recording.data.shape[1] + ) + + # find the artifact occurrences using one or both thresholds, across channels + # replace with LFP artifact code + # is this supposed to be indices?? + if amplitude_thresh_1st is not None: + # first find times with large amp change + artifact_boolean = np.sum( + (np.abs(np.diff(recording.data, axis=0)) > amplitude_thresh_1st), + axis=1, + ) + above_thresh_1st = np.where(artifact_boolean >= nelect_above_1st)[0] + + # second, find artifacts with large baseline change + big_artifacts = np.zeros( + (recording.data.shape[1], above_thresh_1st.shape[0]) + ) + for art_count in np.arange(above_thresh_1st.shape[0]): + if above_thresh_1st[art_count] <= local_window: + local_min = local_max = above_thresh_1st[art_count] + else: + local_max = np.max( + recording.data[ + above_thresh_1st[art_count] + - local_window : above_thresh_1st[art_count] + + local_window, + :, + ], + axis=0, + ) + local_min = np.min( + recording.data[ + above_thresh_1st[art_count] + - local_window : above_thresh_1st[art_count] + + local_window, + :, + ], + axis=0, + ) + big_artifacts[:, art_count] = ( + np.abs(local_max - local_min) > amplitude_thresh_2nd + ) + + # sum columns in big artficat, then compare to nelect_above_2nd + above_thresh = above_thresh_1st[ + np.sum(big_artifacts, axis=0) >= nelect_above_2nd + ] + + artifact_frames = above_thresh.copy() + print("detected ", artifact_frames.shape[0], " artifacts") + + # turn ms to remove total into s to remove from either side of each detected artifact + half_removal_window_s = removal_window_ms / 1000 * 0.5 + + if len(artifact_frames) == 0: + recording_interval = np.asarray( + [[valid_timestamps[0], valid_timestamps[-1]]] + ) + artifact_times_empty = np.asarray([]) + print("No artifacts detected.") + return recording_interval, artifact_times_empty + + artifact_intervals = interval_from_inds(artifact_frames) + + artifact_intervals_s = np.zeros( + (len(artifact_intervals), 2), dtype=np.float64 + ) + for interval_idx, interval in enumerate(artifact_intervals): + artifact_intervals_s[interval_idx] = [ + valid_timestamps[interval[0]] - half_removal_window_s, + valid_timestamps[interval[1]] + half_removal_window_s, + ] + artifact_intervals_s = reduce(_union_concat, artifact_intervals_s) + + valid_intervals = get_valid_intervals( + valid_timestamps, sampling_frequency, 1.5, 0.000001 + ) + + # these are artifact times - need to subtract these from valid timestamps + artifact_valid_times = interval_list_intersect( + valid_intervals, artifact_intervals_s + ) + + # note: this is a slow step + list_triggers = [] + for interval in artifact_valid_times: + list_triggers.append( + np.arange( + np.searchsorted(valid_timestamps, interval[0]), + np.searchsorted(valid_timestamps, interval[1]), + ) + ) + + new_array = np.array(np.concatenate(list_triggers)) + + new_timestamps = np.delete(valid_timestamps, new_array) + + artifact_removed_valid_times = get_valid_intervals( + new_timestamps, sampling_frequency, 1.5, 0.000001 + ) + + return artifact_removed_valid_times, artifact_intervals_s + + +def _check_artifact_thresholds( + amplitude_thresh_1st, + amplitude_thresh_2nd, + proportion_above_thresh_1st, + proportion_above_thresh_2nd, +): + """Alerts user to likely unintended parameters. Not an exhaustive verification. + + Parameters + ---------- + amplitude_thresh_1st: float + amplitude_thresh_2nd: float + proportion_above_thresh_1st: float + proportion_above_thresh_2nd: float + + Return + ------ + amplitude_thresh_1st: float + amplitude_thresh_2nd: float + proportion_above_thresh_1st: float + proportion_above_thresh_2nd: float + + Raise + ------ + ValueError: if signal thresholds are negative + """ + # amplitude or zscore thresholds should be not negative, as they are applied to an absolute signal + signal_thresholds = [ + t for t in [amplitude_thresh_1st, amplitude_thresh_1st] if t is not None + ] + for t in signal_thresholds: + if t < 0: + raise ValueError("Amplitude thresholds must be >= 0, or None") + + # proportion_above_threshold should be in [0:1] inclusive + if proportion_above_thresh_1st < 0: + warnings.warn( + "Warning: proportion_above_thresh must be a proportion >0 and <=1." + f" Using proportion_above_thresh = 0.01 instead of {str(proportion_above_thresh_1st)}" + ) + proportion_above_thresh_1st = 0.01 + elif proportion_above_thresh_1st > 1: + warnings.warn( + "Warning: proportion_above_thresh must be a proportion >0 and <=1. " + f"Using proportion_above_thresh = 1 instead of {str(proportion_above_thresh_1st)}" + ) + proportion_above_thresh_1st = 1 + # proportion_above_threshold should be in [0:1] inclusive + if proportion_above_thresh_2nd < 0: + warnings.warn( + "Warning: proportion_above_thresh must be a proportion >0 and <=1." + f" Using proportion_above_thresh = 0.01 instead of {str(proportion_above_thresh_2nd)}" + ) + proportion_above_thresh_2nd = 0.01 + elif proportion_above_thresh_2nd > 1: + warnings.warn( + "Warning: proportion_above_thresh must be a proportion >0 and <=1. " + f"Using proportion_above_thresh = 1 instead of {str(proportion_above_thresh_2nd)}" + ) + proportion_above_thresh_2nd = 1 + + return ( + amplitude_thresh_1st, + amplitude_thresh_2nd, + proportion_above_thresh_1st, + proportion_above_thresh_2nd, + ) From 46ed9fdd11c6d5418008dbe2171ef847efa2e43c Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Thu, 1 Jun 2023 17:28:02 -0700 Subject: [PATCH 038/131] Change names of modules --- .../{lfp_artifact_MAD_method.py => lfp_artifact_MAD_detection.py} | 0 ..._difference_method.py => lfp_artifact_difference_detection.py} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/spyglass/lfp/v1/{lfp_artifact_MAD_method.py => lfp_artifact_MAD_detection.py} (100%) rename src/spyglass/lfp/v1/{lfp_artifact_difference_method.py => lfp_artifact_difference_detection.py} (100%) diff --git a/src/spyglass/lfp/v1/lfp_artifact_MAD_method.py b/src/spyglass/lfp/v1/lfp_artifact_MAD_detection.py similarity index 100% rename from src/spyglass/lfp/v1/lfp_artifact_MAD_method.py rename to src/spyglass/lfp/v1/lfp_artifact_MAD_detection.py diff --git a/src/spyglass/lfp/v1/lfp_artifact_difference_method.py b/src/spyglass/lfp/v1/lfp_artifact_difference_detection.py similarity index 100% rename from src/spyglass/lfp/v1/lfp_artifact_difference_method.py rename to src/spyglass/lfp/v1/lfp_artifact_difference_detection.py From 33d0d55d92355b3269488759949bf1335d46bf62 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Thu, 1 Jun 2023 17:38:41 -0700 Subject: [PATCH 039/131] Change name of module and sort imports --- src/spyglass/lfp/v1/lfp_artifact.py | 4 ++-- src/spyglass/lfp/v1/lfp_artifact_MAD_detection.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/spyglass/lfp/v1/lfp_artifact.py b/src/spyglass/lfp/v1/lfp_artifact.py index 2225fa904..950132fcf 100644 --- a/src/spyglass/lfp/v1/lfp_artifact.py +++ b/src/spyglass/lfp/v1/lfp_artifact.py @@ -2,10 +2,10 @@ from spyglass.common.common_interval import IntervalList from spyglass.lfp.v1.lfp import LFPV1 -from spyglass.lfp.v1.lfp_artifact_difference_method import ( +from spyglass.lfp.v1.lfp_artifact_difference_detection import ( difference_artifact_detector, ) -from spyglass.lfp.v1.lfp_artifact_MAD_method import mad_artifact_detector +from spyglass.lfp.v1.lfp_artifact_MAD_detection import mad_artifact_detector schema = dj.schema("lfp_v1") diff --git a/src/spyglass/lfp/v1/lfp_artifact_MAD_detection.py b/src/spyglass/lfp/v1/lfp_artifact_MAD_detection.py index 66c3cc6fe..b99640724 100644 --- a/src/spyglass/lfp/v1/lfp_artifact_MAD_detection.py +++ b/src/spyglass/lfp/v1/lfp_artifact_MAD_detection.py @@ -1,6 +1,6 @@ -from scipy.stats import median_abs_deviation -from scipy.ndimage import labeled_comprehension, label, find_objects import numpy as np +from scipy.ndimage import find_objects, label, labeled_comprehension +from scipy.stats import median_abs_deviation def mad_artifact_detector( From 8eee876eea7b672474a1565688e2b3aaef0b04f3 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Fri, 2 Jun 2023 12:02:20 -0700 Subject: [PATCH 040/131] Use a list comp --- .../lfp/v1/lfp_artifact_MAD_detection.py | 47 ++++--------------- 1 file changed, 9 insertions(+), 38 deletions(-) diff --git a/src/spyglass/lfp/v1/lfp_artifact_MAD_detection.py b/src/spyglass/lfp/v1/lfp_artifact_MAD_detection.py index b99640724..d5775653a 100644 --- a/src/spyglass/lfp/v1/lfp_artifact_MAD_detection.py +++ b/src/spyglass/lfp/v1/lfp_artifact_MAD_detection.py @@ -1,13 +1,13 @@ import numpy as np -from scipy.ndimage import find_objects, label, labeled_comprehension +from scipy.ndimage import find_objects, label from scipy.stats import median_abs_deviation def mad_artifact_detector( recording: None, mad_thresh: float = 6.0, - proportion_above_thresh: float = 1.0, - removal_window_ms: float = 1.0, + proportion_above_thresh: float = 0.1, + removal_window_ms: float = 10.0, sampling_frequency: float = 1000.0, ) -> tuple[np.ndarray, np.ndarray]: """Detect LFP artifacts using the median absolute deviation method. @@ -52,11 +52,9 @@ def mad_artifact_detector( is_artifact, timestamps ) - artifact_removed_valid_times = _get_time_intervals_from_bool_array( - ~is_artifact, timestamps - ) + valid_times = _get_time_intervals_from_bool_array(~is_artifact, timestamps) - return artifact_removed_valid_times, artifact_intervals_s + return valid_times, artifact_intervals_s def _mad_scale_lfps(lfps: np.ndarray, mad: np.ndarray) -> np.ndarray: @@ -124,37 +122,10 @@ def _get_time_intervals_from_bool_array( labels, n_labels = label(bool_array) try: - return list( - labeled_comprehension( - timestamps, - labels, - range(1, n_labels + 1), - _get_range, - object, - None, - ), - ) - except ValueError: - return [] - - -def _get_range(x: np.ndarray) -> list[float]: - """Return the range of an array. - - Assumes the array is sorted. - - Parameters - ---------- - x : np.ndarray, shape (n_samples,) - Array to get the range of - - Returns - ------- - range : list[float] - Range of the array - """ - try: - return [x[0], x[-1]] + return [ + timestamps[labels == label_id][[0, -1]] + for label_id in range(1, n_labels + 1) + ] except IndexError: return [] From 4d24c25515ee98f36372fa5a901867e25985d03d Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Fri, 2 Jun 2023 12:02:31 -0700 Subject: [PATCH 041/131] Use int instead of np.int --- src/spyglass/lfp/v1/lfp_artifact_difference_detection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spyglass/lfp/v1/lfp_artifact_difference_detection.py b/src/spyglass/lfp/v1/lfp_artifact_difference_detection.py index f3d74ab3d..1f73d88fd 100644 --- a/src/spyglass/lfp/v1/lfp_artifact_difference_detection.py +++ b/src/spyglass/lfp/v1/lfp_artifact_difference_detection.py @@ -52,7 +52,7 @@ def difference_artifact_detector( valid_timestamps = recording.timestamps - local_window = np.int(local_window_ms / 2) + local_window = int(local_window_ms / 2) # if both thresholds are None, we skip artifact detection if amplitude_thresh_1st is None: From 1bf55fa1526a5ebbe3fd5af2ed41c52e7bae01d5 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Fri, 2 Jun 2023 12:03:33 -0700 Subject: [PATCH 042/131] Add defaults --- src/spyglass/lfp/v1/lfp_artifact.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/spyglass/lfp/v1/lfp_artifact.py b/src/spyglass/lfp/v1/lfp_artifact.py index 950132fcf..ce3ea502c 100644 --- a/src/spyglass/lfp/v1/lfp_artifact.py +++ b/src/spyglass/lfp/v1/lfp_artifact.py @@ -40,7 +40,9 @@ def insert_default(self): }, } - self.insert1(["default", artifact_params], skip_duplicates=True) + self.insert1( + ["default_difference", artifact_params], skip_duplicates=True + ) artifact_params_none = { "artifact_detection_algorithm": "difference", @@ -55,6 +57,16 @@ def insert_default(self): } self.insert1(["none", artifact_params_none], skip_duplicates=True) + artifact_params_mad = { + "artifact_detection_algorithm": "mad", + "artifact_detection_algorithm_params": { + "mad_thresh": 6.0, # akin to z-score standard deviations if the distribution is normal + "proportion_above_thresh": 0.1, + "removal_window_ms": 10.0, # in milliseconds + }, + } + self.insert1(["default_mad", artifact_params_mad], skip_duplicates=True) + @schema class LFPArtifactDetectionSelection(dj.Manual): From 663b28e70b20b8bb57da8c80c08e09d753b50480 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Fri, 2 Jun 2023 14:36:00 -0700 Subject: [PATCH 043/131] Add LFP from common as option --- src/spyglass/lfp/lfp_merge.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/spyglass/lfp/lfp_merge.py b/src/spyglass/lfp/lfp_merge.py index 9491a3c94..c4517cd02 100644 --- a/src/spyglass/lfp/lfp_merge.py +++ b/src/spyglass/lfp/lfp_merge.py @@ -4,6 +4,7 @@ from spyglass.common.common_nwbfile import AnalysisNwbfile from spyglass.lfp.v1.lfp import LFPV1, ImportedLFPV1 from spyglass.utils.dj_helper_fn import fetch_nwb +from spyglass.common.common_ephys import LFP as CommonLFP schema = dj.schema("lfp_merge") @@ -79,11 +80,24 @@ def get_lfp_object(key: dict): lfp_electrode_group_name, interval_list_name, fir_filter_name + class CommonLFP(dj.Part): + """ + Table to pass-through legacy LFP + """ Returns ------- lfp_object The entry or entries in the LFPOutput part table that corresponds to the key + definition = """ + -> PositionOutput + -> CommonLFP + --- + -> IntervalList # the valid intervals for the data + -> FirFilterParameters # the filter used for the data + -> AnalysisNwbfile # the name of the nwb file with the lfp data + lfp_object_id: varchar(40) # the NWB object ID for loading this object from the file + lfp_sampling_rate: float # the sampling rate, in HZ """ # first check if this returns anything from the LFP table query = LFPOutput.LFP & key @@ -91,3 +105,18 @@ def get_lfp_object(key: dict): return LFPV1 & query.fetch("KEY") else: return ImportedLFPV1 & (LFPOutput.ImportedLFP & key).fetch("KEY") + + def fetch_nwb(self, *attrs, **kwargs): + return fetch_nwb( + self, + (AnalysisNwbfile, "analysis_file_abs_path"), + *attrs, + **kwargs, + ) + + def fetch1_dataframe(self, *attrs, **kwargs): + nwb_lfp = self.fetch_nwb()[0] + return pd.DataFrame( + nwb_lfp["lfp"].data, + index=pd.Index(nwb_lfp["lfp"].timestamps, name="time"), + ) From cfd05459651fb70a9f3169ddec0a3a995bb4d9e5 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Fri, 2 Jun 2023 14:36:16 -0700 Subject: [PATCH 044/131] Remove get_lfp_object method --- src/spyglass/lfp/lfp_merge.py | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/src/spyglass/lfp/lfp_merge.py b/src/spyglass/lfp/lfp_merge.py index c4517cd02..ee049b742 100644 --- a/src/spyglass/lfp/lfp_merge.py +++ b/src/spyglass/lfp/lfp_merge.py @@ -67,28 +67,11 @@ def fetch1_dataframe(self, *attrs, **kwargs): index=pd.Index(nwb_lfp["lfp"].timestamps, name="time"), ) - @staticmethod - def get_lfp_object(key: dict): - """Returns the lfp object corresponding to the key - - Parameters - ---------- - key : dict - A dictionary containing some combination of - uuid, - nwb_file_name, - lfp_electrode_group_name, - interval_list_name, - fir_filter_name class CommonLFP(dj.Part): """ Table to pass-through legacy LFP """ - Returns - ------- - lfp_object - The entry or entries in the LFPOutput part table that corresponds to the key definition = """ -> PositionOutput -> CommonLFP @@ -99,12 +82,6 @@ class CommonLFP(dj.Part): lfp_object_id: varchar(40) # the NWB object ID for loading this object from the file lfp_sampling_rate: float # the sampling rate, in HZ """ - # first check if this returns anything from the LFP table - query = LFPOutput.LFP & key - if query is not None: - return LFPV1 & query.fetch("KEY") - else: - return ImportedLFPV1 & (LFPOutput.ImportedLFP & key).fetch("KEY") def fetch_nwb(self, *attrs, **kwargs): return fetch_nwb( From 22ebe2e828721047c0004e7db1891da8a27fcd94 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Fri, 2 Jun 2023 14:45:48 -0700 Subject: [PATCH 045/131] Fix linting --- src/spyglass/lfp/v1/lfp.py | 5 +++- src/spyglass/ripple/v1/__init__.py | 6 ++++- src/spyglass/ripple/v1/ripple.py | 37 ++++++++++++++++++++++-------- 3 files changed, 37 insertions(+), 11 deletions(-) diff --git a/src/spyglass/lfp/v1/lfp.py b/src/spyglass/lfp/v1/lfp.py index 784b2e74f..13d847d77 100644 --- a/src/spyglass/lfp/v1/lfp.py +++ b/src/spyglass/lfp/v1/lfp.py @@ -227,7 +227,10 @@ def create_lfp_electrode_group( """ # remove the session and then recreate the session and Electrode list # check to see if the user allowed the deletion - key = {"nwb_file_name": nwb_file_name, "lfp_electrode_group_name": group_name} + key = { + "nwb_file_name": nwb_file_name, + "lfp_electrode_group_name": group_name, + } LFPElectrodeGroup().insert1(key, skip_duplicates=True) # TODO: do this in a better way diff --git a/src/spyglass/ripple/v1/__init__.py b/src/spyglass/ripple/v1/__init__.py index 5a2d817d8..0e7b84b84 100644 --- a/src/spyglass/ripple/v1/__init__.py +++ b/src/spyglass/ripple/v1/__init__.py @@ -1 +1,5 @@ -from spyglass.ripple.v1 import RippleLFPSelection, RippleParameters, RippleTimesV1 +from spyglass.ripple.v1 import ( + RippleLFPSelection, + RippleParameters, + RippleTimesV1, +) diff --git a/src/spyglass/ripple/v1/ripple.py b/src/spyglass/ripple/v1/ripple.py index 21998cd86..655afc5ab 100644 --- a/src/spyglass/ripple/v1/ripple.py +++ b/src/spyglass/ripple/v1/ripple.py @@ -22,9 +22,13 @@ } -def interpolate_to_new_time(df, new_time, upsampling_interpolation_method="linear"): +def interpolate_to_new_time( + df, new_time, upsampling_interpolation_method="linear" +): old_time = df.index - new_index = pd.Index(np.unique(np.concatenate((old_time, new_time))), name="time") + new_index = pd.Index( + np.unique(np.concatenate((old_time, new_time))), name="time" + ) return ( df.reindex(index=new_index) .interpolate(method=upsampling_interpolation_method) @@ -162,7 +166,9 @@ def make(self, key): # Insert into analysis nwb file nwb_analysis_file = AnalysisNwbfile() - key["analysis_file_name"] = nwb_analysis_file.create(key["nwb_file_name"]) + key["analysis_file_name"] = nwb_analysis_file.create( + key["nwb_file_name"] + ) key["ripple_times_object_id"] = nwb_analysis_file.add_nwb_object( analysis_file_name=key["analysis_file_name"], nwb_object=ripple_times, @@ -223,7 +229,9 @@ def get_ripple_lfps_and_position_info(key): lfp_key = copy.deepcopy(key) del lfp_key["interval_list_name"] ripple_lfp_nwb = (LFPBand & lfp_key).fetch_nwb()[0] - ripple_lfp_electrodes = ripple_lfp_nwb["filtered_data"].electrodes.data[:] + ripple_lfp_electrodes = ripple_lfp_nwb["filtered_data"].electrodes.data[ + : + ] elec_mask = np.full_like(ripple_lfp_electrodes, 0, dtype=bool) elec_mask[ [ @@ -234,7 +242,9 @@ def get_ripple_lfps_and_position_info(key): ] = True ripple_lfp = pd.DataFrame( ripple_lfp_nwb["filtered_data"].data, - index=pd.Index(ripple_lfp_nwb["filtered_data"].timestamps, name="time"), + index=pd.Index( + ripple_lfp_nwb["filtered_data"].timestamps, name="time" + ), ) sampling_frequency = ripple_lfp_nwb["lfp_band_sampling_rate"] @@ -242,7 +252,10 @@ def get_ripple_lfps_and_position_info(key): position_valid_times = ( IntervalList - & {"nwb_file_name": nwb_file_name, "interval_list_name": interval_list_name} + & { + "nwb_file_name": nwb_file_name, + "interval_list_name": interval_list_name, + } ).fetch1("valid_times") position_info = ( @@ -291,7 +304,9 @@ def get_Kay_ripple_consensus_trace( ) ripple_consensus_trace = np.sum(ripple_consensus_trace**2, axis=1) ripple_consensus_trace[not_null] = gaussian_smooth( - ripple_consensus_trace[not_null], smoothing_sigma, sampling_frequency + ripple_consensus_trace[not_null], + smoothing_sigma, + sampling_frequency, ) return pd.DataFrame( np.sqrt(ripple_consensus_trace), index=ripple_filtered_lfps.index @@ -325,7 +340,9 @@ def plot_ripple_consensus_trace( color="lightgrey", ) ax.set_xlabel("Time [s]") - ax.set_xlim((time_slice.start - start_offset, time_slice.stop - start_offset)) + ax.set_xlim( + (time_slice.start - start_offset, time_slice.stop - start_offset) + ) @staticmethod def plot_ripple( @@ -357,6 +374,8 @@ def plot_ripple( color="lightgrey", ) ax.set_ylim((-1, n_lfps)) - ax.set_xlim((time_slice.start - start_offset, time_slice.stop - start_offset)) + ax.set_xlim( + (time_slice.start - start_offset, time_slice.stop - start_offset) + ) ax.set_ylabel("LFPs") ax.set_xlabel("Time [s]") From 0975253106b261b13990a03f679578dae35bfa24 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Fri, 2 Jun 2023 14:47:40 -0700 Subject: [PATCH 046/131] Fix output level --- src/spyglass/ripple/ripple_merge.py | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/spyglass/ripple/ripple_merge.py b/src/spyglass/ripple/ripple_merge.py index 9ac973067..2077a520f 100644 --- a/src/spyglass/ripple/ripple_merge.py +++ b/src/spyglass/ripple/ripple_merge.py @@ -26,14 +26,17 @@ class RippleTimesV1(dj.Part): ripple_times_object_id : varchar(40) """ - def fetch_nwb(self, *attrs, **kwargs): - return fetch_nwb( - self, (AnalysisNwbfile, "analysis_file_abs_path"), *attrs, **kwargs - ) - - def fetch1_dataframe(self): - """Convenience function for returning the marks in a readable format""" - return self.fetch_dataframe()[0] - - def fetch_dataframe(self): - return [data["ripple_times"] for data in self.fetch_nwb()] + def fetch_nwb(self, *attrs, **kwargs): + return fetch_nwb( + self, + (AnalysisNwbfile, "analysis_file_abs_path"), + *attrs, + **kwargs, + ) + + def fetch1_dataframe(self): + """Convenience function for returning the marks in a readable format""" + return self.fetch_dataframe()[0] + + def fetch_dataframe(self): + return [data["ripple_times"] for data in self.fetch_nwb()] From 7c3598843e65d20de945a209474bc86725d448fd Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Fri, 2 Jun 2023 14:53:03 -0700 Subject: [PATCH 047/131] Update for LFPBand versioning --- src/spyglass/ripple/v1/ripple.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/spyglass/ripple/v1/ripple.py b/src/spyglass/ripple/v1/ripple.py index 655afc5ab..ff3620e9f 100644 --- a/src/spyglass/ripple/v1/ripple.py +++ b/src/spyglass/ripple/v1/ripple.py @@ -10,7 +10,8 @@ from spyglass.common import IntervalList # noqa from spyglass.common.common_nwbfile import AnalysisNwbfile -from spyglass.lfp_band.v1.lfp_band import LFPBand, LFPBandSelection +from spyglass.lfp_band.lfp_band_merge import LFPBandOutput +from spyglass.lfp_band.v1.lfp_band import LFPBandSelection from spyglass.position import PositionOutput from spyglass.utils.dj_helper_fn import fetch_nwb @@ -50,7 +51,7 @@ class RippleLFPElectrode(dj.Part): """ def insert1(self, key, **kwargs): - filter_name = (LFPBand & key).fetch1("filter_name") + filter_name = (LFPBandOutput.LFPBandV1 & key).fetch1("filter_name") if "ripple" not in filter_name.lower(): raise UserWarning("Please use a ripple filter") super().insert1(key, **kwargs) @@ -228,7 +229,7 @@ def get_ripple_lfps_and_position_info(key): # warn/validate that there is only one wire per electrode lfp_key = copy.deepcopy(key) del lfp_key["interval_list_name"] - ripple_lfp_nwb = (LFPBand & lfp_key).fetch_nwb()[0] + ripple_lfp_nwb = (LFPBandOutput.LFPBandV1 & lfp_key).fetch_nwb()[0] ripple_lfp_electrodes = ripple_lfp_nwb["filtered_data"].electrodes.data[ : ] From 3865ee67d7b508951eb5fc45a89db9f7370f0849 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Fri, 2 Jun 2023 16:33:02 -0700 Subject: [PATCH 048/131] Revert "Remove get_lfp_object method" This reverts commit cfd05459651fb70a9f3169ddec0a3a995bb4d9e5. --- src/spyglass/lfp/lfp_merge.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/spyglass/lfp/lfp_merge.py b/src/spyglass/lfp/lfp_merge.py index ee049b742..c84a9f170 100644 --- a/src/spyglass/lfp/lfp_merge.py +++ b/src/spyglass/lfp/lfp_merge.py @@ -97,3 +97,29 @@ def fetch1_dataframe(self, *attrs, **kwargs): nwb_lfp["lfp"].data, index=pd.Index(nwb_lfp["lfp"].timestamps, name="time"), ) + + @staticmethod + def get_lfp_object(key: dict): + """Returns the lfp object corresponding to the key + + Parameters + ---------- + key : dict + A dictionary containing some combination of + uuid, + nwb_file_name, + lfp_electrode_group_name, + interval_list_name, + fir_filter_name + + Returns + ------- + lfp_object + The entry or entries in the LFPOutput part table that corresponds to the key + """ + # first check if this returns anything from the LFP table + lfp_object = LFPOutput.LFP & key + if lfp_object is not None: + return LFP & lfp_object.fetch("KEY") + else: + return ImportedLFP & (LFPOutput.ImportedLFP & key).fetch("KEY") From 113b69c0416d2f8cb2f0cebaa97d65af09fabf07 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Fri, 2 Jun 2023 16:37:50 -0700 Subject: [PATCH 049/131] Fix table names --- src/spyglass/lfp/lfp_merge.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/spyglass/lfp/lfp_merge.py b/src/spyglass/lfp/lfp_merge.py index c84a9f170..66229714b 100644 --- a/src/spyglass/lfp/lfp_merge.py +++ b/src/spyglass/lfp/lfp_merge.py @@ -21,7 +21,7 @@ class LFPOutput(dj.Manual): class LFPV1(dj.Part): definition = """ - -> LFPOutput + -> master -> LFPV1 --- -> AnalysisNwbfile @@ -45,7 +45,7 @@ def fetch1_dataframe(self, *attrs, **kwargs): class ImportedLFPV1(dj.Part): definition = """ - -> LFPOutput + -> master -> ImportedLFPV1 --- -> AnalysisNwbfile @@ -73,7 +73,7 @@ class CommonLFP(dj.Part): """ definition = """ - -> PositionOutput + -> master -> CommonLFP --- -> IntervalList # the valid intervals for the data @@ -120,6 +120,6 @@ def get_lfp_object(key: dict): # first check if this returns anything from the LFP table lfp_object = LFPOutput.LFP & key if lfp_object is not None: - return LFP & lfp_object.fetch("KEY") + return LFPV1 & lfp_object.fetch("KEY") else: - return ImportedLFP & (LFPOutput.ImportedLFP & key).fetch("KEY") + return ImportedLFPV1 & (LFPOutput.ImportedLFP & key).fetch("KEY") From 8758b636bb6377288fbaaa58f421322a7a500ae1 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Fri, 2 Jun 2023 16:40:55 -0700 Subject: [PATCH 050/131] Fix imports --- src/spyglass/lfp/lfp_merge.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/spyglass/lfp/lfp_merge.py b/src/spyglass/lfp/lfp_merge.py index 66229714b..8b9d6a721 100644 --- a/src/spyglass/lfp/lfp_merge.py +++ b/src/spyglass/lfp/lfp_merge.py @@ -1,10 +1,12 @@ import datajoint as dj import pandas as pd +from spyglass.common.common_ephys import LFP as CommonLFP # noqa: F401 +from spyglass.common.common_filter import FirFilterParameters # noqa: F401 +from spyglass.common.common_interval import IntervalList # noqa: F401 from spyglass.common.common_nwbfile import AnalysisNwbfile from spyglass.lfp.v1.lfp import LFPV1, ImportedLFPV1 from spyglass.utils.dj_helper_fn import fetch_nwb -from spyglass.common.common_ephys import LFP as CommonLFP schema = dj.schema("lfp_merge") From 96aa54ec7c55a38864b55f65d8815f9d08500338 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Mon, 5 Jun 2023 13:13:16 -0700 Subject: [PATCH 051/131] Update src/spyglass/ripple/v1/ripple.py Co-authored-by: Daniel Gramling <57648931+dpeg22@users.noreply.github.com> --- src/spyglass/ripple/v1/ripple.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spyglass/ripple/v1/ripple.py b/src/spyglass/ripple/v1/ripple.py index ff3620e9f..fe5fec322 100644 --- a/src/spyglass/ripple/v1/ripple.py +++ b/src/spyglass/ripple/v1/ripple.py @@ -136,7 +136,7 @@ class RippleTimesV1(dj.Computed): definition = """ -> RippleParameters -> RippleLFPSelection - -> IntervalPositionInfo + -> PositionOutput --- -> AnalysisNwbfile ripple_times_object_id : varchar(40) From 7c1aadae720072b599d07c75913676d8b869ded0 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Mon, 5 Jun 2023 13:13:27 -0700 Subject: [PATCH 052/131] Update src/spyglass/ripple/v1/ripple.py Co-authored-by: Daniel Gramling <57648931+dpeg22@users.noreply.github.com> --- src/spyglass/ripple/v1/ripple.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/spyglass/ripple/v1/ripple.py b/src/spyglass/ripple/v1/ripple.py index fe5fec322..ad5e5d013 100644 --- a/src/spyglass/ripple/v1/ripple.py +++ b/src/spyglass/ripple/v1/ripple.py @@ -259,13 +259,9 @@ def get_ripple_lfps_and_position_info(key): } ).fetch1("valid_times") + pos_key = {k: v for k, v in key.items() if k in list(PositionOutput.fetch().dtype.fields.keys())} position_info = ( - PositionOutput() - & { - "nwb_file_name": nwb_file_name, - "interval_list_name": interval_list_name, - "position_info_param_name": position_info_param_name, - } + PositionOutput() & pos_key ).fetch1_dataframe() position_info = pd.concat( From e913c31e5e415299aa84ae2b85b4ce7849f1a37e Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Mon, 5 Jun 2023 13:13:42 -0700 Subject: [PATCH 053/131] Update src/spyglass/ripple/v1/ripple.py Co-authored-by: Daniel Gramling <57648931+dpeg22@users.noreply.github.com> --- src/spyglass/ripple/v1/ripple.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/spyglass/ripple/v1/ripple.py b/src/spyglass/ripple/v1/ripple.py index ad5e5d013..13730a2c1 100644 --- a/src/spyglass/ripple/v1/ripple.py +++ b/src/spyglass/ripple/v1/ripple.py @@ -234,13 +234,11 @@ def get_ripple_lfps_and_position_info(key): : ] elec_mask = np.full_like(ripple_lfp_electrodes, 0, dtype=bool) - elec_mask[ - [ - ind - for ind, elec in enumerate(ripple_lfp_electrodes) - if elec in electrode_keys - ] - ] = True + valid_elecs = [elec for elec in electrode_keys if elec in ripple_lfp_electrodes] + lfp_indexed_elec_ids = get_electrode_indices( + ripple_lfp_nwb["filtered_data"], valid_elecs + ) + elec_mask[lfp_indexed_elec_ids] = True ripple_lfp = pd.DataFrame( ripple_lfp_nwb["filtered_data"].data, index=pd.Index( From b6be92a614a488dbe823a04d43c5a4631a81fb2c Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Mon, 5 Jun 2023 13:13:56 -0700 Subject: [PATCH 054/131] Update src/spyglass/ripple/v1/ripple.py Co-authored-by: Daniel Gramling <57648931+dpeg22@users.noreply.github.com> --- src/spyglass/ripple/v1/ripple.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spyglass/ripple/v1/ripple.py b/src/spyglass/ripple/v1/ripple.py index 13730a2c1..6d0fcd5fb 100644 --- a/src/spyglass/ripple/v1/ripple.py +++ b/src/spyglass/ripple/v1/ripple.py @@ -267,7 +267,7 @@ def get_ripple_lfps_and_position_info(key): position_info.loc[slice(valid_time[0], valid_time[1])] for valid_time in position_valid_times ], - axis=1, + axis=0, ) interval_ripple_lfps = pd.concat( [ From 1eb0341c725ea93c28d0c254402c0ffd5362f070 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Mon, 5 Jun 2023 13:14:02 -0700 Subject: [PATCH 055/131] Update src/spyglass/ripple/v1/ripple.py Co-authored-by: Daniel Gramling <57648931+dpeg22@users.noreply.github.com> --- src/spyglass/ripple/v1/ripple.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spyglass/ripple/v1/ripple.py b/src/spyglass/ripple/v1/ripple.py index 6d0fcd5fb..f593cc0ba 100644 --- a/src/spyglass/ripple/v1/ripple.py +++ b/src/spyglass/ripple/v1/ripple.py @@ -274,7 +274,7 @@ def get_ripple_lfps_and_position_info(key): ripple_lfp.loc[slice(valid_time[0], valid_time[1])] for valid_time in position_valid_times ], - axis=1, + axis=0, ) position_info = interpolate_to_new_time( From 360e356b7edd5ac44e3fe4ba029c193a80b89dde Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Mon, 5 Jun 2023 13:20:27 -0700 Subject: [PATCH 056/131] Fix linting --- src/spyglass/ripple/v1/ripple.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/spyglass/ripple/v1/ripple.py b/src/spyglass/ripple/v1/ripple.py index f593cc0ba..fb57142cb 100644 --- a/src/spyglass/ripple/v1/ripple.py +++ b/src/spyglass/ripple/v1/ripple.py @@ -234,7 +234,9 @@ def get_ripple_lfps_and_position_info(key): : ] elec_mask = np.full_like(ripple_lfp_electrodes, 0, dtype=bool) - valid_elecs = [elec for elec in electrode_keys if elec in ripple_lfp_electrodes] + valid_elecs = [ + elec for elec in electrode_keys if elec in ripple_lfp_electrodes + ] lfp_indexed_elec_ids = get_electrode_indices( ripple_lfp_nwb["filtered_data"], valid_elecs ) @@ -257,10 +259,12 @@ def get_ripple_lfps_and_position_info(key): } ).fetch1("valid_times") - pos_key = {k: v for k, v in key.items() if k in list(PositionOutput.fetch().dtype.fields.keys())} - position_info = ( - PositionOutput() & pos_key - ).fetch1_dataframe() + pos_key = { + k: v + for k, v in key.items() + if k in list(PositionOutput.fetch().dtype.fields.keys()) + } + position_info = (PositionOutput() & pos_key).fetch1_dataframe() position_info = pd.concat( [ From cc8f5915fc63e3b82a9f123096c918bac3f6f058 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Mon, 5 Jun 2023 13:28:41 -0700 Subject: [PATCH 057/131] Fix missing import --- src/spyglass/ripple/v1/ripple.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/spyglass/ripple/v1/ripple.py b/src/spyglass/ripple/v1/ripple.py index fb57142cb..5da02717e 100644 --- a/src/spyglass/ripple/v1/ripple.py +++ b/src/spyglass/ripple/v1/ripple.py @@ -14,6 +14,7 @@ from spyglass.lfp_band.v1.lfp_band import LFPBandSelection from spyglass.position import PositionOutput from spyglass.utils.dj_helper_fn import fetch_nwb +from spyglass.utils.nwb_helper_fn import get_electrode_indices schema = dj.schema("ripple_v1") From 05b17d19e6568f73c64643019a29e13f9ab4b1d5 Mon Sep 17 00:00:00 2001 From: Chris Brozdowski Date: Thu, 22 Jun 2023 15:34:24 -0500 Subject: [PATCH 058/131] Merge table class (#556) * Merge table class * lfp_merge cleanup. Populate error specificity * Add merge secondary key * Add `source` to `merge_view` --- docs/src/misc/merge_tables.md | 152 +++++++++ src/spyglass/common/common_ephys.py | 3 +- src/spyglass/lfp/lfp_merge.py | 98 ++---- src/spyglass/lfp/v1/lfp.py | 81 +++-- src/spyglass/utils/dj_helper_fn.py | 10 +- src/spyglass/utils/dj_merge_tables.py | 425 ++++++++++++++++++++++++++ 6 files changed, 658 insertions(+), 111 deletions(-) create mode 100644 docs/src/misc/merge_tables.md create mode 100644 src/spyglass/utils/dj_merge_tables.py diff --git a/docs/src/misc/merge_tables.md b/docs/src/misc/merge_tables.md new file mode 100644 index 000000000..8381062f8 --- /dev/null +++ b/docs/src/misc/merge_tables.md @@ -0,0 +1,152 @@ +# Merge Tables + +## Why + +A pipeline may diverge when we want to process the same data in different ways. +Merge Tables allow us to join divergent pipelines together, and unify +downstream processing steps. For a more in depth discussion, please refer to +[this notebook](https://github.com/ttngu207/db-programming-with-datajoint/blob/master/notebooks/pipelines_merging_design_master_part.ipynb) +and related discussions [here](https://github.com/datajoint/datajoint-python/issues/151) +and [here](https://github.com/LorenFrankLab/spyglass/issues/469). + +**Note:** Deleting entries upstream of Merge Tables will throw errors related to +deleteing a part entry before the master. To circumvent this, you can add +`force_parts=True` to the +[`delete` function](https://datajoint.com/docs/core/datajoint-python/0.14/api/datajoint/__init__/#datajoint.table.Table.delete) +call, but this will leave and orphaned primary key in the master. Instead, use +`spyglass.utils.dj_merge_tables.delete_downstream_merge` to delete master/part pairs. + +## What + +A Merge Table is fundametally a master table with one part for each divergent +pipeline. By convention... + +1. The master table has one primary key, `merge_id`, a + [UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier), and one + secondary attribute, `source`, which gives the part table name. Both are + managed with the custom `insert` function of this class. + +2. Each part table has inherits the final table in its respective pipeline, and + shares the same name as this table. + +```python +from spyglass.utils.dj_merge_tables import Merge + +@schema +class MergeTable(Merge): + definition = """ + merge_id: uuid + --- + source: varchar(32) + """ + + class One(dj.Part): + definition = """ + -> master + --- + -> One + """ + + class Two(dj.Part): + definition = """ + -> master + --- + -> Two + """ +``` + +## How + +The Merge class in Spyglass's utils is a subclass of DataJoint's +[Manual Table](https://datajoint.com/docs/core/design/tables/tiers/#data-entry-lookup-and-manual) +and adds functions to make the awkwardness of part tables more manageable. These +functions are described in the API section, under `utils.dj_merge_tables`. + +One quirk of these utilites is that they take restrictions as agruments, rather +than with operators. So `Table & "field='value'"` becomes +`MergeTable.merge_view(restriction="field='value'"`)`. This is because +`merge_view` is a `Union` rather than a true Table. + +## Example + +First, we'll import various items related to the LFP Merge Table... + +```python +from spyglass.utils.dj_merge_tables import delete_downstream_merge, Merge +from spyglass.common.common_ephys import LFP as CommonLFP # Upstream 1 +from spyglass.lfp.lfp_merge import LFPOutput # Merge Table +from spyglass.lfp.v1.lfp import LFPV1 # Upstream 2 +``` + +Merge Tables have multiple custom methods that begin with `merge`. `help` can +show us the docstring of each + +```python +merge_methods=[d for d in dir(Merge) if d.startswith('merge')] +help(getattr(Merge,merge_methods[-1])) +``` + +We'll use this example to explore populating both `LFPV1` and the `LFPOutput` +Merge Table. + +```python +nwb_file_dict = { # We'll use this later when fetching from the Merge Table + "nwb_file_name": "tonks20211103_.nwb", +} +lfpv1_key = { + **nwb_file_dict, + "lfp_electrode_group_name": "CA1_test", + "target_interval_list_name": "test interval2", + "filter_name": "LFP 0-400 Hz", + "filter_sampling_rate": 30000, +} +LFPV1.populate(lfpv1_key) # Also populates LFPOutput +``` + +The Merge Table can also be populated with keys from `common_ephys.LFP`. + +```python +common_keys = CommonLFP.fetch(limit=3, as_dict=True) +LFPOutput.insert1(common_keys[0], skip_duplicates=True) +LFPOutput.insert(common_keys[1:], skip_duplicates=True) +``` + +`merge_view` shows a union of the master and all part tables. + +```python +LFPOutput.merge_view() +LFPOutput.merge_view(restriction=lfpv1_key) +``` + +UUIDs help retain unique entries across all part tables. We can fetch NWB file +by referencing this or other features. + +```python +uuid_key = LFPOutput.fetch(limit=1, as_dict=True)[-1] +restrict = LFPOutput & uuid_key +result1 = restrict.fetch_nwb() + +nwb_key = LFPOutput.merge_restrict(nwb_file_dict).fetch(as_dict=True)[0] +result2 = (LFPOutput & nwb_key).fetch_nwb() +``` + +When deleting from Merge Tables, we can either... + +1. delete from the Merge Table itself with `merge_delete`_parent, deleting both + the master and part. +2. use `merge_delete_parent` to delete from the parent sources, getting rid of + the entries in the source table they came from. +3. use `delete_downstream_merge` to find Merge Tables downstream and get rid + full entries, avoiding orphaned master table entries. + +The two latter cases can be destructive, so we include an extra layer of +protection with `dry_run`. When true (by default), these functions return +a list of tables with the entries that would otherwise be deleted. + +```python +LFPOutput.merge_delete(common_keys[0]) # Delete from merge table +LFPOutput.merge_delete_parent(restriction=nwb_file_dict, dry_run=True) +delete_downstream_merge( + table=CommonLFP, restriction=common_keys[0], dry_run=True +) +``` diff --git a/src/spyglass/common/common_ephys.py b/src/spyglass/common/common_ephys.py index e05acd56e..5ca0af03c 100644 --- a/src/spyglass/common/common_ephys.py +++ b/src/spyglass/common/common_ephys.py @@ -241,7 +241,8 @@ def make(self, key): assert isinstance(rawdata, pynwb.ecephys.ElectricalSeries) except (ValueError, AssertionError): warnings.warn( - f"Unable to get acquisition object in: {nwb_file_abspath}" + f"Unable to get acquisition object in: {nwb_file_abspath}\n\t" + + f"Skipping entry in {self.full_table_name}" ) return if rawdata.rate is not None: diff --git a/src/spyglass/lfp/lfp_merge.py b/src/spyglass/lfp/lfp_merge.py index 8b9d6a721..ba6de68ac 100644 --- a/src/spyglass/lfp/lfp_merge.py +++ b/src/spyglass/lfp/lfp_merge.py @@ -7,99 +7,42 @@ from spyglass.common.common_nwbfile import AnalysisNwbfile from spyglass.lfp.v1.lfp import LFPV1, ImportedLFPV1 from spyglass.utils.dj_helper_fn import fetch_nwb +from spyglass.utils.dj_merge_tables import Merge schema = dj.schema("lfp_merge") @schema -class LFPOutput(dj.Manual): +class LFPOutput(Merge): definition = """ - lfp_id: uuid + merge_id: uuid --- - source: varchar(40) - version: int - + source: varchar(32) """ class LFPV1(dj.Part): definition = """ -> master - -> LFPV1 --- - -> AnalysisNwbfile - lfp_object_id: varchar(40) + -> LFPV1 """ - def fetch_nwb(self, *attrs, **kwargs): - return fetch_nwb( - self, - (AnalysisNwbfile, "analysis_file_abs_path"), - *attrs, - **kwargs, - ) - - def fetch1_dataframe(self, *attrs, **kwargs): - nwb_lfp = self.fetch_nwb()[0] - return pd.DataFrame( - nwb_lfp["lfp"].data, - index=pd.Index(nwb_lfp["lfp"].timestamps, name="time"), - ) - class ImportedLFPV1(dj.Part): definition = """ -> master - -> ImportedLFPV1 --- - -> AnalysisNwbfile - lfp_object_id: varchar(40) + -> ImportedLFPV1 """ - def fetch_nwb(self, *attrs, **kwargs): - return fetch_nwb( - self, - (AnalysisNwbfile, "analysis_file_abs_path"), - *attrs, - **kwargs, - ) - - def fetch1_dataframe(self, *attrs, **kwargs): - nwb_lfp = self.fetch_nwb()[0] - return pd.DataFrame( - nwb_lfp["lfp"].data, - index=pd.Index(nwb_lfp["lfp"].timestamps, name="time"), - ) - class CommonLFP(dj.Part): - """ - Table to pass-through legacy LFP - """ + """Table to pass-through legacy LFP""" definition = """ -> master - -> CommonLFP --- - -> IntervalList # the valid intervals for the data - -> FirFilterParameters # the filter used for the data - -> AnalysisNwbfile # the name of the nwb file with the lfp data - lfp_object_id: varchar(40) # the NWB object ID for loading this object from the file - lfp_sampling_rate: float # the sampling rate, in HZ + -> CommonLFP """ - def fetch_nwb(self, *attrs, **kwargs): - return fetch_nwb( - self, - (AnalysisNwbfile, "analysis_file_abs_path"), - *attrs, - **kwargs, - ) - - def fetch1_dataframe(self, *attrs, **kwargs): - nwb_lfp = self.fetch_nwb()[0] - return pd.DataFrame( - nwb_lfp["lfp"].data, - index=pd.Index(nwb_lfp["lfp"].timestamps, name="time"), - ) - @staticmethod def get_lfp_object(key: dict): """Returns the lfp object corresponding to the key @@ -125,3 +68,28 @@ def get_lfp_object(key: dict): return LFPV1 & lfp_object.fetch("KEY") else: return ImportedLFPV1 & (LFPOutput.ImportedLFP & key).fetch("KEY") + + def fetch_nwb(self, *attrs, **kwargs): + part_parents = self._merge_restrict_parents( + restriction=self.restriction, return_empties=False + ) + + if len(part_parents) == 1: + return fetch_nwb( + part_parents[0], + (AnalysisNwbfile, "analysis_file_abs_path"), + *attrs, + **kwargs, + ) + else: + raise ValueError( + f"{len(part_parents)} possible sources found in Merge Table" + + part_parents + ) + + def fetch1_dataframe(self, *attrs, **kwargs): + nwb_lfp = self.fetch_nwb()[0] + return pd.DataFrame( + nwb_lfp["lfp"].data, + index=pd.Index(nwb_lfp["lfp"].timestamps, name="time"), + ) diff --git a/src/spyglass/lfp/v1/lfp.py b/src/spyglass/lfp/v1/lfp.py index 13d847d77..9699c980d 100644 --- a/src/spyglass/lfp/v1/lfp.py +++ b/src/spyglass/lfp/v1/lfp.py @@ -21,27 +21,6 @@ MIN_LFP_INTERVAL_DURATION = 1.0 # 1 second minimum interval duration -@schema -class LFPSelection(dj.Manual): - """The user's selection of LFP data to be filtered - - This table is used to select the LFP data to be filtered. The user can select - the LFP data by specifying the electrode group and the interval list to be used. - The interval list is used to select the times from the raw data that will be - filtered. The user can also specify the filter to be used. - - The LFP data is filtered and downsampled to 1 KHz. The filtered data is stored - in the AnalysisNwbfile table. The valid times for the filtered data are stored - in the IntervalList table. - """ - - definition = """ - -> LFPElectrodeGroup # the group of electrodes to be filtered - -> IntervalList.proj(target_interval_list_name='interval_list_name') # the original set of times to be filtered - -> FirFilterParameters # the filter to be used - """ - - @schema class LFPV1(dj.Computed): """The filtered LFP data""" @@ -161,16 +140,9 @@ def make(self, key): # finally, we insert this into the LFP output table. from spyglass.lfp.lfp_merge import LFPOutput - lfp_id = uuid.uuid1() - lfp_o_key = {"lfp_id": lfp_id, "source": "LFP", "version": 1} - LFPOutput.insert1(lfp_o_key) - - orig_key.update(lfp_o_key) - del orig_key["source"] - del orig_key["version"] orig_key["analysis_file_name"] = lfp_file_name orig_key["lfp_object_id"] = lfp_object_id - LFPOutput.LFPV1.insert1(orig_key) + LFPOutput.insert1(orig_key) def fetch_nwb(self, *attrs, **kwargs): return fetch_nwb( @@ -185,18 +157,6 @@ def fetch1_dataframe(self, *attrs, **kwargs): ) -@schema -class ImportedLFPV1(dj.Imported): - definition = """ - -> Session # the session to which this LFP belongs - -> LFPElectrodeGroup # the group of electrodes to be filtered - -> IntervalList # the original set of times to be filtered - lfp_object_id: varchar(40) # the NWB object ID for loading this object from the file - --- - lfp_sampling_rate: float # the sampling rate, in samples/sec - """ - - @schema class LFPElectrodeGroup(dj.Manual): definition = """ @@ -246,3 +206,42 @@ def create_lfp_electrode_group( LFPElectrodeGroup().LFPElectrode.insert1( lfpelectdict, skip_duplicates=True ) + + +@schema +class LFPSelection(dj.Manual): + """The user's selection of LFP data to be filtered + + This table is used to select the LFP data to be filtered. The user can select + the LFP data by specifying the electrode group and the interval list to be used. + The interval list is used to select the times from the raw data that will be + filtered. The user can also specify the filter to be used. + + The LFP data is filtered and downsampled to 1 KHz. The filtered data is stored + in the AnalysisNwbfile table. The valid times for the filtered data are stored + in the IntervalList table. + """ + + definition = """ + -> LFPElectrodeGroup # the group of electrodes to be filtered + -> IntervalList.proj(target_interval_list_name='interval_list_name') # the original set of times to be filtered + -> FirFilterParameters # the filter to be used + """ + + +@schema +class ImportedLFPV1(dj.Imported): + definition = """ + -> Session # the session to which this LFP belongs + -> LFPElectrodeGroup # the group of electrodes to be filtered + -> IntervalList # the original set of times to be filtered + lfp_object_id: varchar(40) # the NWB object ID for loading this object from the file + --- + lfp_sampling_rate: float # the sampling rate, in samples/sec + -> AnalysisNwbfile + """ + + def make(self, key): + raise NotImplementedError( + "For `insert`, use `allow_direct_insert=True`" + ) diff --git a/src/spyglass/utils/dj_helper_fn.py b/src/spyglass/utils/dj_helper_fn.py index 548aa66c7..8aaf40313 100644 --- a/src/spyglass/utils/dj_helper_fn.py +++ b/src/spyglass/utils/dj_helper_fn.py @@ -9,10 +9,11 @@ def dj_replace(original_table, new_values, key_column, replace_column): - """Given the output of a fetch() call from a schema and a 2D array made up of (key_value, replace_value) tuples, - find each instance of key_value in the key_column of the original table and replace the specified replace_column - with the associated replace_value. - Key values must be unique. + """Given the output of a fetch() call from a schema and a 2D array made up + of (key_value, replace_value) tuples, find each instance of key_value in + the key_column of the original table and replace the specified + replace_column with the associated replace_value. Key values must be + unique. Parameters ---------- @@ -84,6 +85,7 @@ def fetch_nwb(query_expression, nwb_master, *attrs, **kwargs): else Nwbfile.get_abs_path ) + # TODO: check that the query_expression restricts tbl - CBroz nwb_files = ( query_expression * tbl.proj(nwb2load_filepath=attr_name) ).fetch(file_name_str) diff --git a/src/spyglass/utils/dj_merge_tables.py b/src/spyglass/utils/dj_merge_tables.py new file mode 100644 index 000000000..02b9d175a --- /dev/null +++ b/src/spyglass/utils/dj_merge_tables.py @@ -0,0 +1,425 @@ +from contextlib import nullcontext +from itertools import chain as iter_chain +from pprint import pprint + +import datajoint as dj +from datajoint.condition import make_condition +from datajoint.errors import DataJointError +from datajoint.preview import repr_html +from datajoint.utils import from_camel_case, to_camel_case +from IPython.core.display import HTML + +RESERVED_PRIMARY_KEY = "merge_id" +RESERVED_SECONDARY_KEY = "source" +RESERVED_SK_LENGTH = 32 + + +class Merge(dj.Manual): + """Adds funcs to support insert/delete/view of Merge tables.""" + + def __init__(self): + super().__init__() + self._reserved_pk = RESERVED_PRIMARY_KEY + self._reserved_sk = RESERVED_SECONDARY_KEY + merge_def = ( + f"\n {self._reserved_pk}: uuid\n ---\n" + + f" {self._reserved_sk}: varchar({RESERVED_SK_LENGTH})\n " + ) + # TODO: Change warnings to logger. Throw error? - CBroz1 + if not self.is_declared: + if self.definition != merge_def: + print( + "WARNING: merge table declared with non-default definition\n\t" + + f"Expected: {merge_def.strip()}\n\t" + + f"Actual : {self.definition.strip()}" + ) + for part in self.parts(as_objects=True): + if part.primary_key != self.primary_key: + print( + f"WARNING: unexpected primary key for {part.table_name}\n\t" + + f"Expected: {self.primary_key}\n\t" + + f"Actual : {part.primary_key}" + ) + + @classmethod + def _merge_restrict_parts( + cls, + restriction: str = True, + as_objects: bool = True, + return_empties: bool = True, + ) -> list: + """Returns a list of parts with restrictions applied. + + Parameters + --------- + restriction: str, optional + Restriction to apply to the merged view. Default True, no restrictions. + as_objects: bool, optional + Default True. Return part tables as objects + return_empties: bool, optional + Default True. Return empty part tables + + Returns + ------ + list + list of datajoint tables, parts of Merge Table + """ + if not dj.conn.connection.dependencies._loaded: + dj.conn.connection.dependencies.load() # Otherwise parts returns none + + if not restriction: + restriction = True + + # Normalize restriction to sql string + restriction = make_condition(cls(), restriction, set()) + + parts_all = cls.parts(as_objects=True) + # If the restriction makes ref to a source, we only want that part + if isinstance(restriction, str) and cls()._reserved_sk in restriction: + parts_all = [ + part + for part in parts_all + if from_camel_case( + restriction.split(f'`{cls()._reserved_sk}`="')[-1].split( + '"' + )[0] + ) # Only look at source part table + in part.full_table_name + ] + + parts = [] + for part in parts_all: + try: + parts.append(part.restrict(restriction)) + except DataJointError: # If restriction not valid on given part + parts.append(part) + + if not return_empties: + parts = [p for p in parts if len(p)] + if not as_objects: + parts = [p.full_table_name for p in parts] + + return parts + + @classmethod + def _merge_restrict_parents( + cls, + restriction: str = True, + as_objects: bool = True, + return_empties: bool = True, + ) -> list: + """Returns a list of part parents with restrictions applied. + + Rather than part tables, we look at parents of those parts, the source + of the data. + + Parameters + --------- + restriction: str, optional + Restriction to apply to the merged view. Default True, no restrictions. + as_objects: bool, optional + Default True. Return part tables as objects + return_empties: bool, optional + Default True. Return empty part tables + + Returns + ------ + list + list of datajoint tables, parents of parts of Merge Table + """ + part_parents = [ + parent # Below, restricting parent to info from restricted part + & part.fetch(*part.heading.secondary_attributes, as_dict=True) + for part in cls()._merge_restrict_parts( + restriction=restriction, return_empties=return_empties + ) + for parent in part.parents(as_objects=True) # ID respective parents + if cls().table_name not in parent.full_table_name # Not merge table + ] + if not as_objects: + part_parents = [p.full_table_name for p in part_parents] + + return part_parents + + @classmethod + def _merge_repr( + cls, restriction: str = True, **kwargs + ) -> dj.expression.Union: + """Merged view, including null entries for columns unique to one part table. + + Parameters + --------- + restriction: str, optional + Restriction to apply to the merged view + + Returns + ------ + datajoint.expression.Union + """ + + parts = [ + cls() * p # join with master to include sec key (i.e., 'source') + for p in cls._merge_restrict_parts(restriction=restriction) + ] + + primary_attrs = list( + dict.fromkeys( # get all columns from parts + iter_chain.from_iterable([p.heading.names for p in parts]) + ) + ) + # primary_attrs.append(cls()._reserved_sk) + query = dj.U(*primary_attrs) * parts[0].proj( # declare query + ..., # include all attributes from part 0 + **{ + a: "NULL" # add null value where part has no column + for a in primary_attrs + if a not in parts[0].heading.names + }, + ) + for part in parts[1:]: # add to declared query for each part + query += dj.U(*primary_attrs) * part.proj( + ..., + **{ + a: "NULL" + for a in primary_attrs + if a not in part.heading.names + }, + ) + return query + + @classmethod + def _merge_insert(cls, rows: list, **kwargs) -> None: + """Insert rows into merge table, ensuring db integrity and mutual exclusivity + + Parameters + --------- + rows: List[dict] + An iterable where an element is a dictionary. + + Raises + ------ + TypeError + If rows is not a list of dicts + ValueError + If entry already exists, mutual exclusivity errors + If data doesn't exist in part parents, integrity error + """ + + try: + for r in iter(rows): + assert isinstance( + r, dict + ), 'Input "rows" must be a list of dictionaries' + except TypeError: + raise TypeError('Input "rows" must be a list of dictionaries') + + parts = cls._merge_restrict_parts(as_objects=True) + master_entries = [] + parts_entries = {p: [] for p in parts} + for row in rows: + key = {} + for part in parts: + master = part.parents(as_objects=True)[-1] + part_name = to_camel_case(part.table_name.split("__")[-1]) + if master & row: + if not key: + key = (master & row).fetch1("KEY") + master_pk = { + cls()._reserved_pk: dj.hash.key_hash(key), + } + parts_entries[part].append({**master_pk, **key}) + master_entries.append( + {**master_pk, cls()._reserved_sk: part_name} + ) + else: + raise ValueError( + "Mutual Exclusivity Error! Entry exists in more " + + f"than one table - Entry: {row}" + ) + + if not key: + raise ValueError( + "Non-existing entry in any of the parent tables - Entry: " + + f"{row}" + ) + + # 1. nullcontext() allows use within `make` but decreases reliability + # 2. cls.connection.transaction is more relaiable but throws errors if + # used within another transaction, i.e. in `make` + + with nullcontext(): # TODO: ensure this block within transaction + super().insert(cls(), master_entries, **kwargs) + for part, part_entries in parts_entries.items(): + part.insert(part_entries, **kwargs) + + @classmethod + def insert(cls, rows: list, **kwargs): + """Insert rows into merge table + + Ensuring db integrity and mutual exclusivity + + Parameters + --------- + rows: List[dict] + An iterable where an element is a dictionary. + + Raises + ------ + TypeError + If rows is not a list of dicts + ValueError + If entry already exists, mutual exclusivity errors + If data doesn't exist in part parents, integrity error + """ + cls._merge_insert(rows, **kwargs) + + @classmethod + def merge_view(cls, restriction: str = True): + """Prints merged view, including null entries for unique columns. + + Parameters + --------- + restriction: str, optional + Restriction to apply to the merged view + """ + + # If we overwrite `preview`, we then encounter issues with operators + # getting passed a `Union`, which doesn't have a method we can + # intercept to manage master/parts + + return pprint(cls._merge_repr(restriction=restriction)) + + @classmethod + def merge_html(cls, restriction: str = True): + """Displays HTML in notebooks.""" + + return HTML(repr_html(cls._merge_repr(restriction=restriction))) + + @classmethod + def merge_restrict(cls, restriction: str = True) -> dj.U: + """Given a restriction string, return a merged view with restriction applied. + + Example + ------- + >>> MergeTable.merge_restrict("field = 1") + + Parameters + ---------- + restriction: str + Restriction one would appy if `merge_view` was a real table. + + Returns + ------- + datajoint.Union + Merged view with restriction applied. + """ + return cls._merge_repr(restriction=restriction) + + @classmethod + def merge_delete(cls, restriction: str = True, **kwargs): + """Given a restriction string, delete corresponding entries. + + Parameters + ---------- + restriction: str + Optional restriction to apply before deletion from master/part + tables. If not provided, delete all entries. + kwargs: dict + Additional keyword arguments for DataJoint delete. + + Example + ------- + >>> MergeTable.merge_delete("field = 1") + """ + uuids = [ + {k: v} + for entry in cls.merge_restrict(restriction).fetch("KEY") + for k, v in entry.items() + if k == cls()._reserved_pk + ] + (cls() & uuids).delete(**kwargs) + + @classmethod + def merge_delete_parent( + cls, restriction: str = True, dry_run=True, **kwargs + ) -> list: + """Delete enties from merge master, part, and respective part parents + + Note: Clears merge entries from their respective parents. + + Parameters + ---------- + restriction: str + Optional restriction to apply before deletion from parents. If not + provided, delete all entries present in Merge Table. + dry_run: bool + Default True. If true, return list of tables with entries that would be + deleted. Otherwise, table entries. + kwargs: dict + Additional keyword arguments for DataJoint delete. + """ + + part_parents = cls._merge_restrict_parents( + restriction=restriction, as_objects=True, return_empties=False + ) + + if dry_run: + return part_parents + + super().delete(cls(), **kwargs) + for part_parent in part_parents: + super().delete(part_parent, **kwargs) + + +def delete_downstream_merge( + table: dj.Table, restriction: str = True, dry_run=True, **kwargs +) -> list: + """Given a table/restriction, id or delete relevant downstream merge entries + + Parameters + ---------- + table: dj.Table + DataJoint table or restriction thereof + restriction: str + Optional restriction to apply before deletion from merge/part + tables. If not provided, delete all downstream entries. + dry_run: bool + Default True. If true, return list of tuples, merge/part tables + downstream of table input. Otherwise, delete merge/part table entries. + kwargs: dict + Additional keyword arguments for DataJoint delete. + + Returns + ------- + List[Tuple[dj.Table, dj.Table]] + Entries in merge/part tables downstream of table input. + """ + if not restriction: + restriction = True + + # Adapted from Spyglass PR 535 + # dj.utils.get_master could maybe help here, but it uses names, not objs + merge_pairs = [ # get each merge/part table + (master, descendant.restrict(restriction)) + for descendant in table.descendants(as_objects=True) # given tbl desc + for master in descendant.parents(as_objects=True) # and those parents + # if is a part table (using a dunder not immediately after schema name) + if "__" in descendant.full_table_name.replace("`.`__", "") + # and it is not in not in direct descendants + and master.full_table_name not in table.descendants(as_objects=False) + # and it uses our reserved primary key in attributes + and RESERVED_PRIMARY_KEY in master.heading.attributes.keys() + ] + + # restrict the merge table based on uuids in part + merge_pairs = [ + (merge & uuids, part) # don't need part for del, but show on dry_run + for merge, part in merge_pairs + for uuids in part.fetch(RESERVED_PRIMARY_KEY, as_dict=True) + ] + + if dry_run: + return merge_pairs + + for merge_table, _ in merge_pairs: + merge_table.delete(**kwargs) From 9bb75bb2fb8a66603da60861a6688b63f8ea5900 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Thu, 22 Jun 2023 13:39:43 -0700 Subject: [PATCH 059/131] Fix minor formatting and spelling errors --- docs/src/misc/merge_tables.md | 30 +++++++++++++-------------- src/spyglass/lfp/v1/lfp.py | 1 - src/spyglass/utils/dj_merge_tables.py | 2 +- src/spyglass/utils/nwb_helper_fn.py | 4 ++-- 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/docs/src/misc/merge_tables.md b/docs/src/misc/merge_tables.md index 8381062f8..aed9dabbc 100644 --- a/docs/src/misc/merge_tables.md +++ b/docs/src/misc/merge_tables.md @@ -10,7 +10,7 @@ and related discussions [here](https://github.com/datajoint/datajoint-python/iss and [here](https://github.com/LorenFrankLab/spyglass/issues/469). **Note:** Deleting entries upstream of Merge Tables will throw errors related to -deleteing a part entry before the master. To circumvent this, you can add +deleting a part entry before the master. To circumvent this, you can add `force_parts=True` to the [`delete` function](https://datajoint.com/docs/core/datajoint-python/0.14/api/datajoint/__init__/#datajoint.table.Table.delete) call, but this will leave and orphaned primary key in the master. Instead, use @@ -21,10 +21,10 @@ call, but this will leave and orphaned primary key in the master. Instead, use A Merge Table is fundametally a master table with one part for each divergent pipeline. By convention... -1. The master table has one primary key, `merge_id`, a +1. The master table has one primary key, `merge_id`, a [UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier), and one - secondary attribute, `source`, which gives the part table name. Both are - managed with the custom `insert` function of this class. + secondary attribute, `source`, which gives the part table name. Both are + managed with the custom `insert` function of this class. 2. Each part table has inherits the final table in its respective pipeline, and shares the same name as this table. @@ -62,12 +62,12 @@ The Merge class in Spyglass's utils is a subclass of DataJoint's and adds functions to make the awkwardness of part tables more manageable. These functions are described in the API section, under `utils.dj_merge_tables`. -One quirk of these utilites is that they take restrictions as agruments, rather -than with operators. So `Table & "field='value'"` becomes -`MergeTable.merge_view(restriction="field='value'"`)`. This is because +One quirk of these utilities is that they take restrictions as arguments, rather +than with operators. So `Table & "field='value'"` becomes +`MergeTable.merge_view(restriction="field='value'"`)`. This is because `merge_view` is a `Union` rather than a true Table. -## Example +## Example First, we'll import various items related to the LFP Merge Table... @@ -78,7 +78,7 @@ from spyglass.lfp.lfp_merge import LFPOutput # Merge Table from spyglass.lfp.v1.lfp import LFPV1 # Upstream 2 ``` -Merge Tables have multiple custom methods that begin with `merge`. `help` can +Merge Tables have multiple custom methods that begin with `merge`. `help` can show us the docstring of each ```python @@ -130,18 +130,18 @@ nwb_key = LFPOutput.merge_restrict(nwb_file_dict).fetch(as_dict=True)[0] result2 = (LFPOutput & nwb_key).fetch_nwb() ``` -When deleting from Merge Tables, we can either... +When deleting from Merge Tables, we can either... 1. delete from the Merge Table itself with `merge_delete`_parent, deleting both - the master and part. + the master and part. 2. use `merge_delete_parent` to delete from the parent sources, getting rid of the entries in the source table they came from. -3. use `delete_downstream_merge` to find Merge Tables downstream and get rid - full entries, avoiding orphaned master table entries. +3. use `delete_downstream_merge` to find Merge Tables downstream and get rid + full entries, avoiding orphaned master table entries. The two latter cases can be destructive, so we include an extra layer of -protection with `dry_run`. When true (by default), these functions return -a list of tables with the entries that would otherwise be deleted. +protection with `dry_run`. When true (by default), these functions return +a list of tables with the entries that would otherwise be deleted. ```python LFPOutput.merge_delete(common_keys[0]) # Delete from merge table diff --git a/src/spyglass/lfp/v1/lfp.py b/src/spyglass/lfp/v1/lfp.py index 9699c980d..4591ca652 100644 --- a/src/spyglass/lfp/v1/lfp.py +++ b/src/spyglass/lfp/v1/lfp.py @@ -1,5 +1,4 @@ import copy -import uuid import datajoint as dj import numpy as np diff --git a/src/spyglass/utils/dj_merge_tables.py b/src/spyglass/utils/dj_merge_tables.py index 02b9d175a..f604c334e 100644 --- a/src/spyglass/utils/dj_merge_tables.py +++ b/src/spyglass/utils/dj_merge_tables.py @@ -306,7 +306,7 @@ def merge_restrict(cls, restriction: str = True) -> dj.U: Parameters ---------- restriction: str - Restriction one would appy if `merge_view` was a real table. + Restriction one would apply if `merge_view` was a real table. Returns ------- diff --git a/src/spyglass/utils/nwb_helper_fn.py b/src/spyglass/utils/nwb_helper_fn.py index c4569e0b0..58cf6a076 100644 --- a/src/spyglass/utils/nwb_helper_fn.py +++ b/src/spyglass/utils/nwb_helper_fn.py @@ -2,12 +2,12 @@ import os import os.path -from pathlib import Path import warnings -import yaml +from pathlib import Path import numpy as np import pynwb +import yaml # dict mapping file path to an open NWBHDF5IO object in read mode and its NWBFile __open_nwb_files = dict() From 7a5d21cf2937199fef08284289e9715e3987c718 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Thu, 22 Jun 2023 13:42:44 -0700 Subject: [PATCH 060/131] Remove unused method --- src/spyglass/lfp/lfp_merge.py | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/src/spyglass/lfp/lfp_merge.py b/src/spyglass/lfp/lfp_merge.py index ba6de68ac..8a1b9977d 100644 --- a/src/spyglass/lfp/lfp_merge.py +++ b/src/spyglass/lfp/lfp_merge.py @@ -5,7 +5,7 @@ from spyglass.common.common_filter import FirFilterParameters # noqa: F401 from spyglass.common.common_interval import IntervalList # noqa: F401 from spyglass.common.common_nwbfile import AnalysisNwbfile -from spyglass.lfp.v1.lfp import LFPV1, ImportedLFPV1 +from spyglass.lfp.v1.lfp import LFPV1, ImportedLFPV1 # noqa: F401 from spyglass.utils.dj_helper_fn import fetch_nwb from spyglass.utils.dj_merge_tables import Merge @@ -43,32 +43,6 @@ class CommonLFP(dj.Part): -> CommonLFP """ - @staticmethod - def get_lfp_object(key: dict): - """Returns the lfp object corresponding to the key - - Parameters - ---------- - key : dict - A dictionary containing some combination of - uuid, - nwb_file_name, - lfp_electrode_group_name, - interval_list_name, - fir_filter_name - - Returns - ------- - lfp_object - The entry or entries in the LFPOutput part table that corresponds to the key - """ - # first check if this returns anything from the LFP table - lfp_object = LFPOutput.LFP & key - if lfp_object is not None: - return LFPV1 & lfp_object.fetch("KEY") - else: - return ImportedLFPV1 & (LFPOutput.ImportedLFP & key).fetch("KEY") - def fetch_nwb(self, *attrs, **kwargs): part_parents = self._merge_restrict_parents( restriction=self.restriction, return_empties=False From 81fc211fbf07fc68cf7cd6714ba6a91b327648f5 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Thu, 22 Jun 2023 14:09:25 -0700 Subject: [PATCH 061/131] Add fetch_nwb to Merge class --- src/spyglass/lfp/lfp_merge.py | 20 -------------------- src/spyglass/utils/dj_merge_tables.py | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/spyglass/lfp/lfp_merge.py b/src/spyglass/lfp/lfp_merge.py index 8a1b9977d..080db266c 100644 --- a/src/spyglass/lfp/lfp_merge.py +++ b/src/spyglass/lfp/lfp_merge.py @@ -4,9 +4,7 @@ from spyglass.common.common_ephys import LFP as CommonLFP # noqa: F401 from spyglass.common.common_filter import FirFilterParameters # noqa: F401 from spyglass.common.common_interval import IntervalList # noqa: F401 -from spyglass.common.common_nwbfile import AnalysisNwbfile from spyglass.lfp.v1.lfp import LFPV1, ImportedLFPV1 # noqa: F401 -from spyglass.utils.dj_helper_fn import fetch_nwb from spyglass.utils.dj_merge_tables import Merge schema = dj.schema("lfp_merge") @@ -43,24 +41,6 @@ class CommonLFP(dj.Part): -> CommonLFP """ - def fetch_nwb(self, *attrs, **kwargs): - part_parents = self._merge_restrict_parents( - restriction=self.restriction, return_empties=False - ) - - if len(part_parents) == 1: - return fetch_nwb( - part_parents[0], - (AnalysisNwbfile, "analysis_file_abs_path"), - *attrs, - **kwargs, - ) - else: - raise ValueError( - f"{len(part_parents)} possible sources found in Merge Table" - + part_parents - ) - def fetch1_dataframe(self, *attrs, **kwargs): nwb_lfp = self.fetch_nwb()[0] return pd.DataFrame( diff --git a/src/spyglass/utils/dj_merge_tables.py b/src/spyglass/utils/dj_merge_tables.py index f604c334e..9ee812140 100644 --- a/src/spyglass/utils/dj_merge_tables.py +++ b/src/spyglass/utils/dj_merge_tables.py @@ -9,6 +9,9 @@ from datajoint.utils import from_camel_case, to_camel_case from IPython.core.display import HTML +from spyglass.common.common_nwbfile import AnalysisNwbfile +from spyglass.utils.dj_helper_fn import fetch_nwb + RESERVED_PRIMARY_KEY = "merge_id" RESERVED_SECONDARY_KEY = "source" RESERVED_SK_LENGTH = 32 @@ -370,6 +373,24 @@ def merge_delete_parent( for part_parent in part_parents: super().delete(part_parent, **kwargs) + def fetch_nwb(self, *attrs, **kwargs): + part_parents = self._merge_restrict_parents( + restriction=self.restriction, return_empties=False + ) + + if len(part_parents) == 1: + return fetch_nwb( + part_parents[0], + (AnalysisNwbfile, "analysis_file_abs_path"), + *attrs, + **kwargs, + ) + else: + raise ValueError( + f"{len(part_parents)} possible sources found in Merge Table" + + part_parents + ) + def delete_downstream_merge( table: dj.Table, restriction: str = True, dry_run=True, **kwargs From 0b38c7d5762de832f9f9ba363d7d56306cbb8b9f Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Thu, 22 Jun 2023 15:44:05 -0700 Subject: [PATCH 062/131] Add temporary part table retrieval method --- src/spyglass/utils/dj_merge_tables.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/spyglass/utils/dj_merge_tables.py b/src/spyglass/utils/dj_merge_tables.py index 9ee812140..e43d1f5c9 100644 --- a/src/spyglass/utils/dj_merge_tables.py +++ b/src/spyglass/utils/dj_merge_tables.py @@ -391,6 +391,10 @@ def fetch_nwb(self, *attrs, **kwargs): + part_parents ) + def get_part_table(self) -> dj.Table: + """Hacky way to retrieve the part table from a merge table with a single entry""" + return getattr(self, self.fetch1("source")) & self + def delete_downstream_merge( table: dj.Table, restriction: str = True, dry_run=True, **kwargs From f3d5f67add5f1b25a426c31d9c7b5f13f0070efe Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Thu, 22 Jun 2023 15:44:36 -0700 Subject: [PATCH 063/131] Update LFPBand to use new merge table structure --- src/spyglass/lfp_band/__init__.py | 1 + src/spyglass/lfp_band/lfp_band_merge.py | 39 ++++++-------------- src/spyglass/lfp_band/v1/__init__.py | 1 + src/spyglass/lfp_band/v1/lfp_band.py | 49 +++++++++++-------------- 4 files changed, 35 insertions(+), 55 deletions(-) create mode 100644 src/spyglass/lfp_band/v1/__init__.py diff --git a/src/spyglass/lfp_band/__init__.py b/src/spyglass/lfp_band/__init__.py index e69de29bb..dea89719b 100644 --- a/src/spyglass/lfp_band/__init__.py +++ b/src/spyglass/lfp_band/__init__.py @@ -0,0 +1 @@ +from spyglass.lfp_band.lfp_band_merge import LFPBandOutput diff --git a/src/spyglass/lfp_band/lfp_band_merge.py b/src/spyglass/lfp_band/lfp_band_merge.py index d5f459204..d5cafdcce 100644 --- a/src/spyglass/lfp_band/lfp_band_merge.py +++ b/src/spyglass/lfp_band/lfp_band_merge.py @@ -1,45 +1,30 @@ import datajoint as dj import pandas as pd -from spyglass.common.common_nwbfile import AnalysisNwbfile from spyglass.lfp_band.v1.lfp_band import LFPBandV1 # noqa F401 -from spyglass.utils.dj_helper_fn import fetch_nwb +from spyglass.utils.dj_merge_tables import Merge schema = dj.schema("lfp_band_merge") @schema -class LFPBandOutput(dj.Manual): +class LFPBandOutput(Merge): definition = """ - lfp_band_id: uuid + merge_id: uuid --- - source: varchar(40) - version: int - + source: varchar(32) """ class LFPBandV1(dj.Part): definition = """ - -> LFPBandOutput - -> LFPBandV1 + -> master --- - -> AnalysisNwbfile - lfp_band_object_id: varchar(40) + -> LFPBandV1 """ - def fetch_nwb(self, *attrs, **kwargs): - return fetch_nwb( - self, - (AnalysisNwbfile, "analysis_file_abs_path"), - *attrs, - **kwargs, - ) - - def fetch1_dataframe(self, *attrs, **kwargs): - filtered_nwb = self.fetch_nwb()[0] - return pd.DataFrame( - filtered_nwb["filtered_data"].data, - index=pd.Index( - filtered_nwb["filtered_data"].timestamps, name="time" - ), - ) + def fetch1_dataframe(self, *attrs, **kwargs): + filtered_nwb = self.fetch_nwb()[0] + return pd.DataFrame( + filtered_nwb["lfp_band"].data, + index=pd.Index(filtered_nwb["lfp_band"].timestamps, name="time"), + ) diff --git a/src/spyglass/lfp_band/v1/__init__.py b/src/spyglass/lfp_band/v1/__init__.py new file mode 100644 index 000000000..92140cfd0 --- /dev/null +++ b/src/spyglass/lfp_band/v1/__init__.py @@ -0,0 +1 @@ +from spyglass.lfp_band.v1.lfp_band import LFPBandV1, LFPBandSelection diff --git a/src/spyglass/lfp_band/v1/lfp_band.py b/src/spyglass/lfp_band/v1/lfp_band.py index bf0af09e6..4d6b82b98 100644 --- a/src/spyglass/lfp_band/v1/lfp_band.py +++ b/src/spyglass/lfp_band/v1/lfp_band.py @@ -28,7 +28,7 @@ class LFPBandSelection(dj.Manual): """The user's selection of LFP data to be filtered in a given frequency band.""" definition = """ - -> LFPOutput # the LFP data to be filtered + -> LFPOutput.proj(lfp_merge_id='merge_id') # the LFP data to be filtered -> FirFilterParameters # the filter to use for the data -> IntervalList.proj(target_interval_list_name='interval_list_name') # the original set of times to be filtered lfp_band_sampling_rate: int # the sampling rate for this band @@ -47,7 +47,7 @@ class LFPBandElectrode(dj.Part): def set_lfp_band_electrodes( self, nwb_file_name: str, - lfp_id: int, + lfp_merge_id: int, electrode_list: list[int], filter_name: str, interval_list_name: str, @@ -60,8 +60,8 @@ def set_lfp_band_electrodes( ---------- nwb_file_name: str The name of the NWB file containing the LFP data - lfp_id: int - The id of the LFP data to be filtered + merge_id: int + The uuid of the LFP data to be filtered electrode_list: list A list of the electrodes to be filtered filter_name: str @@ -75,9 +75,11 @@ def set_lfp_band_electrodes( # Error checks on parameters # electrode_list - lfp_object = LFPOutput.get_lfp_object({"lfp_id": lfp_id}) - print(lfp_object) - lfp_key = lfp_object.fetch1("KEY") + lfp_key = {"merge_id": lfp_merge_id} + lfp_output_table = LFPOutput & lfp_key + lfp_part_table = lfp_output_table.get_part_table() + print(lfp_part_table) + query = LFPElectrodeGroup().LFPElectrode() & lfp_key available_electrodes = query.fetch("electrode_id") if not np.all(np.isin(electrode_list, available_electrodes)): @@ -85,8 +87,7 @@ def set_lfp_band_electrodes( "All elements in electrode_list must be valid electrode_ids in the LFPElectodeGroup table" ) # sampling rate - print(lfp_object) - lfp_sampling_rate = (lfp_object & lfp_key).fetch1("lfp_sampling_rate") + lfp_sampling_rate = lfp_part_table.fetch1("filter_sampling_rate") decimation = lfp_sampling_rate // lfp_band_sampling_rate if lfp_sampling_rate // decimation != lfp_band_sampling_rate: raise ValueError( @@ -133,7 +134,7 @@ def set_lfp_band_electrodes( key = dict( nwb_file_name=nwb_file_name, - lfp_id=lfp_id, + lfp_merge_id=lfp_merge_id, filter_name=filter_name, filter_sampling_rate=lfp_sampling_rate, target_interval_list_name=interval_list_name, @@ -142,7 +143,7 @@ def set_lfp_band_electrodes( # insert an entry into the main LFPBandSelectionTable self.insert1(key, skip_duplicates=True) - key["lfp_electrode_group_name"] = lfp_object.fetch1( + key["lfp_electrode_group_name"] = lfp_part_table.fetch1( "lfp_electrode_group_name" ) # iterate through all of the new elements and add them @@ -177,9 +178,10 @@ class LFPBandV1(dj.Computed): def make(self, key): # get the NWB object with the lfp data; FIX: change to fetch with additional infrastructure - lfp_object = ( - LFPOutput() & {"nwb_file_name": key["nwb_file_name"]} - ).fetch_nwb()[0]["lfp"] + lfp_key = {"merge_id": key["lfp_merge_id"]} + lfp_output_table = LFPOutput & lfp_key + lfp_part_table = lfp_output_table.get_part_table() + lfp_object = lfp_output_table.fetch_nwb()[0]["lfp"] # get the electrodes to be filtered and their references lfp_band_elect_id, lfp_band_ref_id = ( @@ -193,11 +195,7 @@ def make(self, key): lfp_band_elect_id = lfp_band_elect_id[lfp_sort_order] lfp_band_ref_id = lfp_band_ref_id[lfp_sort_order] - lfp_sampling_rate = ( - LFPOutput() - .get_lfp_object({"lfp_id": key["lfp_id"]}) - .fetch1("lfp_sampling_rate") - ) + lfp_sampling_rate = lfp_part_table.fetch1("filter_sampling_rate") interval_list_name, lfp_band_sampling_rate = ( LFPBandSelection() & key ).fetch1("target_interval_list_name", "lfp_band_sampling_rate") @@ -210,11 +208,7 @@ def make(self, key): ).fetch1("valid_times") # the valid_times for this interval may be slightly beyond the valid times for the lfp itself, # so we have to intersect the two - lfp_interval_list = ( - LFPOutput() - .get_lfp_object({"lfp_id": key["lfp_id"]}) - .fetch1("interval_list_name") - ) + lfp_interval_list = lfp_part_table.fetch1("target_interval_list_name") lfp_valid_times = ( IntervalList() & { @@ -370,17 +364,16 @@ def make(self, key): "previously saved lfp band times do not match current times" ) + self.insert1(key) + from spyglass.lfp_band.lfp_band_merge import LFPBandOutput lfp_band_output_key = { - "lfp_band_id": uuid.uuid1(), - "source": "LFPBand", - "version": "1", + "merge_id": uuid.uuid1(), "analysis_file_name": lfp_band_file_name, "lfp_band_object_id": lfp_band_object_id, } LFPBandOutput.insert1(lfp_band_output_key) - LFPBandOutput.LFPBandV1.insert1(key) def fetch_nwb(self, *attrs, **kwargs): return fetch_nwb( From c2540644f11983737b208b82ac7e992cad4a295e Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Thu, 22 Jun 2023 16:08:56 -0700 Subject: [PATCH 064/131] Update for new merge table structure --- src/spyglass/ripple/ripple_merge.py | 33 +++++++++-------------------- src/spyglass/ripple/v1/ripple.py | 18 +++++----------- 2 files changed, 15 insertions(+), 36 deletions(-) diff --git a/src/spyglass/ripple/ripple_merge.py b/src/spyglass/ripple/ripple_merge.py index 2077a520f..39e96afa8 100644 --- a/src/spyglass/ripple/ripple_merge.py +++ b/src/spyglass/ripple/ripple_merge.py @@ -1,8 +1,7 @@ import datajoint as dj -from spyglass.common.common_nwbfile import AnalysisNwbfile from spyglass.ripple.v1.ripple import RippleTimesV1 # noqa F401 -from spyglass.utils.dj_helper_fn import fetch_nwb +from spyglass.utils.dj_merge_tables import Merge schema = dj.schema("ripple_merge") @@ -10,33 +9,21 @@ @schema class RippleTimesOutput(dj.Manual): definition = """ - ripple_id: uuid + merge_id: uuid --- - source: varchar(40) - version: int - + source: varchar(32) """ class RippleTimesV1(dj.Part): definition = """ - -> RippleTimesOutput - -> RippleTimesV1 + -> master --- - -> AnalysisNwbfile - ripple_times_object_id : varchar(40) + -> RippleTimesV1 """ - def fetch_nwb(self, *attrs, **kwargs): - return fetch_nwb( - self, - (AnalysisNwbfile, "analysis_file_abs_path"), - *attrs, - **kwargs, - ) - - def fetch1_dataframe(self): - """Convenience function for returning the marks in a readable format""" - return self.fetch_dataframe()[0] + def fetch1_dataframe(self): + """Convenience function for returning the marks in a readable format""" + return self.fetch_dataframe()[0] - def fetch_dataframe(self): - return [data["ripple_times"] for data in self.fetch_nwb()] + def fetch_dataframe(self): + return [data["ripple_times"] for data in self.fetch_nwb()] diff --git a/src/spyglass/ripple/v1/ripple.py b/src/spyglass/ripple/v1/ripple.py index 5da02717e..48519c87a 100644 --- a/src/spyglass/ripple/v1/ripple.py +++ b/src/spyglass/ripple/v1/ripple.py @@ -185,21 +185,13 @@ def make(self, key): # finally, we insert this into the LFP output table. from spyglass.ripple.ripple_merge import RippleTimesOutput - ripple_times_object_id = uuid.uuid1() ripple_times_output_key = { - "lfp_id": ripple_times_object_id, - "source": "LFP", - "version": 1, + "merge_id": uuid.uuid1(), + "analysis_file_name": key["analysis_file_name"], + "ripple_times_object_id": key["ripple_times_object_id"], } RippleTimesOutput.insert1(ripple_times_output_key) - key.update(ripple_times_output_key) - del key["source"] - del key["version"] - - key["ripple_time_object_id"] = ripple_times_object_id - RippleTimesOutput.RippleTimesV1.insert1(key) - def fetch_nwb(self, *attrs, **kwargs): return fetch_nwb( self, (AnalysisNwbfile, "analysis_file_abs_path"), *attrs, **kwargs @@ -216,7 +208,7 @@ def fetch_dataframe(self): def get_ripple_lfps_and_position_info(key): nwb_file_name = key["nwb_file_name"] interval_list_name = key["target_interval_list_name"] - position_info_param_name = key["position_info_param_name"] + ripple_params = ( RippleParameters & {"ripple_param_name": key["ripple_param_name"]} ).fetch1("ripple_param_dict") @@ -230,7 +222,7 @@ def get_ripple_lfps_and_position_info(key): # warn/validate that there is only one wire per electrode lfp_key = copy.deepcopy(key) del lfp_key["interval_list_name"] - ripple_lfp_nwb = (LFPBandOutput.LFPBandV1 & lfp_key).fetch_nwb()[0] + ripple_lfp_nwb = (LFPBandOutput & lfp_key).fetch_nwb()[0] ripple_lfp_electrodes = ripple_lfp_nwb["filtered_data"].electrodes.data[ : ] From a2114809bf94dcaf36728e232f06c982d94bebc5 Mon Sep 17 00:00:00 2001 From: dpeg22 Date: Tue, 11 Jul 2023 12:08:36 -0700 Subject: [PATCH 065/131] remove duplicate yaml file --- environment_position2.yml | 62 --------------------------------------- 1 file changed, 62 deletions(-) delete mode 100644 environment_position2.yml diff --git a/environment_position2.yml b/environment_position2.yml deleted file mode 100644 index 2aaa39f85..000000000 --- a/environment_position2.yml +++ /dev/null @@ -1,62 +0,0 @@ -# FIRST: INSTALL CORRECT DRIVER for GPU, see https://stackoverflow.com/questions/30820513/what-is-the-correct-version-of-cuda-for-my-nvidia-driver/30820690 -# -# install: mamba env create -f environment_position.yaml -# update: mamba env update -f environment_position.yaml -# after installing do the following: -# conda activate spyglass-position -# mamba env config vars set LD_LIBRARY_PATH=~/path/to/anaconda3/envs/spyglass-position/lib/ -# run mamba install -c conda-forge wxpython -# cd into spyglass and run pip install -e .[position] -name: spyglass-position3 -channels: - - conda-forge - - defaults - - pytorch - - franklab - - edeno -dependencies: - - python>=3.8, <3.10 - - jupyterlab>=3.* - - pydotplus>=2.0.* - - libgcc - - dask>=2.30 - - dask-cuda - - cupy - - pip>=20.2.* - - position_tools - - track_linearization>=2.3 - - replay_trajectory_classification - - ripple_detection - - trajectory_analysis_tools - - ipython - - matplotlib>=3.3 - - seaborn - - skan - - bottleneck - - ipympl - - tqdm - - nb_conda - - ffmpeg - - pytorch<1.12.0 - - torchvision - - torchaudio - - cudatoolkit=11.3 - - tensorflow>=2.0 - - numba>=0.48.0 - - pyfftw<=0.12.0 # used by ghostipy. install from conda-forge so that it works on Mac ARM processors - - pybind11 #To avoid isosplit5 build error - - pip: - - pubnub<6.4.0 - - mountainsort4 - - spikeinterface>0.94,<0.98 - - pynwb>=2.2.0,<3 - - hdmf>=3.4.6 - - ghostipy - - pymysql>=1.0.* - - sortingview>=0.11 - - figurl-jupyter - - git+https://github.com/LorenFrankLab/ndx-franklab-novela.git - - pyyaml - - click - - "black[jupyter]" - - deeplabcut<2.3.0 From bb969830816b3c3850f272e5240395ba62928d78 Mon Sep 17 00:00:00 2001 From: dpeg22 Date: Tue, 11 Jul 2023 13:32:34 -0700 Subject: [PATCH 066/131] minor update --- src/spyglass/ripple/ripple_merge.py | 19 +++++++++++++++---- src/spyglass/ripple/v1/ripple.py | 25 ++++++++++++++----------- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/spyglass/ripple/ripple_merge.py b/src/spyglass/ripple/ripple_merge.py index 39e96afa8..118f5a55d 100644 --- a/src/spyglass/ripple/ripple_merge.py +++ b/src/spyglass/ripple/ripple_merge.py @@ -1,13 +1,14 @@ import datajoint as dj -from spyglass.ripple.v1.ripple import RippleTimesV1 # noqa F401 -from spyglass.utils.dj_merge_tables import Merge +from spyglass.common.common_ripple import RippleTimes as CommonRipple +from .v1.ripple import RippleTimesV1 # noqa F401 +from spyglass.utils.dj_merge_tables import _Merge schema = dj.schema("ripple_merge") @schema -class RippleTimesOutput(dj.Manual): +class RippleTimesOutput(_Merge): definition = """ merge_id: uuid --- @@ -21,9 +22,19 @@ class RippleTimesV1(dj.Part): -> RippleTimesV1 """ + class CommonRipple(dj.Part): + """Table to pass-through legacy RippleTimes""" + + definition = """ + -> master + --- + -> CommonRipple + """ + def fetch1_dataframe(self): """Convenience function for returning the marks in a readable format""" return self.fetch_dataframe()[0] def fetch_dataframe(self): - return [data["ripple_times"] for data in self.fetch_nwb()] + # Note: `proj` below facilitates operator syntax eg Table & restrict + return [data["ripple_times"] for data in self.fetch_nwb(self.proj())] diff --git a/src/spyglass/ripple/v1/ripple.py b/src/spyglass/ripple/v1/ripple.py index 48519c87a..aae6956e3 100644 --- a/src/spyglass/ripple/v1/ripple.py +++ b/src/spyglass/ripple/v1/ripple.py @@ -1,10 +1,10 @@ import copy -import uuid import datajoint as dj import matplotlib.pyplot as plt import numpy as np import pandas as pd +from datajoint.utils import to_camel_case from ripple_detection import Karlsson_ripple_detector, Kay_ripple_detector from ripple_detection.core import gaussian_smooth, get_envelope @@ -64,12 +64,14 @@ def set_lfp_electrodes( group_name="CA1", **kwargs, ): - """Removes all electrodes for the specified nwb file and then adds back the electrodes in the list + """Removes all electrodes for the specified nwb file and then + adds back the electrodes in the list Parameters ---------- key : dict - dictionary corresponding to the LFPBand entry to use for ripple detection + dictionary corresponding to the LFPBand entry to use for + ripple detection electrode_list : list list of electrodes from LFPBandSelection.LFPBandElectrode to be used as the ripple LFP during detection @@ -144,6 +146,7 @@ class RippleTimesV1(dj.Computed): """ def make(self, key): + orig_key = copy.deepcopy(key) print(f"Computing ripple times for: {key}") ripple_params = ( RippleParameters & {"ripple_param_name": key["ripple_param_name"]} @@ -183,14 +186,14 @@ def make(self, key): self.insert1(key) # finally, we insert this into the LFP output table. - from spyglass.ripple.ripple_merge import RippleTimesOutput + from ..ripple_merge import RippleTimesOutput - ripple_times_output_key = { - "merge_id": uuid.uuid1(), - "analysis_file_name": key["analysis_file_name"], - "ripple_times_object_id": key["ripple_times_object_id"], - } - RippleTimesOutput.insert1(ripple_times_output_key) + part_name = to_camel_case(self.table_name.split("__")[-1]) + + # TODO: The next line belongs in a merge table function + RippleTimesOutput._merge_insert( + [orig_key], part_name=part_name, skip_duplicates=True + ) def fetch_nwb(self, *attrs, **kwargs): return fetch_nwb( @@ -222,7 +225,7 @@ def get_ripple_lfps_and_position_info(key): # warn/validate that there is only one wire per electrode lfp_key = copy.deepcopy(key) del lfp_key["interval_list_name"] - ripple_lfp_nwb = (LFPBandOutput & lfp_key).fetch_nwb()[0] + ripple_lfp_nwb = LFPBandOutput.fetch_nwb(lfp_key)[0] ripple_lfp_electrodes = ripple_lfp_nwb["filtered_data"].electrodes.data[ : ] From ca4876caf8a9b2cbaff75ded837a7b418d79d9e3 Mon Sep 17 00:00:00 2001 From: Eric Denovellis Date: Tue, 11 Jul 2023 15:34:32 -0700 Subject: [PATCH 067/131] Fix circular import --- src/spyglass/ripple/v1/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spyglass/ripple/v1/__init__.py b/src/spyglass/ripple/v1/__init__.py index 0e7b84b84..888624332 100644 --- a/src/spyglass/ripple/v1/__init__.py +++ b/src/spyglass/ripple/v1/__init__.py @@ -1,4 +1,4 @@ -from spyglass.ripple.v1 import ( +from spyglass.ripple.v1.ripple import ( RippleLFPSelection, RippleParameters, RippleTimesV1, From 24274424f54326be9d833fa5c81a3eac2cdedaeb Mon Sep 17 00:00:00 2001 From: dpeg22 Date: Wed, 12 Jul 2023 16:18:01 -0700 Subject: [PATCH 068/131] WIP limit accepted LFPBand versions on ripple --- src/spyglass/ripple/v1/ripple.py | 53 ++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/src/spyglass/ripple/v1/ripple.py b/src/spyglass/ripple/v1/ripple.py index aae6956e3..08930127b 100644 --- a/src/spyglass/ripple/v1/ripple.py +++ b/src/spyglass/ripple/v1/ripple.py @@ -23,6 +23,7 @@ "Karlsson_ripple_detector": Karlsson_ripple_detector, } +UPSTREAM_ACCEPTED_VERSIONS = ["LFPBandV1"] def interpolate_to_new_time( df, new_time, upsampling_interpolation_method="linear" @@ -40,9 +41,13 @@ def interpolate_to_new_time( @schema class RippleLFPSelection(dj.Manual): + # proj required to rename merge_id to avoid downstream conflict + # with PositionOutput merge_id definition = """ - -> LFPBand + -> LFPBandOutput.proj(lfp_band_merge_id='merge_id') group_name = 'CA1' : varchar(80) + --- + electrode_ids : mediumblob """ class RippleLFPElectrode(dj.Part): @@ -51,8 +56,13 @@ class RippleLFPElectrode(dj.Part): -> LFPBandSelection.LFPBandElectrode """ + + def validated_insert1(self, key, **kwargs): + def insert1(self, key, **kwargs): - filter_name = (LFPBandOutput.LFPBandV1 & key).fetch1("filter_name") + filter_name = LFPBandOutput.merge_get_parent( + {"merge_id": key["lfp_band_merge_id"]} + ).fetch1("filter_name") if "ripple" not in filter_name.lower(): raise UserWarning("Please use a ripple filter") super().insert1(key, **kwargs) @@ -78,28 +88,35 @@ def set_lfp_electrodes( group_name : str, optional description of the electrode group, by default "CA1" """ - - RippleLFPSelection().insert1( - {**key, "group_name": group_name}, - skip_duplicates=True, - **kwargs, - ) - if not electrode_list: - electrode_list = ( - (LFPBandSelection.LFPBandElectrode() & key) - .fetch("electrode_id") - .tolist() - ) + lfp_entry = LFPBandOutput.merge_get_parent( + {"merge_id": key["lfp_band_merge_id"]} + ).fetch1() + source = (LFPBandOutput & {"merge_id": key["lfp_band_merge_id"]}).fetch1("source") + if source not in UPSTREAM_ACCEPTED_VERSIONS: + raise NotImplementedError("Ripple_V1 will currently only work with LFPBand_v1") + if electrode_list is None: + electrode_list = lfp_entry["electrode_ids"] electrode_list.sort() + lfp_key = LFPBandOutput.merge_get_parent( + {"merge_id": key["lfp_band_merge_id"]} + ).fetch1("KEY") electrode_keys = ( - pd.DataFrame(LFPBandSelection.LFPBandElectrode() & key) + pd.DataFrame(LFPBandSelection.LFPBandElectrode() & lfp_key) .set_index("electrode_id") .loc[electrode_list] .reset_index() .loc[:, LFPBandSelection.LFPBandElectrode.primary_key] ) + import pdb + + pdb.set_trace() electrode_keys["group_name"] = group_name electrode_keys = electrode_keys.sort_values(by=["electrode_id"]) + RippleLFPSelection().insert1( + {**key, "group_name": group_name}, + skip_duplicates=True, + **kwargs, + ) RippleLFPSelection().RippleLFPElectrode.insert( electrode_keys.to_dict(orient="records"), replace=True, @@ -137,10 +154,12 @@ def insert_default(self): @schema class RippleTimesV1(dj.Computed): definition = """ - -> RippleParameters -> RippleLFPSelection - -> PositionOutput + -> RippleParameters + -> PositionOutput.proj(pos_merge_id='merge_id') + --- + electrode_ids : mediumblob -> AnalysisNwbfile ripple_times_object_id : varchar(40) """ From 567d6460dd1f43fbdd571bee0cd93ce5e8b459bf Mon Sep 17 00:00:00 2001 From: dpeg22 Date: Thu, 13 Jul 2023 13:22:42 -0700 Subject: [PATCH 069/131] fix LFPBandV1 nwb object naming --- src/spyglass/lfp_band/v1/lfp_band.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/spyglass/lfp_band/v1/lfp_band.py b/src/spyglass/lfp_band/v1/lfp_band.py index 0077bc7d0..39d3a1a4b 100644 --- a/src/spyglass/lfp_band/v1/lfp_band.py +++ b/src/spyglass/lfp_band/v1/lfp_band.py @@ -383,10 +383,8 @@ def fetch1_dataframe(self, *attrs, **kwargs): """Fetches the filtered data as a dataframe""" filtered_nwb = self.fetch_nwb()[0] return pd.DataFrame( - filtered_nwb["filtered_data"].data, - index=pd.Index( - filtered_nwb["filtered_data"].timestamps, name="time" - ), + filtered_nwb["lfp_band"].data, + index=pd.Index(filtered_nwb["lfp_band"].timestamps, name="time"), ) def compute_analytic_signal(self, electrode_list: list[int], **kwargs): From 84f2559c462f9753d38fb4d5a9caa66cd73a3415 Mon Sep 17 00:00:00 2001 From: dpeg22 Date: Thu, 13 Jul 2023 13:23:07 -0700 Subject: [PATCH 070/131] Modify fetch1_dataframe method in PositionOutput --- src/spyglass/position/position_merge.py | 80 +++++-------------------- 1 file changed, 14 insertions(+), 66 deletions(-) diff --git a/src/spyglass/position/position_merge.py b/src/spyglass/position/position_merge.py index 5a21b8134..38d4dfb3a 100644 --- a/src/spyglass/position/position_merge.py +++ b/src/spyglass/position/position_merge.py @@ -5,6 +5,7 @@ import datajoint as dj import numpy as np import pandas as pd +from datajoint.utils import to_camel_case from tqdm import tqdm as tqdm from ..common.common_position import IntervalPositionInfo as CommonPos @@ -16,6 +17,12 @@ schema = dj.schema("position_merge") +source_class_dict = { + "IntervalPositionInfo": CommonPos, + "DLCPosV1": DLCPosV1, + "TrodesPosV1": TrodesPosV1, +} + @schema class PositionOutput(_Merge): @@ -68,73 +75,14 @@ class CommonPos(dj.Part): def fetch1_dataframe(self): # proj replaces operator restriction to enable # (TableName & restriction).fetch1_dataframe() - nwb_data = self.fetch_nwb(self.proj())[0] - index = pd.Index( - np.asarray(nwb_data["position"].get_spatial_series().timestamps), - name="time", - ) - if ( - "video_frame_ind" - in nwb_data["velocity"].fields["time_series"].keys() - ): - COLUMNS = [ - "video_frame_ind", - "position_x", - "position_y", - "orientation", - "velocity_x", - "velocity_y", - "speed", + key = self.merge_restrict(self.proj()) + query = ( + source_class_dict[ + to_camel_case(self.merge_get_parent(self.proj()).table_name) ] - return pd.DataFrame( - np.concatenate( - ( - np.asarray( - nwb_data["velocity"] - .get_timeseries("video_frame_ind") - .data, - dtype=int, - )[:, np.newaxis], - np.asarray( - nwb_data["position"].get_spatial_series().data - ), - np.asarray( - nwb_data["orientation"].get_spatial_series().data - )[:, np.newaxis], - np.asarray( - nwb_data["velocity"].get_timeseries("velocity").data - ), - ), - axis=1, - ), - columns=COLUMNS, - index=index, - ) - else: - COLUMNS = [ - "position_x", - "position_y", - "orientation", - "velocity_x", - "velocity_y", - "speed", - ] - return pd.DataFrame( - np.concatenate( - ( - np.asarray( - nwb_data["position"].get_spatial_series().data - ), - np.asarray( - nwb_data["orientation"].get_spatial_series().data - )[:, np.newaxis], - np.asarray(nwb_data["velocity"].get_timeseries().data), - ), - axis=1, - ), - columns=COLUMNS, - index=index, - ) + & key + ) + return query.fetch1_dataframe() @schema From f4dacf1d212f470ef72b608295dc97e4208575a3 Mon Sep 17 00:00:00 2001 From: dpeg22 Date: Thu, 13 Jul 2023 13:23:42 -0700 Subject: [PATCH 071/131] Multiple updates to ripple.py for new structure --- src/spyglass/ripple/v1/ripple.py | 88 +++++++++++++++----------------- 1 file changed, 42 insertions(+), 46 deletions(-) diff --git a/src/spyglass/ripple/v1/ripple.py b/src/spyglass/ripple/v1/ripple.py index 08930127b..d37c41b4c 100644 --- a/src/spyglass/ripple/v1/ripple.py +++ b/src/spyglass/ripple/v1/ripple.py @@ -25,6 +25,7 @@ UPSTREAM_ACCEPTED_VERSIONS = ["LFPBandV1"] + def interpolate_to_new_time( df, new_time, upsampling_interpolation_method="linear" ): @@ -56,16 +57,13 @@ class RippleLFPElectrode(dj.Part): -> LFPBandSelection.LFPBandElectrode """ - - def validated_insert1(self, key, **kwargs): - - def insert1(self, key, **kwargs): + @staticmethod + def validate_key(key): filter_name = LFPBandOutput.merge_get_parent( {"merge_id": key["lfp_band_merge_id"]} ).fetch1("filter_name") if "ripple" not in filter_name.lower(): raise UserWarning("Please use a ripple filter") - super().insert1(key, **kwargs) @staticmethod def set_lfp_electrodes( @@ -88,18 +86,23 @@ def set_lfp_electrodes( group_name : str, optional description of the electrode group, by default "CA1" """ - lfp_entry = LFPBandOutput.merge_get_parent( + lfp_key = LFPBandOutput.merge_get_parent( {"merge_id": key["lfp_band_merge_id"]} - ).fetch1() - source = (LFPBandOutput & {"merge_id": key["lfp_band_merge_id"]}).fetch1("source") + ).fetch1("KEY") + source = ( + LFPBandOutput & {"merge_id": key["lfp_band_merge_id"]} + ).fetch1("source") if source not in UPSTREAM_ACCEPTED_VERSIONS: - raise NotImplementedError("Ripple_V1 will currently only work with LFPBand_v1") + raise NotImplementedError( + "Ripple V1 will currently only work with LFPBandV1" + ) if electrode_list is None: - electrode_list = lfp_entry["electrode_ids"] + electrode_list = ( + (LFPBandSelection.LFPBandElectrode & lfp_key) + .fetch("electrode_id") + .tolist() + ) electrode_list.sort() - lfp_key = LFPBandOutput.merge_get_parent( - {"merge_id": key["lfp_band_merge_id"]} - ).fetch1("KEY") electrode_keys = ( pd.DataFrame(LFPBandSelection.LFPBandElectrode() & lfp_key) .set_index("electrode_id") @@ -107,11 +110,10 @@ def set_lfp_electrodes( .reset_index() .loc[:, LFPBandSelection.LFPBandElectrode.primary_key] ) - import pdb - - pdb.set_trace() electrode_keys["group_name"] = group_name + electrode_keys["lfp_band_merge_id"] = key["lfp_band_merge_id"] electrode_keys = electrode_keys.sort_values(by=["electrode_id"]) + RippleLFPSelection.validate_key(key) RippleLFPSelection().insert1( {**key, "group_name": group_name}, skip_duplicates=True, @@ -159,13 +161,17 @@ class RippleTimesV1(dj.Computed): -> PositionOutput.proj(pos_merge_id='merge_id') --- - electrode_ids : mediumblob -> AnalysisNwbfile ripple_times_object_id : varchar(40) """ def make(self, key): orig_key = copy.deepcopy(key) + + nwb_file_name, interval_list_name = LFPBandOutput.merge_get_parent( + {"merge_id": key["lfp_band_merge_id"]} + ).fetch1("nwb_file_name", "target_interval_list_name") + print(f"Computing ripple times for: {key}") ripple_params = ( RippleParameters & {"ripple_param_name": key["ripple_param_name"]} @@ -178,8 +184,9 @@ def make(self, key): speed, interval_ripple_lfps, sampling_frequency, - ) = self.get_ripple_lfps_and_position_info(key) - + ) = self.get_ripple_lfps_and_position_info( + key, nwb_file_name, interval_list_name + ) ripple_times = RIPPLE_DETECTION_ALGORITHMS[ripple_detection_algorithm]( time=np.asarray(interval_ripple_lfps.index), filtered_lfps=np.asarray(interval_ripple_lfps), @@ -187,24 +194,21 @@ def make(self, key): sampling_frequency=sampling_frequency, **ripple_detection_params, ) - # Insert into analysis nwb file nwb_analysis_file = AnalysisNwbfile() - key["analysis_file_name"] = nwb_analysis_file.create( - key["nwb_file_name"] - ) + key["analysis_file_name"] = nwb_analysis_file.create(nwb_file_name) key["ripple_times_object_id"] = nwb_analysis_file.add_nwb_object( analysis_file_name=key["analysis_file_name"], nwb_object=ripple_times, ) nwb_analysis_file.add( - nwb_file_name=key["nwb_file_name"], + nwb_file_name=nwb_file_name, analysis_file_name=key["analysis_file_name"], ) self.insert1(key) - # finally, we insert this into the LFP output table. + # finally, we insert this into the RippleTimesOutput table. from ..ripple_merge import RippleTimesOutput part_name = to_camel_case(self.table_name.split("__")[-1]) @@ -227,10 +231,9 @@ def fetch_dataframe(self): return [data["ripple_times"] for data in self.fetch_nwb()] @staticmethod - def get_ripple_lfps_and_position_info(key): - nwb_file_name = key["nwb_file_name"] - interval_list_name = key["target_interval_list_name"] - + def get_ripple_lfps_and_position_info( + key, nwb_file_name, interval_list_name + ): ripple_params = ( RippleParameters & {"ripple_param_name": key["ripple_param_name"]} ).fetch1("ripple_param_dict") @@ -242,25 +245,21 @@ def get_ripple_lfps_and_position_info(key): ) # warn/validate that there is only one wire per electrode - lfp_key = copy.deepcopy(key) - del lfp_key["interval_list_name"] - ripple_lfp_nwb = LFPBandOutput.fetch_nwb(lfp_key)[0] - ripple_lfp_electrodes = ripple_lfp_nwb["filtered_data"].electrodes.data[ - : - ] + ripple_lfp_nwb = LFPBandOutput.fetch_nwb( + {"merge_id": key["lfp_band_merge_id"]} + )[0] + ripple_lfp_electrodes = ripple_lfp_nwb["lfp_band"].electrodes.data[:] elec_mask = np.full_like(ripple_lfp_electrodes, 0, dtype=bool) valid_elecs = [ elec for elec in electrode_keys if elec in ripple_lfp_electrodes ] lfp_indexed_elec_ids = get_electrode_indices( - ripple_lfp_nwb["filtered_data"], valid_elecs + ripple_lfp_nwb["lfp_band"], valid_elecs ) elec_mask[lfp_indexed_elec_ids] = True ripple_lfp = pd.DataFrame( - ripple_lfp_nwb["filtered_data"].data, - index=pd.Index( - ripple_lfp_nwb["filtered_data"].timestamps, name="time" - ), + ripple_lfp_nwb["lfp_band"].data, + index=pd.Index(ripple_lfp_nwb["lfp_band"].timestamps, name="time"), ) sampling_frequency = ripple_lfp_nwb["lfp_band_sampling_rate"] @@ -274,12 +273,9 @@ def get_ripple_lfps_and_position_info(key): } ).fetch1("valid_times") - pos_key = { - k: v - for k, v in key.items() - if k in list(PositionOutput.fetch().dtype.fields.keys()) - } - position_info = (PositionOutput() & pos_key).fetch1_dataframe() + position_info = ( + PositionOutput() & {"merge_id": key["pos_merge_id"]} + ).fetch1_dataframe() position_info = pd.concat( [ From 720ec8815c8b5256dadb711b2126cc9a5b729a34 Mon Sep 17 00:00:00 2001 From: dpeg22 Date: Fri, 14 Jul 2023 14:28:15 -0700 Subject: [PATCH 072/131] restructure lfp directory --- src/spyglass/lfp/analysis/v1/__init__.py | 0 .../{lfp_band => lfp/analysis}/v1/lfp_band.py | 0 .../{ripple => lfp/analysis}/v1/ripple.py | 0 src/spyglass/lfp_band/__init__.py | 1 - src/spyglass/lfp_band/lfp_band_merge.py | 30 -------------- src/spyglass/lfp_band/v1/__init__.py | 1 - src/spyglass/ripple/__init__.py | 1 - src/spyglass/ripple/ripple_merge.py | 40 ------------------- src/spyglass/ripple/v1/__init__.py | 5 --- 9 files changed, 78 deletions(-) create mode 100644 src/spyglass/lfp/analysis/v1/__init__.py rename src/spyglass/{lfp_band => lfp/analysis}/v1/lfp_band.py (100%) rename src/spyglass/{ripple => lfp/analysis}/v1/ripple.py (100%) delete mode 100644 src/spyglass/lfp_band/__init__.py delete mode 100644 src/spyglass/lfp_band/lfp_band_merge.py delete mode 100644 src/spyglass/lfp_band/v1/__init__.py delete mode 100644 src/spyglass/ripple/__init__.py delete mode 100644 src/spyglass/ripple/ripple_merge.py delete mode 100644 src/spyglass/ripple/v1/__init__.py diff --git a/src/spyglass/lfp/analysis/v1/__init__.py b/src/spyglass/lfp/analysis/v1/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/spyglass/lfp_band/v1/lfp_band.py b/src/spyglass/lfp/analysis/v1/lfp_band.py similarity index 100% rename from src/spyglass/lfp_band/v1/lfp_band.py rename to src/spyglass/lfp/analysis/v1/lfp_band.py diff --git a/src/spyglass/ripple/v1/ripple.py b/src/spyglass/lfp/analysis/v1/ripple.py similarity index 100% rename from src/spyglass/ripple/v1/ripple.py rename to src/spyglass/lfp/analysis/v1/ripple.py diff --git a/src/spyglass/lfp_band/__init__.py b/src/spyglass/lfp_band/__init__.py deleted file mode 100644 index dea89719b..000000000 --- a/src/spyglass/lfp_band/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from spyglass.lfp_band.lfp_band_merge import LFPBandOutput diff --git a/src/spyglass/lfp_band/lfp_band_merge.py b/src/spyglass/lfp_band/lfp_band_merge.py deleted file mode 100644 index d5cafdcce..000000000 --- a/src/spyglass/lfp_band/lfp_band_merge.py +++ /dev/null @@ -1,30 +0,0 @@ -import datajoint as dj -import pandas as pd - -from spyglass.lfp_band.v1.lfp_band import LFPBandV1 # noqa F401 -from spyglass.utils.dj_merge_tables import Merge - -schema = dj.schema("lfp_band_merge") - - -@schema -class LFPBandOutput(Merge): - definition = """ - merge_id: uuid - --- - source: varchar(32) - """ - - class LFPBandV1(dj.Part): - definition = """ - -> master - --- - -> LFPBandV1 - """ - - def fetch1_dataframe(self, *attrs, **kwargs): - filtered_nwb = self.fetch_nwb()[0] - return pd.DataFrame( - filtered_nwb["lfp_band"].data, - index=pd.Index(filtered_nwb["lfp_band"].timestamps, name="time"), - ) diff --git a/src/spyglass/lfp_band/v1/__init__.py b/src/spyglass/lfp_band/v1/__init__.py deleted file mode 100644 index 92140cfd0..000000000 --- a/src/spyglass/lfp_band/v1/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from spyglass.lfp_band.v1.lfp_band import LFPBandV1, LFPBandSelection diff --git a/src/spyglass/ripple/__init__.py b/src/spyglass/ripple/__init__.py deleted file mode 100644 index 908fce6e5..000000000 --- a/src/spyglass/ripple/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from spyglass.ripple.ripple_merge import RippleTimesOutput diff --git a/src/spyglass/ripple/ripple_merge.py b/src/spyglass/ripple/ripple_merge.py deleted file mode 100644 index 118f5a55d..000000000 --- a/src/spyglass/ripple/ripple_merge.py +++ /dev/null @@ -1,40 +0,0 @@ -import datajoint as dj - -from spyglass.common.common_ripple import RippleTimes as CommonRipple -from .v1.ripple import RippleTimesV1 # noqa F401 -from spyglass.utils.dj_merge_tables import _Merge - -schema = dj.schema("ripple_merge") - - -@schema -class RippleTimesOutput(_Merge): - definition = """ - merge_id: uuid - --- - source: varchar(32) - """ - - class RippleTimesV1(dj.Part): - definition = """ - -> master - --- - -> RippleTimesV1 - """ - - class CommonRipple(dj.Part): - """Table to pass-through legacy RippleTimes""" - - definition = """ - -> master - --- - -> CommonRipple - """ - - def fetch1_dataframe(self): - """Convenience function for returning the marks in a readable format""" - return self.fetch_dataframe()[0] - - def fetch_dataframe(self): - # Note: `proj` below facilitates operator syntax eg Table & restrict - return [data["ripple_times"] for data in self.fetch_nwb(self.proj())] diff --git a/src/spyglass/ripple/v1/__init__.py b/src/spyglass/ripple/v1/__init__.py deleted file mode 100644 index 888624332..000000000 --- a/src/spyglass/ripple/v1/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from spyglass.ripple.v1.ripple import ( - RippleLFPSelection, - RippleParameters, - RippleTimesV1, -) From 9c0608aa2f98a2f9ca59f52df357141cc6793062 Mon Sep 17 00:00:00 2001 From: dpeg22 Date: Fri, 14 Jul 2023 16:06:53 -0700 Subject: [PATCH 073/131] restructure lfp and ripple --- src/spyglass/lfp/analysis/v1/__init__.py | 1 + src/spyglass/lfp/analysis/v1/lfp_band.py | 11 +---------- src/spyglass/ripple/__init__.py | 1 + src/spyglass/{lfp/analysis/v1 => ripple}/ripple.py | 8 +++----- 4 files changed, 6 insertions(+), 15 deletions(-) create mode 100644 src/spyglass/ripple/__init__.py rename src/spyglass/{lfp/analysis/v1 => ripple}/ripple.py (98%) diff --git a/src/spyglass/lfp/analysis/v1/__init__.py b/src/spyglass/lfp/analysis/v1/__init__.py index e69de29bb..d7a28c433 100644 --- a/src/spyglass/lfp/analysis/v1/__init__.py +++ b/src/spyglass/lfp/analysis/v1/__init__.py @@ -0,0 +1 @@ +from spyglass.lfp.analysis.v1 import LFPBandV1, LFPBandSelection diff --git a/src/spyglass/lfp/analysis/v1/lfp_band.py b/src/spyglass/lfp/analysis/v1/lfp_band.py index 39d3a1a4b..fe2977631 100644 --- a/src/spyglass/lfp/analysis/v1/lfp_band.py +++ b/src/spyglass/lfp/analysis/v1/lfp_band.py @@ -16,7 +16,7 @@ ) from spyglass.common.common_nwbfile import AnalysisNwbfile from spyglass.lfp.lfp_merge import LFPOutput -from spyglass.lfp.v1.lfp import LFPElectrodeGroup +from spyglass.lfp.lfp_electrodes import LFPElectrodeGroup from spyglass.utils.dj_helper_fn import fetch_nwb from spyglass.utils.nwb_helper_fn import get_electrode_indices @@ -365,15 +365,6 @@ def make(self, key): self.insert1(key) - from spyglass.lfp_band.lfp_band_merge import LFPBandOutput - - lfp_band_output_key = { - "merge_id": uuid.uuid1(), - "analysis_file_name": lfp_band_file_name, - "lfp_band_object_id": lfp_band_object_id, - } - LFPBandOutput.insert1(lfp_band_output_key) - def fetch_nwb(self, *attrs, **kwargs): return fetch_nwb( self, (AnalysisNwbfile, "analysis_file_abs_path"), *attrs, **kwargs diff --git a/src/spyglass/ripple/__init__.py b/src/spyglass/ripple/__init__.py new file mode 100644 index 000000000..ca2b6ef52 --- /dev/null +++ b/src/spyglass/ripple/__init__.py @@ -0,0 +1 @@ +from spyglass.ripple import RippleParameters, RippleLFPSelection, RippleTimesV1 diff --git a/src/spyglass/lfp/analysis/v1/ripple.py b/src/spyglass/ripple/ripple.py similarity index 98% rename from src/spyglass/lfp/analysis/v1/ripple.py rename to src/spyglass/ripple/ripple.py index d37c41b4c..76a0da7ec 100644 --- a/src/spyglass/lfp/analysis/v1/ripple.py +++ b/src/spyglass/ripple/ripple.py @@ -10,8 +10,7 @@ from spyglass.common import IntervalList # noqa from spyglass.common.common_nwbfile import AnalysisNwbfile -from spyglass.lfp_band.lfp_band_merge import LFPBandOutput -from spyglass.lfp_band.v1.lfp_band import LFPBandSelection +from spyglass.lfp.analysis.v1.lfp_band import LFPBandSelection, LFPBandV1 from spyglass.position import PositionOutput from spyglass.utils.dj_helper_fn import fetch_nwb from spyglass.utils.nwb_helper_fn import get_electrode_indices @@ -23,6 +22,7 @@ "Karlsson_ripple_detector": Karlsson_ripple_detector, } +# Do we need this anymore given that LFPBand is no longer a merge table? UPSTREAM_ACCEPTED_VERSIONS = ["LFPBandV1"] @@ -59,9 +59,7 @@ class RippleLFPElectrode(dj.Part): @staticmethod def validate_key(key): - filter_name = LFPBandOutput.merge_get_parent( - {"merge_id": key["lfp_band_merge_id"]} - ).fetch1("filter_name") + filter_name = (LFPBandV1 & key).fetch1("filter_name") if "ripple" not in filter_name.lower(): raise UserWarning("Please use a ripple filter") From 7da38dd9f6fa2c43c7fc58e16b00c789add39a95 Mon Sep 17 00:00:00 2001 From: dpeg22 Date: Fri, 14 Jul 2023 16:07:08 -0700 Subject: [PATCH 074/131] move LFPElectrodeGroup to lfp_electrodes --- src/spyglass/lfp/lfp_electrodes.py | 102 +++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 src/spyglass/lfp/lfp_electrodes.py diff --git a/src/spyglass/lfp/lfp_electrodes.py b/src/spyglass/lfp/lfp_electrodes.py new file mode 100644 index 000000000..72227da02 --- /dev/null +++ b/src/spyglass/lfp/lfp_electrodes.py @@ -0,0 +1,102 @@ +import datajoint as dj +from spyglass.common.common_ephys import Electrode +from spyglass.common.common_session import Session + +schema = dj.schema("lfp_electrodes") + + +@schema +class LFPElectrodeGroup(dj.Manual): + definition = """ + -> Session # the session to which this LFP belongs + lfp_electrode_group_name: varchar(200) # the name of this group of electrodes + """ + + class LFPElectrode(dj.Part): + definition = """ + -> LFPElectrodeGroup # the group of electrodes to be filtered + -> Electrode # the electrode to be filtered + """ + + @staticmethod + def create_lfp_electrode_group( + nwb_file_name: str, group_name: str, electrode_list: list[int] + ): + """Adds an LFPElectrodeGroup and the individual electrodes + + Parameters + ---------- + nwb_file_name : str + The name of the nwb file (e.g. the session) + group_name : str + The name of this group (< 200 char) + electrode_list : list + A list of the electrode ids to include in this group. + """ + # remove the session and then recreate the session and Electrode list + # check to see if the user allowed the deletion + key = { + "nwb_file_name": nwb_file_name, + "lfp_electrode_group_name": group_name, + } + LFPElectrodeGroup().insert1(key, skip_duplicates=True) + + # TODO: do this in a better way + all_electrodes = (Electrode() & {"nwb_file_name": nwb_file_name}).fetch( + as_dict=True + ) + primary_key = Electrode.primary_key + for e in all_electrodes: + # create a dictionary so we can insert the electrodes + if e["electrode_id"] in electrode_list: + lfpelectdict = {k: v for k, v in e.items() if k in primary_key} + lfpelectdict["lfp_electrode_group_name"] = group_name + LFPElectrodeGroup().LFPElectrode.insert1( + lfpelectdict, skip_duplicates=True + ) + + +# @schema +# class LFPElectrodeGroups(dj.Manual): +# definition = """ +# -> common_session.Session +# group_id: uint +# target: varchar(32) +# --- +# lfp_electrode_group_name: varchar(32) # the name of this group of electrodes +# parent_set: group_id of upstream set +# """ + +# def insert_entry(key, **kwargs): +# if paramset_idx is None: +# paramset_idx = ( +# dj.U().aggr(cls, n="max(paramset_idx)").fetch1("n") or 0 +# ) + 1 + +# class Electrodes(dj.Part): +# definition=""" + +# electrode_id: int +# """ + + +# class LFP(dj.Part): +# definition = """ +# id: int +# """ + +# class LFPBand(dj.Part): +# definition = """ +# id: int +# """ + +# class Ripple(dj.Part): +# definition = """ +# id: int +# """ + +# def validate_insert(key, **kwargs): +# pass + +# def validate_delete(restriction=None, **kwargs): +# pass From a3e1430030828beb30baf9a8306746905665362f Mon Sep 17 00:00:00 2001 From: dpeg22 Date: Wed, 19 Jul 2023 11:50:19 -0700 Subject: [PATCH 075/131] change directory structure for lfp --- src/spyglass/lfp/analysis/v1/__init__.py | 1 - src/spyglass/lfp/v1/__init__.py | 1 + src/spyglass/lfp/{analysis => }/v1/lfp_band.py | 0 src/spyglass/ripple/ripple.py | 2 +- 4 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 src/spyglass/lfp/analysis/v1/__init__.py rename src/spyglass/lfp/{analysis => }/v1/lfp_band.py (100%) diff --git a/src/spyglass/lfp/analysis/v1/__init__.py b/src/spyglass/lfp/analysis/v1/__init__.py deleted file mode 100644 index d7a28c433..000000000 --- a/src/spyglass/lfp/analysis/v1/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from spyglass.lfp.analysis.v1 import LFPBandV1, LFPBandSelection diff --git a/src/spyglass/lfp/v1/__init__.py b/src/spyglass/lfp/v1/__init__.py index 2530a2fc0..8db41f64c 100644 --- a/src/spyglass/lfp/v1/__init__.py +++ b/src/spyglass/lfp/v1/__init__.py @@ -11,3 +11,4 @@ LFPArtifactDetectionSelection, LFPArtifactRemovedIntervalList, ) +from spyglass.lfp.v1.lfp_band import LFPBandV1, LFPBandSelection diff --git a/src/spyglass/lfp/analysis/v1/lfp_band.py b/src/spyglass/lfp/v1/lfp_band.py similarity index 100% rename from src/spyglass/lfp/analysis/v1/lfp_band.py rename to src/spyglass/lfp/v1/lfp_band.py diff --git a/src/spyglass/ripple/ripple.py b/src/spyglass/ripple/ripple.py index 76a0da7ec..1dac4dc5c 100644 --- a/src/spyglass/ripple/ripple.py +++ b/src/spyglass/ripple/ripple.py @@ -10,7 +10,7 @@ from spyglass.common import IntervalList # noqa from spyglass.common.common_nwbfile import AnalysisNwbfile -from spyglass.lfp.analysis.v1.lfp_band import LFPBandSelection, LFPBandV1 +from spyglass.lfp.v1.lfp_band import LFPBandSelection, LFPBandV1 from spyglass.position import PositionOutput from spyglass.utils.dj_helper_fn import fetch_nwb from spyglass.utils.nwb_helper_fn import get_electrode_indices From 4328bb6764bc52ba716accb1216c33cfb7a6e9ae Mon Sep 17 00:00:00 2001 From: dpeg22 Date: Wed, 19 Jul 2023 15:30:58 -0700 Subject: [PATCH 076/131] fix object naming in lfp_band --- src/spyglass/lfp/v1/lfp_band.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spyglass/lfp/v1/lfp_band.py b/src/spyglass/lfp/v1/lfp_band.py index fe2977631..2e7a0adbd 100644 --- a/src/spyglass/lfp/v1/lfp_band.py +++ b/src/spyglass/lfp/v1/lfp_band.py @@ -397,7 +397,7 @@ def compute_analytic_signal(self, electrode_list: list[int], **kwargs): If any electrodes passed to electrode_list are invalid for the dataset """ - filtered_band = self.fetch_nwb()[0]["filtered_data"] + filtered_band = self.fetch_nwb()[0]["lfp_band"] electrode_index = np.isin( filtered_band.electrodes.data[:], electrode_list ) From fdb4ed350861a053973cb5cad5f0cf6dcb2ef1c7 Mon Sep 17 00:00:00 2001 From: dpeg22 Date: Thu, 20 Jul 2023 10:31:12 -0700 Subject: [PATCH 077/131] move LFPElectrodeGroup to lfp_electrode.py --- src/spyglass/lfp/__init__.py | 1 + src/spyglass/lfp/lfp_electrode.py | 57 +++++++++++++++++++++++++++++++ src/spyglass/lfp/v1/lfp.py | 54 ++--------------------------- 3 files changed, 60 insertions(+), 52 deletions(-) create mode 100644 src/spyglass/lfp/lfp_electrode.py diff --git a/src/spyglass/lfp/__init__.py b/src/spyglass/lfp/__init__.py index f0b973f5b..9474d30d4 100644 --- a/src/spyglass/lfp/__init__.py +++ b/src/spyglass/lfp/__init__.py @@ -1 +1,2 @@ from spyglass.lfp.lfp_merge import LFPOutput +from spyglass.lfp.lfp_electrode import LFPElectrodeGroup diff --git a/src/spyglass/lfp/lfp_electrode.py b/src/spyglass/lfp/lfp_electrode.py new file mode 100644 index 000000000..5e4f1b193 --- /dev/null +++ b/src/spyglass/lfp/lfp_electrode.py @@ -0,0 +1,57 @@ +import datajoint as dj + +from spyglass.common.common_ephys import Electrode +from spyglass.common.common_session import Session + +schema = dj.schema("lfp_electrode") + + +@schema +class LFPElectrodeGroup(dj.Manual): + definition = """ + -> Session # the session to which this LFP belongs + lfp_electrode_group_name: varchar(200) # the name of this group of electrodes + """ + + class LFPElectrode(dj.Part): + definition = """ + -> LFPElectrodeGroup # the group of electrodes to be filtered + -> Electrode # the electrode to be filtered + """ + + @staticmethod + def create_lfp_electrode_group( + nwb_file_name: str, group_name: str, electrode_list: list[int] + ): + """Adds an LFPElectrodeGroup and the individual electrodes + + Parameters + ---------- + nwb_file_name : str + The name of the nwb file (e.g. the session) + group_name : str + The name of this group (< 200 char) + electrode_list : list + A list of the electrode ids to include in this group. + """ + # remove the session and then recreate the session and Electrode list + # check to see if the user allowed the deletion + key = { + "nwb_file_name": nwb_file_name, + "lfp_electrode_group_name": group_name, + } + LFPElectrodeGroup().insert1(key, skip_duplicates=True) + + # TODO: do this in a better way + all_electrodes = (Electrode() & {"nwb_file_name": nwb_file_name}).fetch( + as_dict=True + ) + primary_key = Electrode.primary_key + for e in all_electrodes: + # create a dictionary so we can insert the electrodes + if e["electrode_id"] in electrode_list: + lfpelectdict = {k: v for k, v in e.items() if k in primary_key} + lfpelectdict["lfp_electrode_group_name"] = group_name + LFPElectrodeGroup().LFPElectrode.insert1( + lfpelectdict, skip_duplicates=True + ) diff --git a/src/spyglass/lfp/v1/lfp.py b/src/spyglass/lfp/v1/lfp.py index c44ff4986..404a7a6d8 100644 --- a/src/spyglass/lfp/v1/lfp.py +++ b/src/spyglass/lfp/v1/lfp.py @@ -4,7 +4,8 @@ import numpy as np import pandas as pd -from spyglass.common.common_ephys import Electrode, Raw +from spyglass.common.common_ephys import Raw +from spyglass.lfp.lfp_electrode import LFPElectrodeGroup from spyglass.common.common_filter import FirFilterParameters from spyglass.common.common_interval import ( IntervalList, @@ -20,57 +21,6 @@ MIN_LFP_INTERVAL_DURATION = 1.0 # 1 second minimum interval duration -@schema -class LFPElectrodeGroup(dj.Manual): - definition = """ - -> Session # the session to which this LFP belongs - lfp_electrode_group_name: varchar(200) # the name of this group of electrodes - """ - - class LFPElectrode(dj.Part): - definition = """ - -> LFPElectrodeGroup # the group of electrodes to be filtered - -> Electrode # the electrode to be filtered - """ - - @staticmethod - def create_lfp_electrode_group( - nwb_file_name: str, group_name: str, electrode_list: list[int] - ): - """Adds an LFPElectrodeGroup and the individual electrodes - - Parameters - ---------- - nwb_file_name : str - The name of the nwb file (e.g. the session) - group_name : str - The name of this group (< 200 char) - electrode_list : list - A list of the electrode ids to include in this group. - """ - # remove the session and then recreate the session and Electrode list - # check to see if the user allowed the deletion - key = { - "nwb_file_name": nwb_file_name, - "lfp_electrode_group_name": group_name, - } - LFPElectrodeGroup().insert1(key, skip_duplicates=True) - - # TODO: do this in a better way - all_electrodes = (Electrode() & {"nwb_file_name": nwb_file_name}).fetch( - as_dict=True - ) - primary_key = Electrode.primary_key - for e in all_electrodes: - # create a dictionary so we can insert the electrodes - if e["electrode_id"] in electrode_list: - lfpelectdict = {k: v for k, v in e.items() if k in primary_key} - lfpelectdict["lfp_electrode_group_name"] = group_name - LFPElectrodeGroup().LFPElectrode.insert1( - lfpelectdict, skip_duplicates=True - ) - - @schema class LFPSelection(dj.Manual): """The user's selection of LFP data to be filtered From 738f34b3ee3ccdf4118d9ee9f9843f3de26060a4 Mon Sep 17 00:00:00 2001 From: dpeg22 Date: Thu, 20 Jul 2023 15:17:47 -0700 Subject: [PATCH 078/131] change import to lfp_band --- src/spyglass/lfp/lfp_electrodes.py | 102 ----------------------------- src/spyglass/lfp/v1/lfp_band.py | 4 +- 2 files changed, 1 insertion(+), 105 deletions(-) delete mode 100644 src/spyglass/lfp/lfp_electrodes.py diff --git a/src/spyglass/lfp/lfp_electrodes.py b/src/spyglass/lfp/lfp_electrodes.py deleted file mode 100644 index 72227da02..000000000 --- a/src/spyglass/lfp/lfp_electrodes.py +++ /dev/null @@ -1,102 +0,0 @@ -import datajoint as dj -from spyglass.common.common_ephys import Electrode -from spyglass.common.common_session import Session - -schema = dj.schema("lfp_electrodes") - - -@schema -class LFPElectrodeGroup(dj.Manual): - definition = """ - -> Session # the session to which this LFP belongs - lfp_electrode_group_name: varchar(200) # the name of this group of electrodes - """ - - class LFPElectrode(dj.Part): - definition = """ - -> LFPElectrodeGroup # the group of electrodes to be filtered - -> Electrode # the electrode to be filtered - """ - - @staticmethod - def create_lfp_electrode_group( - nwb_file_name: str, group_name: str, electrode_list: list[int] - ): - """Adds an LFPElectrodeGroup and the individual electrodes - - Parameters - ---------- - nwb_file_name : str - The name of the nwb file (e.g. the session) - group_name : str - The name of this group (< 200 char) - electrode_list : list - A list of the electrode ids to include in this group. - """ - # remove the session and then recreate the session and Electrode list - # check to see if the user allowed the deletion - key = { - "nwb_file_name": nwb_file_name, - "lfp_electrode_group_name": group_name, - } - LFPElectrodeGroup().insert1(key, skip_duplicates=True) - - # TODO: do this in a better way - all_electrodes = (Electrode() & {"nwb_file_name": nwb_file_name}).fetch( - as_dict=True - ) - primary_key = Electrode.primary_key - for e in all_electrodes: - # create a dictionary so we can insert the electrodes - if e["electrode_id"] in electrode_list: - lfpelectdict = {k: v for k, v in e.items() if k in primary_key} - lfpelectdict["lfp_electrode_group_name"] = group_name - LFPElectrodeGroup().LFPElectrode.insert1( - lfpelectdict, skip_duplicates=True - ) - - -# @schema -# class LFPElectrodeGroups(dj.Manual): -# definition = """ -# -> common_session.Session -# group_id: uint -# target: varchar(32) -# --- -# lfp_electrode_group_name: varchar(32) # the name of this group of electrodes -# parent_set: group_id of upstream set -# """ - -# def insert_entry(key, **kwargs): -# if paramset_idx is None: -# paramset_idx = ( -# dj.U().aggr(cls, n="max(paramset_idx)").fetch1("n") or 0 -# ) + 1 - -# class Electrodes(dj.Part): -# definition=""" - -# electrode_id: int -# """ - - -# class LFP(dj.Part): -# definition = """ -# id: int -# """ - -# class LFPBand(dj.Part): -# definition = """ -# id: int -# """ - -# class Ripple(dj.Part): -# definition = """ -# id: int -# """ - -# def validate_insert(key, **kwargs): -# pass - -# def validate_delete(restriction=None, **kwargs): -# pass diff --git a/src/spyglass/lfp/v1/lfp_band.py b/src/spyglass/lfp/v1/lfp_band.py index 2e7a0adbd..05e20dced 100644 --- a/src/spyglass/lfp/v1/lfp_band.py +++ b/src/spyglass/lfp/v1/lfp_band.py @@ -1,5 +1,3 @@ -import uuid - import datajoint as dj import numpy as np import pandas as pd @@ -16,7 +14,7 @@ ) from spyglass.common.common_nwbfile import AnalysisNwbfile from spyglass.lfp.lfp_merge import LFPOutput -from spyglass.lfp.lfp_electrodes import LFPElectrodeGroup +from spyglass.lfp.lfp_electrode import LFPElectrodeGroup from spyglass.utils.dj_helper_fn import fetch_nwb from spyglass.utils.nwb_helper_fn import get_electrode_indices From 720521abdb5f83e31496ca8fcc3cc4c98d8cabc5 Mon Sep 17 00:00:00 2001 From: Loren Frank Date: Thu, 20 Jul 2023 15:22:27 -0700 Subject: [PATCH 079/131] removed random_chunk dict from snr --- src/spyglass/spikesorting/spikesorting_curation.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/spyglass/spikesorting/spikesorting_curation.py b/src/spyglass/spikesorting/spikesorting_curation.py index 7dc63105f..602be4484 100644 --- a/src/spyglass/spikesorting/spikesorting_curation.py +++ b/src/spyglass/spikesorting/spikesorting_curation.py @@ -392,11 +392,11 @@ class MetricParameters(dj.Manual): metric_default_params = { "snr": { "peak_sign": "neg", - "random_chunk_kwargs_dict": { - "num_chunks_per_segment": 20, - "chunk_size": 10000, - "seed": 0, - }, + # "random_chunk_kwargs_dict": { + # "num_chunks_per_segment": 20, + # "chunk_size": 10000, + # "seed": 0, + # }, }, "isi_violation": {"isi_threshold_ms": 1.5, "min_isi_ms": 0.0}, "nn_isolation": { From d1f580ed59d888c8eb9527333ba5f45e07604d95 Mon Sep 17 00:00:00 2001 From: Denisse Morales-Rodriguez Date: Thu, 20 Jul 2023 16:03:23 -0700 Subject: [PATCH 080/131] fixed nn_isolation to return one number --- src/spyglass/spikesorting/spikesorting_curation.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/spyglass/spikesorting/spikesorting_curation.py b/src/spyglass/spikesorting/spikesorting_curation.py index 602be4484..2a3420abb 100644 --- a/src/spyglass/spikesorting/spikesorting_curation.py +++ b/src/spyglass/spikesorting/spikesorting_curation.py @@ -392,11 +392,11 @@ class MetricParameters(dj.Manual): metric_default_params = { "snr": { "peak_sign": "neg", - # "random_chunk_kwargs_dict": { - # "num_chunks_per_segment": 20, - # "chunk_size": 10000, - # "seed": 0, - # }, + "random_chunk_kwargs_dict": { + "num_chunks_per_segment": 20, + "chunk_size": 10000, + "seed": 0, + }, }, "isi_violation": {"isi_threshold_ms": 1.5, "min_isi_ms": 0.0}, "nn_isolation": { @@ -551,6 +551,9 @@ def _compute_metric(self, waveform_extractor, metric_name, **metric_params): metric[str(unit_id)] = metric_func( waveform_extractor, this_unit_id=unit_id, **metric_params ) + #nn_isolation returns tuple with isolation and unit number. We only want isolation. + if metric_name == "nn_isolation": + metric[str(unit_id)] = metric[str(unit_id)][0] return metric def _dump_to_json(self, qm_dict, save_path): From fb2f491fdea746c51a36ed462ec91cb73a52f9a9 Mon Sep 17 00:00:00 2001 From: Ryan Ly Date: Mon, 24 Jul 2023 13:57:43 -0400 Subject: [PATCH 081/131] Add notebook demonstrating some approaches to alter tables manually (#600) Co-authored-by: CBroz1 --- examples/db_alter.ipynb | 1699 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 1699 insertions(+) create mode 100644 examples/db_alter.ipynb diff --git a/examples/db_alter.ipynb b/examples/db_alter.ipynb new file mode 100644 index 000000000..3ae8502b6 --- /dev/null +++ b/examples/db_alter.ipynb @@ -0,0 +1,1699 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "b275c085-5542-445e-9f42-b4f2773adad2", + "metadata": { + "tags": [] + }, + "source": [ + "# Altering a Spyglass DataJoint table\n" + ] + }, + { + "cell_type": "markdown", + "id": "944d8595-62e5-4fb2-acfd-bbeee3d017f1", + "metadata": {}, + "source": [ + "This notebook was used to do the following modifications to Loren Frank Lab's Spyglass database:\n", + "\n", + "1. Move table LFPElectrodeGroup from lfp_v1 schema to new schema called lfp_electrode\n", + "2. Move table ImportedLFPV1 from lfp_v1 schema to new schema called lfp_imported\n", + "3. Remove empty tables in the lfp-related schema that are not associated with any code and create issues when plotting ERDs\n", + "\n", + "See https://github.com/LorenFrankLab/spyglass/pull/594\n" + ] + }, + { + "cell_type": "markdown", + "id": "6ccd0dd5-9190-429a-afa5-d8ad0b8ba8c9", + "metadata": {}, + "source": [ + "# Prepare local test database using backup of production database\n", + "\n", + "```\n", + "# ssh into a frank lab machine\n", + "ssh rly@typhoon.cin.ucsf.edu -p XXXX\n", + "\n", + "# zip up the latest database backup and place in your home directory on the frank lab remote storage\n", + "# change the dates in the file names as appropriate\n", + "tar -cvf lmf-db-20230722.tar.gz /stelmo/mysql-backup/lmf-db-20230722/\n", + "\n", + "# NOTE: we may only really need the mysql-all.sql file but it's good to have a full backup handy\n", + "\n", + "# copy the zipped up database backup to your local machine\n", + "# NOTE: this is a large file >11 GB\n", + "scp -P XXXX rly@typhoon.cin.ucsf.edu:lmf-db-20230722.tar.gz ~/Downloads/\n", + "cd ~/Downloads\n", + "tar -xzvf lmf-db-20230720.tar.gz\n", + "# this will unzip into a stelmo folder in ~/Downloads\n", + "\n", + "# start a clean datajoint mysql database in docker locally\n", + "# on Ryan's laptop, that involves:\n", + "cd ~/Documents/NWB/datajoint-mysql-docker\n", + "docker-compose up -d\n", + "\n", + "# load the database backup into the local empty database\n", + "# this will take ~20 minutes depending on the size of the backup and speed of the computer...\n", + "cat ~/Downloads/stelmo/mysql-backup/lmf-db-20230722/mysql-all.sql | docker exec -i dj mysql -u root --password=tutorial -h 127.0.0.1\n", + "```\n" + ] + }, + { + "cell_type": "markdown", + "id": "bfdd35de-5592-4116-95e3-c1dc900a085d", + "metadata": {}, + "source": [ + "# Examine the backup file for references to the tables being altered\n", + "\n", + "For LFPElectrodeGroup (encoded as l_f_p_electrode_group in mysql tables):\n", + "\n", + "Search for all instances of the table name being altered in mysql-all.sql\n", + "\n", + "```\n", + "grep l_f_p_electrode_group ~/Downloads/stelmo/mysql-backup/lmf-db-20230722/mysql-all.sql > out.txt\n", + "```\n", + "\n", + "take note of which tables these are in. for example:\n", + "\n", + "- l_f_p_band_selection**l_f_p_band_electrode_ibfk_2 is a foreign key from LFPBandSelection.\\_LFPBandElectrode that references\n", + " `` `lfp_v1`.`l_f_p_electrode_group**l_f_p_electrode` ``\n", + "- similarly for \\_imported_l_f_p_ibfk_2 and \\_imported_l_f_p_v1_ibfk_2\n", + "- l_f_p_band_selection**l_f_p_band_electrode_ibfk_2 is a foreign key from LFPBandSelection.\\_LFPBandElectrode that references\n", + " `l_f_p_electrode_group**l_f_p_electrode`\n", + "- l_f_p_selection_ibfk_1 is a foreign key from LFPSelection that references `l_f_p_electrode_group`\n", + "\n", + "ignore all logs and innodb_table_stats.\n", + "\n", + "use `grep -A 20 -B 20` to get context around each match\n", + "\n", + "also search the spyglass codebase for references to this table\n", + "\n", + "- imported in `lfp/v1/__init__.py`\n", + "- defined in `lfp/v1/lfp.py`\n", + "- has a part table\n", + "- used as primary key in LFPSelection in `lfp/v1/lfp.py`\n", + "- used in make function of LFPV1\n", + "- used as primary key in ImportedLFPV1 in `lfp/v1/lfp.py`\n", + "- used as primary key in LFPBandSelection.LFPBandElectrode in `lfp_band/v1/lfp_band.py` and in code\n", + "\n", + "- the `lfp/v1/lfp.py::ImportedLFP` table is not in the codebase and therefore should not exist in the database. It is empty and seems to be causing issues with plotting ERDs. It must have been created once from a local or temporary version of the codebase and then the code was updated.\n", + "- LFPOutput.ImportedLFP still has a foreign key to ImportedLFP. This should be a foreign key to ImportedLFPV1.\n", + "\n", + "The ImportedLFPV1 table is being moved and renamed. LFPOutput.ImportedLFPV1 is also being renamed.\n", + "\n", + "- it is currently empty.\n", + "- ImportedLFP is also empty.\n", + "- LFPOutput.ImportedLFP is also empty.\n", + "\n", + "Drop all these tables and re-initialize with the PR.\n", + "\n", + "Need to find all the foreign keys to these tables and drop those keys (or tables) before dropping the above tables.\n", + "In this order:\n", + "\n", + "- Drop empty LFPMerge.ImportedLFPV1\n", + "- Drop empty LFPOutput.ImportedLFP\n", + "- Drop empty ImportedLFPV1\n", + "- Drop empty ImportedLFP\n", + " ...\n", + "\n", + "Delete the local docker volume and reload the backup database as needed to nail down the sequence of steps that you will perform on the production database.\n" + ] + }, + { + "cell_type": "markdown", + "id": "8153d27e-0aff-43f5-a695-be7036945e1c", + "metadata": {}, + "source": [ + "# Make sure your repo is on the master branch\n" + ] + }, + { + "cell_type": "markdown", + "id": "9610c0f7-d830-4d81-b539-813485ccece6", + "metadata": {}, + "source": [ + "# Configure a connection to the local database for a dry run - skip this cell if running on frank lab servers on the production database\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6d8f3047-349a-4830-8bfd-911b0df5bb47", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "import datajoint as dj\n", + "import os\n", + "from pathlib import Path\n", + "\n", + "# set dirs\n", + "base_dir = Path(\n", + " \"/Users/rly/Documents/NWB/spyglass-workspace\"\n", + ") # change this to your desired directory\n", + "raw_dir = base_dir / \"raw\"\n", + "analysis_dir = base_dir / \"analysis\"\n", + "recording_dir = base_dir / \"recording\"\n", + "sorting_dir = base_dir / \"sorting\"\n", + "waveforms_dir = base_dir / \"waveforms\"\n", + "tmp_dir = base_dir / \"tmp\"\n", + "kachery_cloud_dir = base_dir / \".kachery_cloud\"\n", + "\n", + "os.makedirs(raw_dir, exist_ok=True)\n", + "os.makedirs(analysis_dir, exist_ok=True)\n", + "os.makedirs(recording_dir, exist_ok=True)\n", + "os.makedirs(sorting_dir, exist_ok=True)\n", + "os.makedirs(waveforms_dir, exist_ok=True)\n", + "os.makedirs(tmp_dir, exist_ok=True)\n", + "os.makedirs(kachery_cloud_dir, exist_ok=True)\n", + "\n", + "# set dj config\n", + "dj.config[\"database.host\"] = \"localhost\"\n", + "dj.config[\"database.user\"] = \"root\"\n", + "dj.config[\"database.password\"] = \"tutorial\"\n", + "dj.config[\"database.port\"] = 3306\n", + "dj.config[\"stores\"] = {\n", + " \"raw\": {\n", + " \"protocol\": \"file\",\n", + " \"location\": str(raw_dir),\n", + " \"stage\": str(raw_dir),\n", + " },\n", + " \"analysis\": {\n", + " \"protocol\": \"file\",\n", + " \"location\": str(analysis_dir),\n", + " \"stage\": str(analysis_dir),\n", + " },\n", + "}\n", + "dj.config[\"enable_python_native_blobs\"] = True\n", + "\n", + "# set env vars\n", + "os.environ[\"SPYGLASS_BASE_DIR\"] = str(base_dir)\n", + "os.environ[\"SPYGLASS_RECORDING_DIR\"] = str(recording_dir)\n", + "os.environ[\"SPYGLASS_SORTING_DIR\"] = str(sorting_dir)\n", + "os.environ[\"SPYGLASS_WAVEFORMS_DIR\"] = str(waveforms_dir)\n", + "os.environ[\"SPYGLASS_TEMP_DIR\"] = str(tmp_dir)\n", + "os.environ[\"KACHERY_CLOUD_DIR\"] = str(kachery_cloud_dir)\n", + "os.environ[\"DJ_SUPPORT_FILEPATH_MANAGEMENT\"] = \"TRUE\"" + ] + }, + { + "cell_type": "markdown", + "id": "9e2f53b3-8e47-4542-88db-61c5865214a2", + "metadata": {}, + "source": [ + "# Start here instead of above if running on the Frank Lab servers on the production database\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5ee60967-f5b2-4654-a939-fd519b512c62", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "import datajoint as dj\n", + "import spyglass as sg\n", + "\n", + "sg.config[\"prepopulate\"] = False\n", + "\n", + "import spyglass.common as sgc\n", + "import spyglass.data_import as sgdi\n", + "import spyglass.lfp as lfp\n", + "import spyglass.lfp.v1 as lfp_v1\n", + "import spyglass.lfp_band as lfp_band\n", + "import spyglass.lfp_band.lfp_band_merge as lfp_band_merge" + ] + }, + { + "cell_type": "markdown", + "id": "681d51ca-cf1b-4b9c-b4d1-4cbb94506195", + "metadata": {}, + "source": [ + "# Plot ERDs of the tables being altered to see what tables depend on these tables\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "35d789b7-b72d-474b-b17d-672d98149511", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "dj.ERD(lfp_v1.LFPElectrodeGroup) + 2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cb7cfe57-9641-4be0-88ad-b666732ca7a8", + "metadata": {}, + "outputs": [], + "source": [ + "dj.ERD(lfp_v1.ImportedLFP) + 2" + ] + }, + { + "cell_type": "markdown", + "id": "922847bc-a820-4327-9927-1dd27febe482", + "metadata": {}, + "source": [ + "# Start with tasks #2 and #3\n" + ] + }, + { + "cell_type": "markdown", + "id": "82b66064-f9e6-4cd0-acfd-5eb5feb3b1e2", + "metadata": {}, + "source": [ + "# Confirm that the tables being dropped are empty\n", + "\n", + "- If the table exists, just print the contents, e.g., `lfp.LFPOutput.ImportedLFPV1`\n", + "- If the table does not exist, use a MySQL database browser, like TablePlus for macOS.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fcd619e9-fa99-4baa-97ca-48a08bd10c86", + "metadata": {}, + "outputs": [], + "source": [ + "lfp.LFPOutput.ImportedLFPV1()" + ] + }, + { + "cell_type": "markdown", + "id": "437dabfa-e7cc-4094-acb3-3242200df9c7", + "metadata": {}, + "source": [ + "The `lfp_v1.l_f_p_output` table shouldn't even exist anymore. There are no references in the codebase to it anymore. It should have been replaced with the `lfp_merge.l_f_p_output` table. But the data in the two tables differ... Probably `lfp_v1.l_f_p_output` is old. It has only 80 rows. Ignore this for now.\n" + ] + }, + { + "cell_type": "markdown", + "id": "dd0dce66-6373-4ece-a4ba-8becef0bba31", + "metadata": {}, + "source": [ + "# Drop tables starting with those that no other tables depend upon\n", + "\n", + "Carefully, one at a time...\n", + "\n", + "The expected output if the command passes is ``\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2d8e2279-ee93-4a93-847f-9c228566528f", + "metadata": {}, + "outputs": [], + "source": [ + "conn = dj.conn()\n", + "conn.query(\"USE `lfp_merge`\")\n", + "conn.query(\n", + " \"DROP TABLE `lfp_merge`.`l_f_p_output__imported_l_f_p_v1`\"\n", + ") # can't use datajoint to drop this because it's a part table" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "39560434-f383-474c-94cd-5ffdaba8dc4f", + "metadata": {}, + "outputs": [], + "source": [ + "conn = dj.conn()\n", + "conn.query(\"USE `lfp_v1`\")\n", + "conn.query(\n", + " \"DROP TABLE `lfp_v1`.`l_f_p_output__imported_l_f_p`\"\n", + ") # can't use datajoint to drop this because it's a part table and also doesn't exist in the code" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9c6ff6fc-2c88-4956-a379-d35a931984c7", + "metadata": {}, + "outputs": [], + "source": [ + "conn = dj.conn()\n", + "conn.query(\"USE `lfp_v1`\")\n", + "conn.query(\n", + " \"DROP TABLE `lfp_v1`.`_imported_l_f_p_v1`\"\n", + ") # can't use datajoint to drop this because it doesn't exist in the code" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d87ffa17-a776-4171-bf51-4295dea9f9d6", + "metadata": {}, + "outputs": [], + "source": [ + "conn = dj.conn()\n", + "conn.query(\"USE `lfp_v1`\")\n", + "conn.query(\n", + " \"DROP TABLE `lfp_v1`.`_imported_l_f_p`\"\n", + ") # can't use datajoint to drop this because it doesn't exist in the code" + ] + }, + { + "cell_type": "markdown", + "id": "bd8fc6c0-6364-427d-8026-4bc11f676eb2", + "metadata": {}, + "source": [ + "# Task 1. Rename the tables while maintaining foreign key references from other tables to these tables\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "202ab4d7-0e81-4655-903e-07bb5582d349", + "metadata": {}, + "outputs": [], + "source": [ + "dj.schema(\"lfp_electrode\") # create a new database" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4e68349f-db92-483e-82b0-161b2cccac98", + "metadata": {}, + "outputs": [], + "source": [ + "conn = dj.conn()\n", + "conn.query(\"USE `lfp_v1`\")\n", + "conn.query(\n", + " \"ALTER TABLE `lfp_v1`.`l_f_p_electrode_group` RENAME `lfp_electrode`.`l_f_p_electrode_group`\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "26d054c6-189f-479f-873f-2a76c0397365", + "metadata": {}, + "outputs": [], + "source": [ + "conn = dj.conn()\n", + "conn.query(\"USE `lfp_v1`\")\n", + "conn.query(\n", + " \"ALTER TABLE `lfp_v1`.`l_f_p_electrode_group__l_f_p_electrode` RENAME `lfp_electrode`.`l_f_p_electrode_group__l_f_p_electrode`\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "c9d12ce2-0ea6-4475-82a1-fb924d333047", + "metadata": {}, + "source": [ + "# Verify the changes\n", + "\n", + "Dump individual databases to a file and search for lingering references to `lfp_v1.l_f_p_electrode_group` or `lfp_v1.l_f_p_electrode_group__l_f_p_electrode`. Make sure they have been updated.\n", + "\n", + "```\n", + "docker exec -i dj mysqldump -u root --password=tutorial -h 127.0.0.1 --databases lfp_v1 > dump_lfp_v1.sql\n", + "docker exec -i dj mysqldump -u root --password=tutorial -h 127.0.0.1 --databases lfp_band_v1 > dump_lfp_band_v1.sql\n", + "```\n", + "\n", + "You might also just be able to run:\n", + "\n", + "```\n", + "SELECT * FROM information_schema.KEY_COLUMN_USAGE WHERE REFERENCED_TABLE_NAME = 'l_f_p_electrode_group'\n", + "SELECT * FROM information_schema.KEY_COLUMN_USAGE WHERE REFERENCED_TABLE_NAME = 'l_f_p_electrode_group__l_f_p_electrode'\n", + "```\n", + "\n", + "If time permits, run through the steps of this notebook again to make sure it is smooth and foolproof before running this on the production database.\n" + ] + }, + { + "cell_type": "markdown", + "id": "9f1cfdd0-202e-4a15-b6f9-0af768bb5a61", + "metadata": {}, + "source": [ + "# Then switch git branches to the PR with the new changes\n" + ] + }, + { + "cell_type": "markdown", + "id": "8288acea-e97c-4a34-bb83-c89c49102b37", + "metadata": {}, + "source": [ + "# Restart the Jupyter kernel. Confirm things work. Connect to the local database again.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "14e33ff2-fd02-4a8f-8275-988a17a0aadf", + "metadata": {}, + "outputs": [], + "source": [ + "import datajoint as dj\n", + "import os\n", + "from pathlib import Path\n", + "\n", + "# set dirs\n", + "base_dir = Path(\n", + " \"/Users/rly/Documents/NWB/spyglass-workspace\"\n", + ") # change this to your desired directory\n", + "raw_dir = base_dir / \"raw\"\n", + "analysis_dir = base_dir / \"analysis\"\n", + "recording_dir = base_dir / \"recording\"\n", + "sorting_dir = base_dir / \"sorting\"\n", + "waveforms_dir = base_dir / \"waveforms\"\n", + "tmp_dir = base_dir / \"tmp\"\n", + "kachery_cloud_dir = base_dir / \".kachery_cloud\"\n", + "\n", + "os.makedirs(raw_dir, exist_ok=True)\n", + "os.makedirs(analysis_dir, exist_ok=True)\n", + "os.makedirs(recording_dir, exist_ok=True)\n", + "os.makedirs(sorting_dir, exist_ok=True)\n", + "os.makedirs(waveforms_dir, exist_ok=True)\n", + "os.makedirs(tmp_dir, exist_ok=True)\n", + "os.makedirs(kachery_cloud_dir, exist_ok=True)\n", + "\n", + "# set dj config\n", + "dj.config[\"database.host\"] = \"localhost\"\n", + "dj.config[\"database.user\"] = \"root\"\n", + "dj.config[\"database.password\"] = \"tutorial\"\n", + "dj.config[\"database.port\"] = 3306\n", + "dj.config[\"stores\"] = {\n", + " \"raw\": {\n", + " \"protocol\": \"file\",\n", + " \"location\": str(raw_dir),\n", + " \"stage\": str(raw_dir),\n", + " },\n", + " \"analysis\": {\n", + " \"protocol\": \"file\",\n", + " \"location\": str(analysis_dir),\n", + " \"stage\": str(analysis_dir),\n", + " },\n", + "}\n", + "dj.config[\"enable_python_native_blobs\"] = True\n", + "\n", + "# set env vars\n", + "os.environ[\"SPYGLASS_BASE_DIR\"] = str(base_dir)\n", + "os.environ[\"SPYGLASS_RECORDING_DIR\"] = str(recording_dir)\n", + "os.environ[\"SPYGLASS_SORTING_DIR\"] = str(sorting_dir)\n", + "os.environ[\"SPYGLASS_WAVEFORMS_DIR\"] = str(waveforms_dir)\n", + "os.environ[\"SPYGLASS_TEMP_DIR\"] = str(tmp_dir)\n", + "os.environ[\"KACHERY_CLOUD_DIR\"] = str(kachery_cloud_dir)\n", + "os.environ[\"DJ_SUPPORT_FILEPATH_MANAGEMENT\"] = \"TRUE\"" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "72254c87-1833-44b7-8ab7-47edffb467f1", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[2023-07-23 23:56:50,225][INFO]: Connecting root@localhost:3306\n", + "[2023-07-23 23:56:50,363][INFO]: Connected root@localhost:3306\n" + ] + } + ], + "source": [ + "import spyglass as sg\n", + "\n", + "sg.config[\"prepopulate\"] = False\n", + "\n", + "import spyglass.common as sgc\n", + "import spyglass.data_import as sgdi\n", + "import spyglass.lfp as lfp\n", + "import spyglass.lfp.v1 as lfp_v1\n", + "import spyglass.lfp_band as lfp_band\n", + "import spyglass.lfp_band.lfp_band_merge as lfp_band_merge" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "428ef635-259d-4f7b-aa57-a48ff3af721f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
\n", + "

nwb_file_name

\n", + " name of the NWB file\n", + "
\n", + "

lfp_electrode_group_name

\n", + " the name of this group of electrodes\n", + "
arthur20220315_.nwball_tets_arthur
arthur20220316_.nwball_tets_arthur
arthur20220317_.nwball_tets_arthur
arthur20220318_.nwball_tets_arthur
arthur20220319_.nwball_tets_arthur
arthur20220320_.nwball_tets_arthur
arthur20220321_.nwball_tets_arthur
arthur20220322_.nwball_tets_arthur
arthur20220323_.nwball_tets_arthur
arthur20220324_.nwball_tets_arthur
arthur20220325_.nwball_tets_arthur
arthur20220326_.nwball_tets_arthur
\n", + "

...

\n", + "

Total: 333

\n", + " " + ], + "text/plain": [ + "*nwb_file_name *lfp_electrode\n", + "+------------+ +------------+\n", + "arthur20220315 all_tets_arthu\n", + "arthur20220316 all_tets_arthu\n", + "arthur20220317 all_tets_arthu\n", + "arthur20220318 all_tets_arthu\n", + "arthur20220319 all_tets_arthu\n", + "arthur20220320 all_tets_arthu\n", + "arthur20220321 all_tets_arthu\n", + "arthur20220322 all_tets_arthu\n", + "arthur20220323 all_tets_arthu\n", + "arthur20220324 all_tets_arthu\n", + "arthur20220325 all_tets_arthu\n", + "arthur20220326 all_tets_arthu\n", + " ...\n", + " (Total: 333)" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lfp.LFPElectrodeGroup()" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "78598711-6fa7-4c54-84f0-3c3ec3e36324", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
\n", + "

nwb_file_name

\n", + " name of the NWB file\n", + "
\n", + "

lfp_electrode_group_name

\n", + " the name of this group of electrodes\n", + "
\n", + "

target_interval_list_name

\n", + " descriptive name of this interval list\n", + "
\n", + "

filter_name

\n", + " descriptive name of this filter\n", + "
\n", + "

filter_sampling_rate

\n", + " sampling rate for this filter\n", + "
arthur20220315_.nwball_tets_arthurr1_r2LFP 0-400 Hz30000
arthur20220315_.nwball_tets_arthurr2_r3LFP 0-400 Hz30000
arthur20220316_.nwball_tets_arthurr1_r2LFP 0-400 Hz30000
arthur20220316_.nwball_tets_arthurr2_r3LFP 0-400 Hz30000
arthur20220317_.nwball_tets_arthurr1_r2LFP 0-400 Hz30000
arthur20220317_.nwball_tets_arthurr2_r3LFP 0-400 Hz30000
arthur20220318_.nwball_tets_arthurr1_r2LFP 0-400 Hz30000
arthur20220318_.nwball_tets_arthurr2_r3LFP 0-400 Hz30000
arthur20220319_.nwball_tets_arthurr2_r2LFP 0-400 Hz30000
arthur20220319_.nwball_tets_arthurr2_r3LFP 0-400 Hz30000
arthur20220320_.nwball_tets_arthurr1_r2LFP 0-400 Hz30000
arthur20220320_.nwball_tets_arthurr2_r3LFP 0-400 Hz30000
\n", + "

...

\n", + "

Total: 1102

\n", + " " + ], + "text/plain": [ + "*nwb_file_name *lfp_electrode *target_interv *filter_name *filter_sampli\n", + "+------------+ +------------+ +------------+ +------------+ +------------+\n", + "arthur20220315 all_tets_arthu r1_r2 LFP 0-400 Hz 30000 \n", + "arthur20220315 all_tets_arthu r2_r3 LFP 0-400 Hz 30000 \n", + "arthur20220316 all_tets_arthu r1_r2 LFP 0-400 Hz 30000 \n", + "arthur20220316 all_tets_arthu r2_r3 LFP 0-400 Hz 30000 \n", + "arthur20220317 all_tets_arthu r1_r2 LFP 0-400 Hz 30000 \n", + "arthur20220317 all_tets_arthu r2_r3 LFP 0-400 Hz 30000 \n", + "arthur20220318 all_tets_arthu r1_r2 LFP 0-400 Hz 30000 \n", + "arthur20220318 all_tets_arthu r2_r3 LFP 0-400 Hz 30000 \n", + "arthur20220319 all_tets_arthu r2_r2 LFP 0-400 Hz 30000 \n", + "arthur20220319 all_tets_arthu r2_r3 LFP 0-400 Hz 30000 \n", + "arthur20220320 all_tets_arthu r1_r2 LFP 0-400 Hz 30000 \n", + "arthur20220320 all_tets_arthu r2_r3 LFP 0-400 Hz 30000 \n", + " ...\n", + " (Total: 1102)" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lfp_v1.LFPSelection()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "261bf6cf-ba4b-48f0-84f7-11a52626c40b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
\n", + "

nwb_file_name

\n", + " name of the NWB file\n", + "
\n", + "

lfp_electrode_group_name

\n", + " the name of this group of electrodes\n", + "
arthur20220315_.nwball_tets_arthur
arthur20220316_.nwball_tets_arthur
arthur20220317_.nwball_tets_arthur
arthur20220318_.nwball_tets_arthur
arthur20220319_.nwball_tets_arthur
arthur20220320_.nwball_tets_arthur
arthur20220321_.nwball_tets_arthur
arthur20220322_.nwball_tets_arthur
arthur20220323_.nwball_tets_arthur
arthur20220324_.nwball_tets_arthur
arthur20220325_.nwball_tets_arthur
arthur20220326_.nwball_tets_arthur
\n", + "

...

\n", + "

Total: 333

\n", + " " + ], + "text/plain": [ + "*nwb_file_name *lfp_electrode\n", + "+------------+ +------------+\n", + "arthur20220315 all_tets_arthu\n", + "arthur20220316 all_tets_arthu\n", + "arthur20220317 all_tets_arthu\n", + "arthur20220318 all_tets_arthu\n", + "arthur20220319 all_tets_arthu\n", + "arthur20220320 all_tets_arthu\n", + "arthur20220321 all_tets_arthu\n", + "arthur20220322 all_tets_arthu\n", + "arthur20220323 all_tets_arthu\n", + "arthur20220324 all_tets_arthu\n", + "arthur20220325 all_tets_arthu\n", + "arthur20220326 all_tets_arthu\n", + " ...\n", + " (Total: 333)" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from spyglass.lfp.lfp_electrode import LFPElectrodeGroup\n", + "\n", + "LFPElectrodeGroup()" + ] + }, + { + "cell_type": "markdown", + "id": "719ca00f-e106-4434-ac61-d17b3a9d4cae", + "metadata": {}, + "source": [ + "# Run this on the production database on the frank lab servers\n", + "\n", + "- Log in to the frank lab server\n", + "- Reinstall the master branch of spyglass\n", + "\n", + "```\n", + "ssh rly@typhoon.cin.ucsf.edu -p XXXX\n", + "cd spyglass\n", + "# remove the existing spyglass repo if it exists\n", + "mamba remove --name spyglass --all --yes\n", + "git status\n", + "# make sure i am on the master branch\n", + "git pull\n", + "mamba env create -f environment.yml --verbose # this can take like 30 minutes\n", + "mamba activate spyglass\n", + "pip install -e .\n", + "```\n", + "\n", + "- Copy this notebook there\n", + "- Start jupyter\n", + "- Run through all the above steps EXCEPT do not configure datajoint to connect to a local database. Datajoint is already configured to connect to the Frank Lab spyglass production database (at least on Ryan's account)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e19074ce-2502-43bd-b29e-aef38d4a8564", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c97a6dc6-ad40-4899-9983-e09bd59f1b79", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "46741e20-f97b-41a5-95a4-fe0e78ed6709", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2074c54e-4640-4ad0-ba3c-84947f3bad20", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "8763a53e-3b27-41b7-8a4e-462bf7217e1c", + "metadata": {}, + "source": [ + "# A scrapped idea - changing a primary key of a table that is used by lots of downstream tables\n", + "\n", + "2. Copy all entries from common_ephys.LFPSelection to new lfp_electrode.LFPElectrodeGroup and set the \"lfp_electrode_group_name\" values to \"full_session_full_channel_set\"\n", + "3. Add a column in common_ephys.LFP that is a foreign key to new lfp_electrode.LFPElectrodeGroup with the values equal to the new entries in lfp_electrode.LFPElectrodeGroup\n", + "4. Change the primary key of common_ephys.LFP to new lfp_electrode.LFPElectrodeGroup (this might involve adding a new primary key and then removing the old one).\n", + "\n", + "- If changing the primary key requires manually adding the new \"lfp_electrode_group_name\" to every table downstream of common_ephys.LFP, then abort mission.\n", + "- To add a new primary key, we would need to drop the foreign key to the primary key of common_ephys.LFP (recursively) on every downstream table, some of which may be primary keys themselves. This would require dropping basically reference to common_ephys.LFP and every reference to a table that references that, etc.\n", + "\n", + "### ChatGPT says:\n", + "\n", + "If you encounter the \"Foreign key constraint is incorrectly formed\" error when trying to drop the primary key, it might be because there are foreign key constraints referencing the primary key you're attempting to drop.\n", + "\n", + "To add a new column to an existing primary key without encountering this issue, you can follow these steps:\n", + "\n", + "1. **Drop Foreign Key Constraints**:\n", + " You need to drop any foreign key constraints that reference the existing primary key before modifying it. Identify the foreign key constraints that are using the primary key you want to modify, and drop them using the `ALTER TABLE` statement. For example:\n", + "\n", + " ```sql\n", + " -- Drop foreign key constraints that reference the primary key\n", + " ALTER TABLE referencing_table1 DROP FOREIGN KEY constraint_name1;\n", + " ALTER TABLE referencing_table2 DROP FOREIGN KEY constraint_name2;\n", + " -- ... (repeat for each referencing table)\n", + " ```\n", + "\n", + " Replace `referencing_table1`, `referencing_table2`, etc., with the names of the tables that have foreign key constraints, and `constraint_name1`, `constraint_name2`, etc., with the actual names of the foreign key constraints.\n", + "\n", + "2. **Drop Primary Key Constraint**:\n", + " Once all foreign key constraints have been dropped, you can drop the existing primary key constraint:\n", + "\n", + " ```sql\n", + " ALTER TABLE users DROP PRIMARY KEY;\n", + " ```\n", + "\n", + " Replace `users` with the name of your table.\n", + "\n", + "3. **Add the New Column and Primary Key**:\n", + " Now that the primary key constraint is removed, you can add the new column and designate it as the primary key:\n", + "\n", + " ```sql\n", + " ALTER TABLE users\n", + " ADD COLUMN new_id INT AUTO_INCREMENT PRIMARY KEY;\n", + " ```\n", + "\n", + " Replace `users` with the name of your table and `new_id` with the name of the new column.\n", + "\n", + "4. **Recreate Foreign Key Constraints**:\n", + " After successfully adding the new primary key column, you can re-create the foreign key constraints that were previously dropped:\n", + "\n", + " ```sql\n", + " ALTER TABLE referencing_table1\n", + " ADD CONSTRAINT constraint_name1 FOREIGN KEY (foreign_key_column1) REFERENCES users(new_id);\n", + "\n", + " ALTER TABLE referencing_table2\n", + " ADD CONSTRAINT constraint_name2 FOREIGN KEY (foreign_key_column2) REFERENCES users(new_id);\n", + "\n", + " -- ... (repeat for each referencing table)\n", + " ```\n", + "\n", + " Replace `referencing_table1`, `referencing_table2`, etc., with the names of the tables that have foreign key constraints, `constraint_name1`, `constraint_name2`, etc., with the desired names of the foreign key constraints, and `foreign_key_column1`, `foreign_key_column2`, etc., with the columns in the referencing tables that reference the new primary key column.\n", + "\n", + "Please be cautious when modifying primary keys and foreign key constraints, as they are critical to maintaining data integrity. Always have proper backups and thoroughly test any changes in a safe environment before applying them to production data.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4c9ba764-69a9-40ec-8794-6039cb836f83", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "14e670e7-d50b-46b2-b9a4-06c97332dc63", + "metadata": {}, + "source": [ + "# Old cells from previous database surgery\n" + ] + }, + { + "cell_type": "markdown", + "id": "2a3ed9e2-dda3-4c6f-8ae8-e4adf1f5f69f", + "metadata": {}, + "source": [ + "# Alter DataAcquisitionDevice and create DataAcquisitionDeviceSystem and DataAcquisitionDeviceAmplifier tables\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "557e792a-476d-44bd-8a19-f98fb73473ac", + "metadata": {}, + "outputs": [], + "source": [ + "# inspect values\n", + "sgc.DataAcquisitionDevice()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0c5941ed-0a06-4581-94a7-bafe31cf16e6", + "metadata": {}, + "outputs": [], + "source": [ + "# store the values in memory\n", + "res = sgc.DataAcquisitionDevice.fetch()\n", + "res" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6829902b-b6ff-44aa-be65-be094cab153b", + "metadata": {}, + "outputs": [], + "source": [ + "# rename the fields\n", + "res.dtype.names = [\n", + " \"data_acquisition_device_name\",\n", + " \"data_acquisition_device_system\",\n", + " \"data_acquisition_device_amplifier\",\n", + " \"adc_circuit\",\n", + "]\n", + "res" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "60b0d8cf-6cb4-4c71-ada4-533d5d44f4f1", + "metadata": {}, + "outputs": [], + "source": [ + "# drop DataAcquisitionDevice\n", + "# this will also drop sgc.SessionDataAcquisitionDevice() but this should not exist anyway (it may have been created during testing)\n", + "sgc.DataAcquisitionDevice().drop()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "63a383f7-69c6-4519-94f2-f40c3175d1a8", + "metadata": {}, + "outputs": [], + "source": [ + "# these new tables may already exist and have dummy data from testing\n", + "# temporarily make a class for them and then drop the tables\n", + "schema = dj.schema(\"common_device\")\n", + "\n", + "\n", + "@schema\n", + "class DataAcquisitionDeviceSystem(dj.Manual):\n", + " pass\n", + "\n", + "\n", + "@schema\n", + "class DataAcquisitionDeviceAmplifier(dj.Manual):\n", + " pass\n", + "\n", + "\n", + "DataAcquisitionDeviceSystem.drop()\n", + "DataAcquisitionDeviceAmplifier.drop()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dc1d0241-641c-4c0c-b9e9-f0937e539314", + "metadata": {}, + "outputs": [], + "source": [ + "# load new class definitions\n", + "schema = dj.schema(\"common_device\")\n", + "\n", + "\n", + "@schema\n", + "class DataAcquisitionDeviceSystem(dj.Manual):\n", + " definition = \"\"\"\n", + " # Known data acquisition device system names.\n", + " data_acquisition_device_system: varchar(80)\n", + " ---\n", + " \"\"\"\n", + "\n", + "\n", + "@schema\n", + "class DataAcquisitionDeviceAmplifier(dj.Manual):\n", + " definition = \"\"\"\n", + " # Known data acquisition device amplifier names.\n", + " data_acquisition_device_amplifier: varchar(80)\n", + " ---\n", + " \"\"\"\n", + "\n", + "\n", + "@schema\n", + "class DataAcquisitionDevice(dj.Manual):\n", + " definition = \"\"\"\n", + " data_acquisition_device_name: varchar(80)\n", + " ---\n", + " -> DataAcquisitionDeviceSystem\n", + " -> DataAcquisitionDeviceAmplifier\n", + " adc_circuit = NULL: varchar(2000)\n", + " \"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ecfd069d-112d-42ea-9cff-d4c9175c670d", + "metadata": {}, + "outputs": [], + "source": [ + "# populate DataAcquisitionDeviceSystem\n", + "for name in res[\"data_acquisition_device_system\"]:\n", + " DataAcquisitionDeviceSystem.insert1(\n", + " {\"data_acquisition_device_system\": name}, skip_duplicates=True\n", + " )\n", + "DataAcquisitionDeviceSystem()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a165c177-57f0-48c0-9e53-dcf04fcade0f", + "metadata": {}, + "outputs": [], + "source": [ + "# populate DataAcquisitionDeviceAmplifier\n", + "for name in res[\"data_acquisition_device_amplifier\"]:\n", + " DataAcquisitionDeviceAmplifier.insert1(\n", + " {\"data_acquisition_device_amplifier\": name}, skip_duplicates=True\n", + " )\n", + "DataAcquisitionDeviceAmplifier()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d7a9aa1f-cc74-417c-bf88-189d1b2290c7", + "metadata": {}, + "outputs": [], + "source": [ + "# populate DataAcquisitionDevice\n", + "DataAcquisitionDevice.insert(res)\n", + "DataAcquisitionDevice()" + ] + }, + { + "cell_type": "markdown", + "id": "9310d24d-6f11-4dcb-a399-767d026dc59b", + "metadata": {}, + "source": [ + "# Create new ProbeType table\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a480d357-ef2f-4684-bd21-1dfe2a036995", + "metadata": {}, + "outputs": [], + "source": [ + "# these new tables may already exist and have dummy data from testing\n", + "# temporarily make a class for them and then drop the tables\n", + "schema = dj.schema(\"common_device\")\n", + "\n", + "\n", + "@schema\n", + "class ProbeType(dj.Manual):\n", + " definition = \"\"\"\n", + " # Type/category of probe, e.g., Neuropixels 1.0 or NeuroNexus X-Y-Z, regardless of configuration.\n", + " # This is a controlled vocabulary of probe type names.\n", + " # This is separated from Probe because probes like the Neuropixels 1.0 can have different dynamic configurations,\n", + " # e.g. channel maps.\n", + " probe_type: varchar(80)\n", + " ---\n", + " probe_description: varchar(2000) # description of this probe\n", + " manufacturer = \"\": varchar(200) # manufacturer of this probe\n", + " num_shanks: int # number of shanks on this probe\n", + " \"\"\"\n", + "\n", + "\n", + "ProbeType.drop()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0bbe3d7a-c29f-4fd7-92da-74c4789b996b", + "metadata": {}, + "outputs": [], + "source": [ + "# load new class definition\n", + "schema = dj.schema(\"common_device\")\n", + "\n", + "\n", + "@schema\n", + "class ProbeType(dj.Manual):\n", + " definition = \"\"\"\n", + " # Type/category of probe, e.g., Neuropixels 1.0 or NeuroNexus X-Y-Z, regardless of configuration.\n", + " # This is a controlled vocabulary of probe type names.\n", + " # This is separated from Probe because probes like the Neuropixels 1.0 can have different dynamic configurations,\n", + " # e.g. channel maps.\n", + " probe_type: varchar(80)\n", + " ---\n", + " probe_description: varchar(2000) # description of this probe\n", + " manufacturer = \"\": varchar(200) # manufacturer of this probe\n", + " num_shanks: int # number of shanks on this probe\n", + " \"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e0089ad9-3438-4292-b15a-e0411b99cfa9", + "metadata": {}, + "outputs": [], + "source": [ + "# populate ProbeType from Probe\n", + "res = sgc.Probe.fetch()\n", + "for row in res:\n", + " ProbeType.insert1(\n", + " {\n", + " \"probe_type\": row[\"probe_type\"],\n", + " \"probe_description\": row[\"probe_description\"],\n", + " \"num_shanks\": row[\"num_shanks\"],\n", + " }\n", + " )\n", + "ProbeType()" + ] + }, + { + "cell_type": "markdown", + "id": "28f93788-27d6-408e-a26b-e8ec445cac03", + "metadata": {}, + "source": [ + "# Alter primary key of Probe table\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "caecd02c-442e-4677-b986-c011e3225138", + "metadata": {}, + "outputs": [], + "source": [ + "# confirm that only a few tables are affected by these changes\n", + "# only Probe.Shank and ElectrodeGroup should use Probe\n", + "dj.ERD(sgc.Probe) + 1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9a453fec-9556-4bec-ac70-d1cc6406fb08", + "metadata": {}, + "outputs": [], + "source": [ + "# only Probe.Electrode should use Probe.Shank\n", + "dj.ERD(sgc.Probe.Shank) + 1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "048fe4ab-a842-4b69-af31-e3b3c717b1ce", + "metadata": {}, + "outputs": [], + "source": [ + "# only Electrode should use Probe.Electrode\n", + "dj.ERD(sgc.Probe.Electrode) + 1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "93c1bc8b-a8d9-40b4-bd1e-5b580596e5eb", + "metadata": {}, + "outputs": [], + "source": [ + "conn = dj.conn()\n", + "conn.query(\"USE `common_device`\")\n", + "conn.query(\n", + " \"ALTER TABLE `probe` CHANGE `probe_type` `probe_id` varchar(80) NOT NULL\"\n", + ")\n", + "conn.query(\n", + " \"ALTER TABLE `probe__shank` CHANGE `probe_type` `probe_id` varchar(80) NOT NULL\"\n", + ")\n", + "conn.query(\n", + " \"ALTER TABLE `probe__electrode` CHANGE `probe_type` `probe_id` varchar(80) NOT NULL\"\n", + ")\n", + "conn.query(\"USE `common_ephys`\")\n", + "conn.query(\n", + " \"ALTER TABLE `_electrode_group` CHANGE `probe_type` `probe_id` varchar(80) DEFAULT NULL\"\n", + ")\n", + "conn.query(\n", + " \"ALTER TABLE `_electrode_group` DROP KEY `probe_type`, ADD KEY `probe_id` (`probe_id`)\"\n", + ")\n", + "conn.query(\n", + " \"ALTER TABLE `_electrode` CHANGE `probe_type` `probe_id` varchar(80) DEFAULT NULL\"\n", + ")\n", + "conn.query(\n", + " \"ALTER TABLE `_electrode` DROP KEY `probe_type`, ADD KEY `probe_id` (`probe_id`,`probe_shank`,`probe_electrode`)\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8a4c54c1-3333-4ce4-a85b-8a370d5478cd", + "metadata": {}, + "outputs": [], + "source": [ + "stop\n", + "# then update spyglass code to reflect the name change (`git checkout file_based_mods`)\n", + "# restart kernel\n", + "# dump databases common_device and common_ephys to file to make sure the name change cascaded correctly\n", + "# `docker exec -i dj mysqldump -u root --password=tutorial -h 127.0.0.1 --databases common_device common_ephys > dump.sql`\n", + "# run first cell\n", + "# print tables in spyglass to make sure the name change worked" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "01d68e4d-fef5-42d6-9103-d341e59057c4", + "metadata": {}, + "outputs": [], + "source": [ + "# verify the change\n", + "sgc.Probe()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "82b00b2b-48a7-47cc-80e0-3d02d862a64a", + "metadata": {}, + "outputs": [], + "source": [ + "sgc.Probe.Shank()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b3cf2fcb-bf93-41e6-b833-499e2f32d12d", + "metadata": {}, + "outputs": [], + "source": [ + "sgc.Probe.Electrode()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a8ee9b62-cf4c-4c85-9473-8fc186d90ed5", + "metadata": {}, + "outputs": [], + "source": [ + "sgc.ElectrodeGroup()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "165cb9b4-d9fc-478a-ab45-b45c4eace08d", + "metadata": {}, + "outputs": [], + "source": [ + "sgc.Electrode()" + ] + }, + { + "cell_type": "markdown", + "id": "27cbf2c9-9fa4-499f-bb30-2e0c08652945", + "metadata": {}, + "source": [ + "# Alter columns of Probe table\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b84b1735-6077-44b2-8f6a-4981a18ca626", + "metadata": {}, + "outputs": [], + "source": [ + "# load new class definition\n", + "schema = dj.schema(\"common_device\")\n", + "from spyglass.common import DataAcquisitionDevice\n", + "\n", + "\n", + "@schema\n", + "class Probe(dj.Manual):\n", + " definition = \"\"\"\n", + " # A configuration of a ProbeType. For most probe types, there is only one configuration, and that configuration\n", + " # should always be used. For Neuropixels probes, the specific channel map (which electrodes are used,\n", + " # where are they, and in what order) can differ between users and sessions, and each configuration should have a\n", + " # different ProbeType.\n", + " probe_id: varchar(80) # a unique ID for this probe and dynamic configuration\n", + " ---\n", + " -> ProbeType # the type of probe, selected from a controlled list of probe types\n", + " -> [nullable] DataAcquisitionDevice # the data acquisition device used with this Probe\n", + " contact_side_numbering: enum(\"True\", \"False\") # if True, then electrode contacts are facing you when numbering them\n", + " \"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6fdc8f9f-5b32-4f9d-bdbd-d3c4bd0b59a5", + "metadata": {}, + "outputs": [], + "source": [ + "conn = dj.conn()\n", + "conn.query(\"USE `common_device`\")\n", + "conn.query(\n", + " \"ALTER TABLE `probe` \"\n", + " \"DROP `probe_description`, \"\n", + " \"DROP `num_shanks`, \"\n", + " \"ADD `probe_type` varchar(80) NOT NULL DEFAULT '' COMMENT '' AFTER `probe_id`, \"\n", + " \"ADD `data_acquisition_device_name` varchar(80) COMMENT '' AFTER `probe_type`\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "232df23f-83c6-4f69-9eb6-1ce7b7126ecb", + "metadata": {}, + "outputs": [], + "source": [ + "conn = dj.conn()\n", + "conn.query(\"USE `common_device`\")\n", + "conn.query(\n", + " \"UPDATE `probe` SET `probe_type` = `probe_id` where `probe_type` = ''\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bc1f42dc-a5a7-4422-8552-e7e7c4a9905d", + "metadata": {}, + "outputs": [], + "source": [ + "conn = dj.conn()\n", + "conn.query(\"USE `common_device`\")\n", + "conn.query(\n", + " \"ALTER TABLE `probe` \"\n", + " \"ADD FOREIGN KEY (`probe_type`) REFERENCES `common_device`.`probe_type` (`probe_type`) ON UPDATE CASCADE ON DELETE RESTRICT, \"\n", + " \"ADD FOREIGN KEY (`data_acquisition_device_name`) REFERENCES `common_device`.`data_acquisition_device` (`data_acquisition_device_name`) ON UPDATE CASCADE ON DELETE RESTRICT\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "90110b79-97b3-4f66-a0c6-5c31b3cfcdbb", + "metadata": {}, + "outputs": [], + "source": [ + "stop\n", + "# restart kernel\n", + "# dump databases common_device and common_ephys to file to make sure the name change cascaded correctly\n", + "# `docker exec -i dj mysqldump -u root --password=tutorial -h 127.0.0.1 --databases common_device > dump.sql`\n", + "# run cell 1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5941880a-b34b-460e-a603-8395727eabae", + "metadata": {}, + "outputs": [], + "source": [ + "# verify this is correct\n", + "sgc.Probe()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0069c9f6-d7fb-4c83-bb76-2bc884469bef", + "metadata": {}, + "outputs": [], + "source": [ + "# verify the join works\n", + "sgc.Probe() * sgc.ProbeType()" + ] + }, + { + "cell_type": "markdown", + "id": "a8cbc1eb-7eb0-4d97-bcca-c6a2c9c3d4a5", + "metadata": {}, + "source": [ + "# Move ExperimenterList data to Session.Experimenter\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e393aed7-ee6c-4320-9052-3c5703333545", + "metadata": {}, + "outputs": [], + "source": [ + "# access the old ExperimenterList table\n", + "schema = dj.schema(\"common_session\")\n", + "\n", + "\n", + "@schema\n", + "class ExperimenterList(dj.Imported):\n", + " definition = \"\"\"\n", + " -> Session\n", + " \"\"\"\n", + "\n", + " class Experimenter(dj.Part):\n", + " definition = \"\"\"\n", + " -> ExperimenterList\n", + " -> LabMember\n", + " \"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f6d1b2db-4c65-4e95-8665-e8f2ffd29816", + "metadata": {}, + "outputs": [], + "source": [ + "res = ExperimenterList.Experimenter()\n", + "res" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3a72571b-7936-4d82-a0c7-4654f47c9171", + "metadata": {}, + "outputs": [], + "source": [ + "sgc.Session.Experimenter.insert(res)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c7fd8fda-c42a-4f25-8b45-7829918d03c1", + "metadata": {}, + "outputs": [], + "source": [ + "sgc.Session.Experimenter()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ba75818b-ee71-4f85-a183-28f894f2644f", + "metadata": {}, + "outputs": [], + "source": [ + "ExperimenterList.drop()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "629eef8f-d46d-4890-993a-12b7f784e100", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.16" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From 0f49eedb46af865c557c9697bfaacfba83280f8d Mon Sep 17 00:00:00 2001 From: dpeg22 Date: Mon, 24 Jul 2023 11:00:20 -0700 Subject: [PATCH 082/131] move ripple into v1 and modify inits --- src/spyglass/lfp/v1/__init__.py | 4 +++- src/spyglass/ripple/__init__.py | 6 +++++- src/spyglass/ripple/v1/__init__.py | 5 +++++ src/spyglass/ripple/{ => v1}/ripple.py | 30 ++++++++------------------ 4 files changed, 22 insertions(+), 23 deletions(-) create mode 100644 src/spyglass/ripple/v1/__init__.py rename src/spyglass/ripple/{ => v1}/ripple.py (93%) diff --git a/src/spyglass/lfp/v1/__init__.py b/src/spyglass/lfp/v1/__init__.py index 95e1a43ce..34804a3e1 100644 --- a/src/spyglass/lfp/v1/__init__.py +++ b/src/spyglass/lfp/v1/__init__.py @@ -10,4 +10,6 @@ LFPArtifactDetectionSelection, LFPArtifactRemovedIntervalList, ) -from spyglass.lfp.v1.lfp_band import LFPBandV1, LFPBandSelection + +# Commented out to prevent circular import +# from spyglass.lfp.v1.lfp_band import LFPBandV1, LFPBandSelection diff --git a/src/spyglass/ripple/__init__.py b/src/spyglass/ripple/__init__.py index ca2b6ef52..e284af017 100644 --- a/src/spyglass/ripple/__init__.py +++ b/src/spyglass/ripple/__init__.py @@ -1 +1,5 @@ -from spyglass.ripple import RippleParameters, RippleLFPSelection, RippleTimesV1 +from spyglass.ripple.v1 import ( + RippleParameters, + RippleLFPSelection, + RippleTimesV1, +) diff --git a/src/spyglass/ripple/v1/__init__.py b/src/spyglass/ripple/v1/__init__.py new file mode 100644 index 000000000..e284af017 --- /dev/null +++ b/src/spyglass/ripple/v1/__init__.py @@ -0,0 +1,5 @@ +from spyglass.ripple.v1 import ( + RippleParameters, + RippleLFPSelection, + RippleTimesV1, +) diff --git a/src/spyglass/ripple/ripple.py b/src/spyglass/ripple/v1/ripple.py similarity index 93% rename from src/spyglass/ripple/ripple.py rename to src/spyglass/ripple/v1/ripple.py index 1dac4dc5c..683124609 100644 --- a/src/spyglass/ripple/ripple.py +++ b/src/spyglass/ripple/v1/ripple.py @@ -45,7 +45,7 @@ class RippleLFPSelection(dj.Manual): # proj required to rename merge_id to avoid downstream conflict # with PositionOutput merge_id definition = """ - -> LFPBandOutput.proj(lfp_band_merge_id='merge_id') + -> LFPBandV1.proj(lfp_band_merge_id='merge_id') group_name = 'CA1' : varchar(80) --- electrode_ids : mediumblob @@ -84,12 +84,12 @@ def set_lfp_electrodes( group_name : str, optional description of the electrode group, by default "CA1" """ - lfp_key = LFPBandOutput.merge_get_parent( + lfp_key = LFPBandV1.merge_get_parent( {"merge_id": key["lfp_band_merge_id"]} ).fetch1("KEY") - source = ( - LFPBandOutput & {"merge_id": key["lfp_band_merge_id"]} - ).fetch1("source") + source = (LFPBandV1 & {"merge_id": key["lfp_band_merge_id"]}).fetch1( + "source" + ) if source not in UPSTREAM_ACCEPTED_VERSIONS: raise NotImplementedError( "Ripple V1 will currently only work with LFPBandV1" @@ -166,9 +166,9 @@ class RippleTimesV1(dj.Computed): def make(self, key): orig_key = copy.deepcopy(key) - nwb_file_name, interval_list_name = LFPBandOutput.merge_get_parent( - {"merge_id": key["lfp_band_merge_id"]} - ).fetch1("nwb_file_name", "target_interval_list_name") + nwb_file_name, interval_list_name = (LFPBandV1 & key).fetch1( + "nwb_file_name", "target_interval_list_name" + ) print(f"Computing ripple times for: {key}") ripple_params = ( @@ -206,16 +206,6 @@ def make(self, key): self.insert1(key) - # finally, we insert this into the RippleTimesOutput table. - from ..ripple_merge import RippleTimesOutput - - part_name = to_camel_case(self.table_name.split("__")[-1]) - - # TODO: The next line belongs in a merge table function - RippleTimesOutput._merge_insert( - [orig_key], part_name=part_name, skip_duplicates=True - ) - def fetch_nwb(self, *attrs, **kwargs): return fetch_nwb( self, (AnalysisNwbfile, "analysis_file_abs_path"), *attrs, **kwargs @@ -243,9 +233,7 @@ def get_ripple_lfps_and_position_info( ) # warn/validate that there is only one wire per electrode - ripple_lfp_nwb = LFPBandOutput.fetch_nwb( - {"merge_id": key["lfp_band_merge_id"]} - )[0] + ripple_lfp_nwb = (LFPBandV1 & key).fetch_nwb()[0] ripple_lfp_electrodes = ripple_lfp_nwb["lfp_band"].electrodes.data[:] elec_mask = np.full_like(ripple_lfp_electrodes, 0, dtype=bool) valid_elecs = [ From b0fbd2371a14c81994ee5a4e857cb8bb57d25f45 Mon Sep 17 00:00:00 2001 From: dpeg22 Date: Mon, 24 Jul 2023 13:25:36 -0700 Subject: [PATCH 083/131] modify ripple inits --- src/spyglass/ripple/__init__.py | 5 ----- src/spyglass/ripple/v1/__init__.py | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/spyglass/ripple/__init__.py b/src/spyglass/ripple/__init__.py index e284af017..e69de29bb 100644 --- a/src/spyglass/ripple/__init__.py +++ b/src/spyglass/ripple/__init__.py @@ -1,5 +0,0 @@ -from spyglass.ripple.v1 import ( - RippleParameters, - RippleLFPSelection, - RippleTimesV1, -) diff --git a/src/spyglass/ripple/v1/__init__.py b/src/spyglass/ripple/v1/__init__.py index e284af017..e6d0de6cc 100644 --- a/src/spyglass/ripple/v1/__init__.py +++ b/src/spyglass/ripple/v1/__init__.py @@ -1,4 +1,4 @@ -from spyglass.ripple.v1 import ( +from spyglass.ripple.v1.ripple import ( RippleParameters, RippleLFPSelection, RippleTimesV1, From 3bce73ba4ca512b7fd3a0e90394471e4ee4f54e3 Mon Sep 17 00:00:00 2001 From: dpeg22 Date: Tue, 25 Jul 2023 10:29:35 -0700 Subject: [PATCH 084/131] modify RippleLFPSelection definition --- src/spyglass/ripple/v1/ripple.py | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/src/spyglass/ripple/v1/ripple.py b/src/spyglass/ripple/v1/ripple.py index 683124609..0b844e24e 100644 --- a/src/spyglass/ripple/v1/ripple.py +++ b/src/spyglass/ripple/v1/ripple.py @@ -45,10 +45,8 @@ class RippleLFPSelection(dj.Manual): # proj required to rename merge_id to avoid downstream conflict # with PositionOutput merge_id definition = """ - -> LFPBandV1.proj(lfp_band_merge_id='merge_id') + -> LFPBandV1 group_name = 'CA1' : varchar(80) - --- - electrode_ids : mediumblob """ class RippleLFPElectrode(dj.Part): @@ -84,32 +82,25 @@ def set_lfp_electrodes( group_name : str, optional description of the electrode group, by default "CA1" """ - lfp_key = LFPBandV1.merge_get_parent( - {"merge_id": key["lfp_band_merge_id"]} - ).fetch1("KEY") - source = (LFPBandV1 & {"merge_id": key["lfp_band_merge_id"]}).fetch1( - "source" - ) - if source not in UPSTREAM_ACCEPTED_VERSIONS: - raise NotImplementedError( - "Ripple V1 will currently only work with LFPBandV1" - ) + # if source not in UPSTREAM_ACCEPTED_VERSIONS: + # raise NotImplementedError( + # "Ripple V1 will currently only work with LFPBandV1" + # ) if electrode_list is None: electrode_list = ( - (LFPBandSelection.LFPBandElectrode & lfp_key) + (LFPBandSelection.LFPBandElectrode & key) .fetch("electrode_id") .tolist() ) electrode_list.sort() electrode_keys = ( - pd.DataFrame(LFPBandSelection.LFPBandElectrode() & lfp_key) + pd.DataFrame(LFPBandSelection.LFPBandElectrode() & key) .set_index("electrode_id") .loc[electrode_list] .reset_index() .loc[:, LFPBandSelection.LFPBandElectrode.primary_key] ) electrode_keys["group_name"] = group_name - electrode_keys["lfp_band_merge_id"] = key["lfp_band_merge_id"] electrode_keys = electrode_keys.sort_values(by=["electrode_id"]) RippleLFPSelection.validate_key(key) RippleLFPSelection().insert1( @@ -258,11 +249,9 @@ def get_ripple_lfps_and_position_info( "interval_list_name": interval_list_name, } ).fetch1("valid_times") - position_info = ( PositionOutput() & {"merge_id": key["pos_merge_id"]} ).fetch1_dataframe() - position_info = pd.concat( [ position_info.loc[slice(valid_time[0], valid_time[1])] From 235ed7285bb811c2c99491346d654639969144f0 Mon Sep 17 00:00:00 2001 From: dpeg22 Date: Tue, 25 Jul 2023 16:53:04 -0700 Subject: [PATCH 085/131] add try/except to RippleLFPSelection --- notebooks/12_Ripple_Detection.ipynb | 2248 ++++++++++----------------- src/spyglass/ripple/v1/ripple.py | 32 +- 2 files changed, 844 insertions(+), 1436 deletions(-) diff --git a/notebooks/12_Ripple_Detection.ipynb b/notebooks/12_Ripple_Detection.ipynb index 6a16d6eec..9db2db94b 100644 --- a/notebooks/12_Ripple_Detection.ipynb +++ b/notebooks/12_Ripple_Detection.ipynb @@ -8,33 +8,25 @@ }, "source": [ "# Ripple Detection\n", - "Ripple detection depends on a set of LFPs, the parameters used for detection and the speed of the animal. You will need `RippleLFPSelection`, `RippleParameters`, and `IntervalPositionInfo` to be populated accordingly. Let's import these:" + "Ripple detection depends on a set of LFPs, the parameters used for detection and the speed of the animal. You will need `RippleLFPSelection`, `RippleParameters`, and `PositionOutput` to be populated accordingly. Let's import these:" ] }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 12, "id": "46518472-a30e-4462-a5a3-3e7514fae090", "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[2022-11-28 14:37:02,551][INFO]: Connecting edeno@lmf-db.cin.ucsf.edu:3306\n", - "[2022-11-28 14:37:02,627][INFO]: Connected edeno@lmf-db.cin.ucsf.edu:3306\n", - "/home/edeno/miniconda3/envs/spyglass/lib/python3.9/site-packages/position_tools/core.py:3: DeprecationWarning: Please use `gaussian_filter1d` from the `scipy.ndimage` namespace, the `scipy.ndimage.filters` namespace is deprecated.\n", - " from scipy.ndimage.filters import gaussian_filter1d\n" - ] - } - ], + "outputs": [], "source": [ - "from spyglass.common.common_ripple import (\n", - " RippleLFPSelection,\n", - " RippleParameters,\n", - " RippleTimes,\n", - ")\n", - "from spyglass.common import IntervalPositionInfo" + "import pandas as pd\n", + "import numpy as np\n", + "import datajoint as dj\n", + "import spyglass.common as sgc\n", + "from spyglass.lfp import LFPOutput\n", + "import spyglass.lfp.v1 as sglfp\n", + "from spyglass.lfp.v1.lfp_band import LFPBandV1, LFPBandSelection\n", + "from spyglass.position import PositionOutput\n", + "import spyglass.ripple.v1 as sgrip" ] }, { @@ -59,23 +51,28 @@ "data": { "text/plain": [ "\u001b[0;31mSignature:\u001b[0m\n", - "\u001b[0mRippleLFPSelection\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mset_lfp_electrodes\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0mnwb_file_name\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0melectrode_list\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0msgrip\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mRippleLFPSelection\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mset_lfp_electrodes\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0mkey\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0melectrode_list\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0mgroup_name\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'CA1'\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mDocstring:\u001b[0m\n", - "Removes all electrodes for the specified nwb file and then adds back the electrodes in the list\n", + "Removes all electrodes for the specified nwb file and then\n", + "adds back the electrodes in the list\n", "\n", "Parameters\n", "----------\n", - "nwb_file_name : str\n", - " The name of the nwb file for the desired session\n", + "key : dict\n", + " dictionary corresponding to the LFPBand entry to use for\n", + " ripple detection\n", "electrode_list : list\n", - " list of electrodes to be used for LFP\n", + " list of electrodes from LFPBandSelection.LFPBandElectrode\n", + " to be used as the ripple LFP during detection\n", "group_name : str, optional\n", - "\u001b[0;31mFile:\u001b[0m /cumulus/edeno/spyglass/src/spyglass/common/common_ripple.py\n", - "\u001b[0;31mType:\u001b[0m function\n" + " description of the electrode group, by default \"CA1\"\n", + "\u001b[0;31mFile:\u001b[0m ~/Src2/spyglass/src/spyglass/ripple/v1/ripple.py\n", + "\u001b[0;31mType:\u001b[0m function" ] }, "metadata": {}, @@ -83,7 +80,7 @@ } ], "source": [ - "?RippleLFPSelection.set_lfp_electrodes" + "?sgrip.RippleLFPSelection.set_lfp_electrodes" ] }, { @@ -109,7 +106,9 @@ "metadata": {}, "outputs": [], "source": [ - "nwb_file_name = \"chimi20200216_new_.nwb\"" + "nwb_file_name = \"tonks20211103_.nwb\"\n", + "interval_list_name = \"test interval\"\n", + "filter_name = \"Ripple 150-250 Hz\"" ] }, { @@ -150,38 +149,6 @@ " \n", " \n", " \n", - " probe_type\n", - " probe_shank\n", - " probe_electrode\n", - " name\n", - " original_reference_electrode\n", - " x\n", - " y\n", - " z\n", - " filtering\n", - " impedance\n", - " bad_channel\n", - " x_warped\n", - " y_warped\n", - " z_warped\n", - " contacts\n", - " region_name\n", - " subregion_name\n", - " subsubregion_name\n", - " \n", - " \n", - " nwb_file_name\n", - " electrode_group_name\n", - " electrode_id\n", - " region_id\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", " \n", " \n", " \n", @@ -189,560 +156,7 @@ " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " chimi20200216_new_.nwb\n", - " 0\n", - " 0\n", - " 6\n", - " tetrode_12.5\n", - " 0\n", - " 0\n", - " 0\n", - " 16\n", - " 0.0\n", - " 0.0\n", - " 0.0\n", - " None\n", - " 0.0\n", - " False\n", - " 0.0\n", - " 0.0\n", - " 0.0\n", - " \n", - " Hippocampus\n", - " \n", - " \n", - " \n", - " \n", - " 1\n", - " 6\n", - " tetrode_12.5\n", - " 0\n", - " 1\n", - " 1\n", - " 16\n", - " 0.0\n", - " 0.0\n", - " 0.0\n", - " None\n", - " 0.0\n", - " False\n", - " 0.0\n", - " 0.0\n", - " 0.0\n", - " \n", - " Hippocampus\n", - " \n", - " \n", - " \n", - " \n", - " 2\n", - " 6\n", - " tetrode_12.5\n", - " 0\n", - " 2\n", - " 2\n", - " 16\n", - " 0.0\n", - " 0.0\n", - " 0.0\n", - " None\n", - " 0.0\n", - " False\n", - " 0.0\n", - " 0.0\n", - " 0.0\n", - " \n", - " Hippocampus\n", - " \n", - " \n", - " \n", - " \n", - " 3\n", - " 6\n", - " tetrode_12.5\n", - " 0\n", - " 3\n", - " 3\n", - " 16\n", - " 0.0\n", - " 0.0\n", - " 0.0\n", - " None\n", - " 0.0\n", - " False\n", - " 0.0\n", - " 0.0\n", - " 0.0\n", - " \n", - " Hippocampus\n", - " \n", - " \n", - " \n", - " \n", - " 1\n", - " 4\n", - " 6\n", - " tetrode_12.5\n", - " 0\n", - " 0\n", - " 4\n", - " 16\n", - " 0.0\n", - " 0.0\n", - " 0.0\n", - " None\n", - " 0.0\n", - " False\n", - " 0.0\n", - " 0.0\n", - " 0.0\n", - " \n", - " Hippocampus\n", - " \n", - " \n", - " \n", - " \n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", - " \n", - " \n", - " 8\n", - " 35\n", - " 6\n", - " tetrode_12.5\n", - " 0\n", - " 3\n", - " 35\n", - " 16\n", - " 0.0\n", - " 0.0\n", - " 0.0\n", - " None\n", - " 0.0\n", - " False\n", - " 0.0\n", - " 0.0\n", - " 0.0\n", - " \n", - " Hippocampus\n", - " \n", - " \n", - " \n", - " \n", - " 9\n", - " 36\n", - " 6\n", - " tetrode_12.5\n", - " 0\n", - " 0\n", - " 36\n", - " 16\n", - " 0.0\n", - " 0.0\n", - " 0.0\n", - " None\n", - " 0.0\n", - " False\n", - " 0.0\n", - " 0.0\n", - " 0.0\n", - " \n", - " Hippocampus\n", - " \n", - " \n", - " \n", - " \n", - " 37\n", - " 6\n", - " tetrode_12.5\n", - " 0\n", - " 1\n", - " 37\n", - " 16\n", - " 0.0\n", - " 0.0\n", - " 0.0\n", - " None\n", - " 0.0\n", - " False\n", - " 0.0\n", - " 0.0\n", - " 0.0\n", - " \n", - " Hippocampus\n", - " \n", - " \n", - " \n", - " \n", - " 38\n", - " 6\n", - " tetrode_12.5\n", - " 0\n", - " 2\n", - " 38\n", - " 16\n", - " 0.0\n", - " 0.0\n", - " 0.0\n", - " None\n", - " 0.0\n", - " False\n", - " 0.0\n", - " 0.0\n", - " 0.0\n", - " \n", - " Hippocampus\n", - " \n", - " \n", - " \n", - " \n", - " 39\n", - " 6\n", - " tetrode_12.5\n", - " 0\n", - " 3\n", - " 39\n", - " 16\n", - " 0.0\n", - " 0.0\n", - " 0.0\n", - " None\n", - " 0.0\n", - " False\n", - " 0.0\n", - " 0.0\n", - " 0.0\n", - " \n", - " Hippocampus\n", - " \n", - " \n", - " \n", - " \n", - "\n", - "

224 rows × 18 columns

\n", - "" - ], - "text/plain": [ - " probe_type \\\n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 tetrode_12.5 \n", - " 1 6 tetrode_12.5 \n", - " 2 6 tetrode_12.5 \n", - " 3 6 tetrode_12.5 \n", - " 1 4 6 tetrode_12.5 \n", - "... ... \n", - " 8 35 6 tetrode_12.5 \n", - " 9 36 6 tetrode_12.5 \n", - " 37 6 tetrode_12.5 \n", - " 38 6 tetrode_12.5 \n", - " 39 6 tetrode_12.5 \n", - "\n", - " probe_shank \\\n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 0 \n", - " 1 6 0 \n", - " 2 6 0 \n", - " 3 6 0 \n", - " 1 4 6 0 \n", - "... ... \n", - " 8 35 6 0 \n", - " 9 36 6 0 \n", - " 37 6 0 \n", - " 38 6 0 \n", - " 39 6 0 \n", - "\n", - " probe_electrode \\\n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 0 \n", - " 1 6 1 \n", - " 2 6 2 \n", - " 3 6 3 \n", - " 1 4 6 0 \n", - "... ... \n", - " 8 35 6 3 \n", - " 9 36 6 0 \n", - " 37 6 1 \n", - " 38 6 2 \n", - " 39 6 3 \n", - "\n", - " name \\\n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 0 \n", - " 1 6 1 \n", - " 2 6 2 \n", - " 3 6 3 \n", - " 1 4 6 4 \n", - "... ... \n", - " 8 35 6 35 \n", - " 9 36 6 36 \n", - " 37 6 37 \n", - " 38 6 38 \n", - " 39 6 39 \n", - "\n", - " original_reference_electrode \\\n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 16 \n", - " 1 6 16 \n", - " 2 6 16 \n", - " 3 6 16 \n", - " 1 4 6 16 \n", - "... ... \n", - " 8 35 6 16 \n", - " 9 36 6 16 \n", - " 37 6 16 \n", - " 38 6 16 \n", - " 39 6 16 \n", - "\n", - " x y \\\n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 0.0 0.0 \n", - " 1 6 0.0 0.0 \n", - " 2 6 0.0 0.0 \n", - " 3 6 0.0 0.0 \n", - " 1 4 6 0.0 0.0 \n", - "... ... ... \n", - " 8 35 6 0.0 0.0 \n", - " 9 36 6 0.0 0.0 \n", - " 37 6 0.0 0.0 \n", - " 38 6 0.0 0.0 \n", - " 39 6 0.0 0.0 \n", - "\n", - " z \\\n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 0.0 \n", - " 1 6 0.0 \n", - " 2 6 0.0 \n", - " 3 6 0.0 \n", - " 1 4 6 0.0 \n", - "... ... \n", - " 8 35 6 0.0 \n", - " 9 36 6 0.0 \n", - " 37 6 0.0 \n", - " 38 6 0.0 \n", - " 39 6 0.0 \n", - "\n", - " filtering \\\n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 None \n", - " 1 6 None \n", - " 2 6 None \n", - " 3 6 None \n", - " 1 4 6 None \n", - "... ... \n", - " 8 35 6 None \n", - " 9 36 6 None \n", - " 37 6 None \n", - " 38 6 None \n", - " 39 6 None \n", - "\n", - " impedance \\\n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 0.0 \n", - " 1 6 0.0 \n", - " 2 6 0.0 \n", - " 3 6 0.0 \n", - " 1 4 6 0.0 \n", - "... ... \n", - " 8 35 6 0.0 \n", - " 9 36 6 0.0 \n", - " 37 6 0.0 \n", - " 38 6 0.0 \n", - " 39 6 0.0 \n", - "\n", - " bad_channel \\\n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 False \n", - " 1 6 False \n", - " 2 6 False \n", - " 3 6 False \n", - " 1 4 6 False \n", - "... ... \n", - " 8 35 6 False \n", - " 9 36 6 False \n", - " 37 6 False \n", - " 38 6 False \n", - " 39 6 False \n", - "\n", - " x_warped \\\n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 0.0 \n", - " 1 6 0.0 \n", - " 2 6 0.0 \n", - " 3 6 0.0 \n", - " 1 4 6 0.0 \n", - "... ... \n", - " 8 35 6 0.0 \n", - " 9 36 6 0.0 \n", - " 37 6 0.0 \n", - " 38 6 0.0 \n", - " 39 6 0.0 \n", - "\n", - " y_warped \\\n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 0.0 \n", - " 1 6 0.0 \n", - " 2 6 0.0 \n", - " 3 6 0.0 \n", - " 1 4 6 0.0 \n", - "... ... \n", - " 8 35 6 0.0 \n", - " 9 36 6 0.0 \n", - " 37 6 0.0 \n", - " 38 6 0.0 \n", - " 39 6 0.0 \n", - "\n", - " z_warped \\\n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 0.0 \n", - " 1 6 0.0 \n", - " 2 6 0.0 \n", - " 3 6 0.0 \n", - " 1 4 6 0.0 \n", - "... ... \n", - " 8 35 6 0.0 \n", - " 9 36 6 0.0 \n", - " 37 6 0.0 \n", - " 38 6 0.0 \n", - " 39 6 0.0 \n", - "\n", - " contacts \\\n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 \n", - " 1 6 \n", - " 2 6 \n", - " 3 6 \n", - " 1 4 6 \n", - "... ... \n", - " 8 35 6 \n", - " 9 36 6 \n", - " 37 6 \n", - " 38 6 \n", - " 39 6 \n", - "\n", - " region_name \\\n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 Hippocampus \n", - " 1 6 Hippocampus \n", - " 2 6 Hippocampus \n", - " 3 6 Hippocampus \n", - " 1 4 6 Hippocampus \n", - "... ... \n", - " 8 35 6 Hippocampus \n", - " 9 36 6 Hippocampus \n", - " 37 6 Hippocampus \n", - " 38 6 Hippocampus \n", - " 39 6 Hippocampus \n", - "\n", - " subregion_name \\\n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 \n", - " 1 6 \n", - " 2 6 \n", - " 3 6 \n", - " 1 4 6 \n", - "... ... \n", - " 8 35 6 \n", - " 9 36 6 \n", - " 37 6 \n", - " 38 6 \n", - " 39 6 \n", - "\n", - " subsubregion_name \n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 \n", - " 1 6 \n", - " 2 6 \n", - " 3 6 \n", - " 1 4 6 \n", - "... ... \n", - " 8 35 6 \n", - " 9 36 6 \n", - " 37 6 \n", - " 38 6 \n", - " 39 6 \n", - "\n", - "[224 rows x 18 columns]" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from spyglass.common import Electrode, BrainRegion\n", - "\n", - "electrodes = (\n", - " (Electrode() & {\"nwb_file_name\": nwb_file_name}) * BrainRegion\n", - ").fetch(format=\"frame\")\n", - "electrodes" - ] - }, - { - "cell_type": "markdown", - "id": "c400f47e-a21b-451a-8721-35191161dc6e", - "metadata": {}, - "source": [ - "For ripple detection, we want only tetrodes, and only the first good wire on each tetrode. We will assume that is the first wire on each tetrode. I will do this using pandas syntax but you could use datajoint to filter this table as well. Here is the filtered table." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "83b9c019-a171-4d77-bccc-7c9945af1692", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -765,6 +179,13 @@ " \n", " \n", " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", @@ -788,84 +209,22 @@ " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", + " \n", " \n", - " \n", " \n", " \n", " \n", @@ -876,88 +235,20 @@ " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", " \n", " \n", + " \n", + " \n", + " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", " \n", " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", " \n", @@ -968,88 +259,26 @@ " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", " \n", @@ -1060,19 +289,20 @@ " \n", " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", " \n", @@ -1083,19 +313,273 @@ " \n", " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
probe_typeprobe_idprobe_shankprobe_electrodenamenwb_file_nameelectrode_group_nameelectrode_idlfp_merge_idfilter_namefilter_sampling_ratetarget_interval_list_namelfp_band_sampling_ratelfp_electrode_group_namereference_elect_idregion_id
chimi20200216_new_.nwb006tetrode_12.5000160.00.00.0None0.0False0.00.00.0Hippocampus
146tetrode_12.5004160.00.00.0None0.0False0.00.00.0Hippocampus
10406tetrode_12.50040160.00.00.0None0.0False0.00.00.0Hippocampus
11446tonks20211103_.nwb7282f3c93d5-5d5d-2d47-75b3-c346dddbd312Ripple 150-250 Hz1000test interval100CA1_test-119tetrode_12.5002844160.00.00.00.00.0Hippocampus
17686tetrode_12.50068810.00.00.0ca1None0.0False0.00.00.0Hippocampus
18726tetrode_12.50072810.00.00.0None0.0False0.00.00.0Hippocampus
1000CA1_test-119766tetrode_12.50076810.00.00.0None0.0False0.00.00.0Hippocampus
286tetrode_12.50081628440.00.00.00.00.0Hippocampus
21846tetrode_12.50084810.00.00.0ca1None0.0False0.00.00.0Hippocampus
22886tetrode_12.50088810.00.00.0None0.0False0.00.00.0Hippocampus
23926tetrode_12.50092810.00.00.0None0.0False0.00.00.0Hippocampus
3126
8322f3c93d5-5d5d-2d47-75b3-c346dddbd312Ripple 150-250 Hz1000test interval100CA1_test-119tetrode_12.500121632440.00.00.00.00.0Hippocampusca1NoneNone
52061000CA1_test-119tetrode_12.500201632440.00.00.00.00.0Hippocampusca1NoneNone
\n", + "
" + ], + "text/plain": [ + " probe_id \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 tetrode_12.5 \n", + " 1000 CA1_test -1 19 tetrode_12.5 \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 tetrode_12.5 \n", + " 1000 CA1_test -1 19 tetrode_12.5 \n", + "\n", + " probe_shank \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0 \n", + " 1000 CA1_test -1 19 0 \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0 \n", + " 1000 CA1_test -1 19 0 \n", + "\n", + " probe_electrode \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0 \n", + " 1000 CA1_test -1 19 0 \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0 \n", + " 1000 CA1_test -1 19 0 \n", + "\n", + " name \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 28 \n", + " 1000 CA1_test -1 19 28 \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 32 \n", + " 1000 CA1_test -1 19 32 \n", + "\n", + " original_reference_electrode \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 44 \n", + " 1000 CA1_test -1 19 44 \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 44 \n", + " 1000 CA1_test -1 19 44 \n", + "\n", + " x \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0.0 \n", + " 1000 CA1_test -1 19 0.0 \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0.0 \n", + " 1000 CA1_test -1 19 0.0 \n", + "\n", + " y \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0.0 \n", + " 1000 CA1_test -1 19 0.0 \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0.0 \n", + " 1000 CA1_test -1 19 0.0 \n", + "\n", + " z \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0.0 \n", + " 1000 CA1_test -1 19 0.0 \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0.0 \n", + " 1000 CA1_test -1 19 0.0 \n", + "\n", + " filtering \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 None \n", + " 1000 CA1_test -1 19 None \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 None \n", + " 1000 CA1_test -1 19 None \n", + "\n", + " impedance \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0.0 \n", + " 1000 CA1_test -1 19 0.0 \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0.0 \n", + " 1000 CA1_test -1 19 0.0 \n", + "\n", + " bad_channel \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 False \n", + " 1000 CA1_test -1 19 False \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 False \n", + " 1000 CA1_test -1 19 False \n", + "\n", + " x_warped \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0.0 \n", + " 1000 CA1_test -1 19 0.0 \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0.0 \n", + " 1000 CA1_test -1 19 0.0 \n", + "\n", + " y_warped \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0.0 \n", + " 1000 CA1_test -1 19 0.0 \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0.0 \n", + " 1000 CA1_test -1 19 0.0 \n", + "\n", + " z_warped \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0.0 \n", + " 1000 CA1_test -1 19 0.0 \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0.0 \n", + " 1000 CA1_test -1 19 0.0 \n", + "\n", + " contacts \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 \n", + " 1000 CA1_test -1 19 \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 \n", + " 1000 CA1_test -1 19 \n", + "\n", + " region_name \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 ca1 \n", + " 1000 CA1_test -1 19 ca1 \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 ca1 \n", + " 1000 CA1_test -1 19 ca1 \n", + "\n", + " subregion_name \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 None \n", + " 1000 CA1_test -1 19 None \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 None \n", + " 1000 CA1_test -1 19 None \n", + "\n", + " subsubregion_name \n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 None \n", + " 1000 CA1_test -1 19 None \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 None \n", + " 1000 CA1_test -1 19 None " + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "electrodes = (\n", + " (sgc.Electrode() & {\"nwb_file_name\": nwb_file_name}) * \n", + " (LFPBandSelection.LFPBandElectrode() & {\n", + " \"nwb_file_name\": nwb_file_name,\n", + " \"filter_name\": filter_name,\n", + " \"target_interval_list_name\": interval_list_name\n", + " }) * sgc.BrainRegion\n", + ").fetch(format=\"frame\")\n", + "electrodes" + ] + }, + { + "cell_type": "markdown", + "id": "c400f47e-a21b-451a-8721-35191161dc6e", + "metadata": {}, + "source": [ + "For ripple detection, we want only tetrodes, and only the first good wire on each tetrode. We will assume that is the first wire on each tetrode. I will do this using pandas syntax but you could use datajoint to filter this table as well. Here is the filtered table." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "83b9c019-a171-4d77-bccc-7c9945af1692", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", " \n", @@ -1106,19 +590,20 @@ " \n", " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1129,19 +614,26 @@ " \n", " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1152,19 +644,20 @@ " \n", " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", " \n", @@ -1175,354 +668,140 @@ " \n", " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", " \n", " \n", "
probe_idprobe_shankprobe_electrodenameoriginal_reference_electrodexyzfilteringimpedancebad_channelx_warpedy_warpedz_warpedcontactsregion_namesubregion_namesubsubregion_name
6246nwb_file_nameelectrode_group_nameelectrode_idlfp_merge_idfilter_namefilter_sampling_ratetarget_interval_list_namelfp_band_sampling_ratelfp_electrode_group_namereference_elect_idregion_id
tonks20211103_.nwb7282f3c93d5-5d5d-2d47-75b3-c346dddbd312Ripple 150-250 Hz1000test interval100CA1_test-119tetrode_12.500241628440.00.00.00.00.0Hippocampusca1NoneNone
72861000CA1_test-119tetrode_12.5002816440.00.00.00.00.0Hippocampusca1NoneNone
83268322f3c93d5-5d5d-2d47-75b3-c346dddbd312Ripple 150-250 Hz1000test interval100CA1_test-119tetrode_12.5003216440.00.00.00.00.0Hippocampusca1NoneNone
93661000CA1_test-119tetrode_12.500361632440.00.00.00.00.0Hippocampusca1NoneNone
\n", "
" ], "text/plain": [ - " probe_type \\\n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 tetrode_12.5 \n", - " 1 4 6 tetrode_12.5 \n", - " 10 40 6 tetrode_12.5 \n", - " 11 44 6 tetrode_12.5 \n", - " 17 68 6 tetrode_12.5 \n", - " 18 72 6 tetrode_12.5 \n", - " 19 76 6 tetrode_12.5 \n", - " 2 8 6 tetrode_12.5 \n", - " 21 84 6 tetrode_12.5 \n", - " 22 88 6 tetrode_12.5 \n", - " 23 92 6 tetrode_12.5 \n", - " 3 12 6 tetrode_12.5 \n", - " 5 20 6 tetrode_12.5 \n", - " 6 24 6 tetrode_12.5 \n", - " 7 28 6 tetrode_12.5 \n", - " 8 32 6 tetrode_12.5 \n", - " 9 36 6 tetrode_12.5 \n", + " probe_id \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 tetrode_12.5 \n", + " 1000 CA1_test -1 19 tetrode_12.5 \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 tetrode_12.5 \n", + " 1000 CA1_test -1 19 tetrode_12.5 \n", + "\n", + " probe_shank \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0 \n", + " 1000 CA1_test -1 19 0 \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0 \n", + " 1000 CA1_test -1 19 0 \n", "\n", - " probe_shank \\\n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 0 \n", - " 1 4 6 0 \n", - " 10 40 6 0 \n", - " 11 44 6 0 \n", - " 17 68 6 0 \n", - " 18 72 6 0 \n", - " 19 76 6 0 \n", - " 2 8 6 0 \n", - " 21 84 6 0 \n", - " 22 88 6 0 \n", - " 23 92 6 0 \n", - " 3 12 6 0 \n", - " 5 20 6 0 \n", - " 6 24 6 0 \n", - " 7 28 6 0 \n", - " 8 32 6 0 \n", - " 9 36 6 0 \n", + " probe_electrode \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0 \n", + " 1000 CA1_test -1 19 0 \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0 \n", + " 1000 CA1_test -1 19 0 \n", "\n", - " probe_electrode \\\n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 0 \n", - " 1 4 6 0 \n", - " 10 40 6 0 \n", - " 11 44 6 0 \n", - " 17 68 6 0 \n", - " 18 72 6 0 \n", - " 19 76 6 0 \n", - " 2 8 6 0 \n", - " 21 84 6 0 \n", - " 22 88 6 0 \n", - " 23 92 6 0 \n", - " 3 12 6 0 \n", - " 5 20 6 0 \n", - " 6 24 6 0 \n", - " 7 28 6 0 \n", - " 8 32 6 0 \n", - " 9 36 6 0 \n", + " name \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 28 \n", + " 1000 CA1_test -1 19 28 \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 32 \n", + " 1000 CA1_test -1 19 32 \n", "\n", - " name \\\n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 0 \n", - " 1 4 6 4 \n", - " 10 40 6 40 \n", - " 11 44 6 44 \n", - " 17 68 6 68 \n", - " 18 72 6 72 \n", - " 19 76 6 76 \n", - " 2 8 6 8 \n", - " 21 84 6 84 \n", - " 22 88 6 88 \n", - " 23 92 6 92 \n", - " 3 12 6 12 \n", - " 5 20 6 20 \n", - " 6 24 6 24 \n", - " 7 28 6 28 \n", - " 8 32 6 32 \n", - " 9 36 6 36 \n", + " original_reference_electrode \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 44 \n", + " 1000 CA1_test -1 19 44 \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 44 \n", + " 1000 CA1_test -1 19 44 \n", "\n", - " original_reference_electrode \\\n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 16 \n", - " 1 4 6 16 \n", - " 10 40 6 16 \n", - " 11 44 6 16 \n", - " 17 68 6 81 \n", - " 18 72 6 81 \n", - " 19 76 6 81 \n", - " 2 8 6 16 \n", - " 21 84 6 81 \n", - " 22 88 6 81 \n", - " 23 92 6 81 \n", - " 3 12 6 16 \n", - " 5 20 6 16 \n", - " 6 24 6 16 \n", - " 7 28 6 16 \n", - " 8 32 6 16 \n", - " 9 36 6 16 \n", + " x \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0.0 \n", + " 1000 CA1_test -1 19 0.0 \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0.0 \n", + " 1000 CA1_test -1 19 0.0 \n", "\n", - " x y \\\n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 0.0 0.0 \n", - " 1 4 6 0.0 0.0 \n", - " 10 40 6 0.0 0.0 \n", - " 11 44 6 0.0 0.0 \n", - " 17 68 6 0.0 0.0 \n", - " 18 72 6 0.0 0.0 \n", - " 19 76 6 0.0 0.0 \n", - " 2 8 6 0.0 0.0 \n", - " 21 84 6 0.0 0.0 \n", - " 22 88 6 0.0 0.0 \n", - " 23 92 6 0.0 0.0 \n", - " 3 12 6 0.0 0.0 \n", - " 5 20 6 0.0 0.0 \n", - " 6 24 6 0.0 0.0 \n", - " 7 28 6 0.0 0.0 \n", - " 8 32 6 0.0 0.0 \n", - " 9 36 6 0.0 0.0 \n", + " y \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0.0 \n", + " 1000 CA1_test -1 19 0.0 \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0.0 \n", + " 1000 CA1_test -1 19 0.0 \n", "\n", - " z \\\n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 0.0 \n", - " 1 4 6 0.0 \n", - " 10 40 6 0.0 \n", - " 11 44 6 0.0 \n", - " 17 68 6 0.0 \n", - " 18 72 6 0.0 \n", - " 19 76 6 0.0 \n", - " 2 8 6 0.0 \n", - " 21 84 6 0.0 \n", - " 22 88 6 0.0 \n", - " 23 92 6 0.0 \n", - " 3 12 6 0.0 \n", - " 5 20 6 0.0 \n", - " 6 24 6 0.0 \n", - " 7 28 6 0.0 \n", - " 8 32 6 0.0 \n", - " 9 36 6 0.0 \n", + " z \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0.0 \n", + " 1000 CA1_test -1 19 0.0 \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0.0 \n", + " 1000 CA1_test -1 19 0.0 \n", "\n", - " filtering \\\n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 None \n", - " 1 4 6 None \n", - " 10 40 6 None \n", - " 11 44 6 None \n", - " 17 68 6 None \n", - " 18 72 6 None \n", - " 19 76 6 None \n", - " 2 8 6 None \n", - " 21 84 6 None \n", - " 22 88 6 None \n", - " 23 92 6 None \n", - " 3 12 6 None \n", - " 5 20 6 None \n", - " 6 24 6 None \n", - " 7 28 6 None \n", - " 8 32 6 None \n", - " 9 36 6 None \n", + " filtering \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 None \n", + " 1000 CA1_test -1 19 None \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 None \n", + " 1000 CA1_test -1 19 None \n", "\n", - " impedance \\\n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 0.0 \n", - " 1 4 6 0.0 \n", - " 10 40 6 0.0 \n", - " 11 44 6 0.0 \n", - " 17 68 6 0.0 \n", - " 18 72 6 0.0 \n", - " 19 76 6 0.0 \n", - " 2 8 6 0.0 \n", - " 21 84 6 0.0 \n", - " 22 88 6 0.0 \n", - " 23 92 6 0.0 \n", - " 3 12 6 0.0 \n", - " 5 20 6 0.0 \n", - " 6 24 6 0.0 \n", - " 7 28 6 0.0 \n", - " 8 32 6 0.0 \n", - " 9 36 6 0.0 \n", + " impedance \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0.0 \n", + " 1000 CA1_test -1 19 0.0 \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0.0 \n", + " 1000 CA1_test -1 19 0.0 \n", "\n", - " bad_channel \\\n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 False \n", - " 1 4 6 False \n", - " 10 40 6 False \n", - " 11 44 6 False \n", - " 17 68 6 False \n", - " 18 72 6 False \n", - " 19 76 6 False \n", - " 2 8 6 False \n", - " 21 84 6 False \n", - " 22 88 6 False \n", - " 23 92 6 False \n", - " 3 12 6 False \n", - " 5 20 6 False \n", - " 6 24 6 False \n", - " 7 28 6 False \n", - " 8 32 6 False \n", - " 9 36 6 False \n", + " bad_channel \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 False \n", + " 1000 CA1_test -1 19 False \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 False \n", + " 1000 CA1_test -1 19 False \n", "\n", - " x_warped \\\n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 0.0 \n", - " 1 4 6 0.0 \n", - " 10 40 6 0.0 \n", - " 11 44 6 0.0 \n", - " 17 68 6 0.0 \n", - " 18 72 6 0.0 \n", - " 19 76 6 0.0 \n", - " 2 8 6 0.0 \n", - " 21 84 6 0.0 \n", - " 22 88 6 0.0 \n", - " 23 92 6 0.0 \n", - " 3 12 6 0.0 \n", - " 5 20 6 0.0 \n", - " 6 24 6 0.0 \n", - " 7 28 6 0.0 \n", - " 8 32 6 0.0 \n", - " 9 36 6 0.0 \n", + " x_warped \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0.0 \n", + " 1000 CA1_test -1 19 0.0 \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0.0 \n", + " 1000 CA1_test -1 19 0.0 \n", "\n", - " y_warped \\\n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 0.0 \n", - " 1 4 6 0.0 \n", - " 10 40 6 0.0 \n", - " 11 44 6 0.0 \n", - " 17 68 6 0.0 \n", - " 18 72 6 0.0 \n", - " 19 76 6 0.0 \n", - " 2 8 6 0.0 \n", - " 21 84 6 0.0 \n", - " 22 88 6 0.0 \n", - " 23 92 6 0.0 \n", - " 3 12 6 0.0 \n", - " 5 20 6 0.0 \n", - " 6 24 6 0.0 \n", - " 7 28 6 0.0 \n", - " 8 32 6 0.0 \n", - " 9 36 6 0.0 \n", + " y_warped \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0.0 \n", + " 1000 CA1_test -1 19 0.0 \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0.0 \n", + " 1000 CA1_test -1 19 0.0 \n", "\n", - " z_warped \\\n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 0.0 \n", - " 1 4 6 0.0 \n", - " 10 40 6 0.0 \n", - " 11 44 6 0.0 \n", - " 17 68 6 0.0 \n", - " 18 72 6 0.0 \n", - " 19 76 6 0.0 \n", - " 2 8 6 0.0 \n", - " 21 84 6 0.0 \n", - " 22 88 6 0.0 \n", - " 23 92 6 0.0 \n", - " 3 12 6 0.0 \n", - " 5 20 6 0.0 \n", - " 6 24 6 0.0 \n", - " 7 28 6 0.0 \n", - " 8 32 6 0.0 \n", - " 9 36 6 0.0 \n", + " z_warped \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0.0 \n", + " 1000 CA1_test -1 19 0.0 \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 0.0 \n", + " 1000 CA1_test -1 19 0.0 \n", "\n", - " contacts \\\n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 \n", - " 1 4 6 \n", - " 10 40 6 \n", - " 11 44 6 \n", - " 17 68 6 \n", - " 18 72 6 \n", - " 19 76 6 \n", - " 2 8 6 \n", - " 21 84 6 \n", - " 22 88 6 \n", - " 23 92 6 \n", - " 3 12 6 \n", - " 5 20 6 \n", - " 6 24 6 \n", - " 7 28 6 \n", - " 8 32 6 \n", - " 9 36 6 \n", + " contacts \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 \n", + " 1000 CA1_test -1 19 \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 \n", + " 1000 CA1_test -1 19 \n", "\n", - " region_name \\\n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 Hippocampus \n", - " 1 4 6 Hippocampus \n", - " 10 40 6 Hippocampus \n", - " 11 44 6 Hippocampus \n", - " 17 68 6 Hippocampus \n", - " 18 72 6 Hippocampus \n", - " 19 76 6 Hippocampus \n", - " 2 8 6 Hippocampus \n", - " 21 84 6 Hippocampus \n", - " 22 88 6 Hippocampus \n", - " 23 92 6 Hippocampus \n", - " 3 12 6 Hippocampus \n", - " 5 20 6 Hippocampus \n", - " 6 24 6 Hippocampus \n", - " 7 28 6 Hippocampus \n", - " 8 32 6 Hippocampus \n", - " 9 36 6 Hippocampus \n", + " region_name \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 ca1 \n", + " 1000 CA1_test -1 19 ca1 \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 ca1 \n", + " 1000 CA1_test -1 19 ca1 \n", "\n", - " subregion_name \\\n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 \n", - " 1 4 6 \n", - " 10 40 6 \n", - " 11 44 6 \n", - " 17 68 6 \n", - " 18 72 6 \n", - " 19 76 6 \n", - " 2 8 6 \n", - " 21 84 6 \n", - " 22 88 6 \n", - " 23 92 6 \n", - " 3 12 6 \n", - " 5 20 6 \n", - " 6 24 6 \n", - " 7 28 6 \n", - " 8 32 6 \n", - " 9 36 6 \n", + " subregion_name \\\n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 None \n", + " 1000 CA1_test -1 19 None \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 None \n", + " 1000 CA1_test -1 19 None \n", "\n", - " subsubregion_name \n", - "nwb_file_name electrode_group_name electrode_id region_id \n", - "chimi20200216_new_.nwb 0 0 6 \n", - " 1 4 6 \n", - " 10 40 6 \n", - " 11 44 6 \n", - " 17 68 6 \n", - " 18 72 6 \n", - " 19 76 6 \n", - " 2 8 6 \n", - " 21 84 6 \n", - " 22 88 6 \n", - " 23 92 6 \n", - " 3 12 6 \n", - " 5 20 6 \n", - " 6 24 6 \n", - " 7 28 6 \n", - " 8 32 6 \n", - " 9 36 6 " + " subsubregion_name \n", + "nwb_file_name electrode_group_name electrode_id lfp_merge_id filter_name filter_sampling_rate target_interval_list_name lfp_band_sampling_rate lfp_electrode_group_name reference_elect_id region_id \n", + "tonks20211103_.nwb 7 28 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 None \n", + " 1000 CA1_test -1 19 None \n", + " 8 32 2f3c93d5-5d5d-2d47-75b3-c346dddbd312 Ripple 150-250 Hz 1000 test interval 100 CA1_test -1 19 None \n", + " 1000 CA1_test -1 19 None " ] }, "execution_count": 5, @@ -1531,8 +810,9 @@ } ], "source": [ + "hpc_names = [\"ca1\", \"hippocampus\", \"CA1\", \"Hippocampus\"]\n", "electrodes.loc[\n", - " (electrodes.region_name == \"Hippocampus\")\n", + " (electrodes.region_name.isin(hpc_names))\n", " & (electrodes.probe_electrode == 0)\n", "]" ] @@ -1547,32 +827,29 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 13, "id": "0eba0656-c4dd-42bd-b18f-23aac13eb70a", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[0, 4, 40, 44, 68, 72, 76, 8, 84, 88, 92, 12, 20, 24, 28, 32, 36]" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ - "electrode_list = (\n", + "electrode_list = np.unique((\n", " electrodes.loc[\n", - " (electrodes.region_name == \"Hippocampus\")\n", + " (electrodes.region_name.isin(hpc_names))\n", " & (electrodes.probe_electrode == 0)\n", " ]\n", " .reset_index()\n", " .electrode_id\n", - ").tolist()\n", + ").tolist())\n", "\n", - "electrode_list" + "electrode_list.sort()" + ] + }, + { + "cell_type": "markdown", + "id": "14133ef0-06d0-4e1e-827b-882227d8bfe9", + "metadata": {}, + "source": [ + "Another approach is to use all the available electrodes from `LFPBandV1`, which is the default behavior of `set_lfp_electrodes`" ] }, { @@ -1580,26 +857,28 @@ "id": "a9d4a09c-a098-4be3-89d4-67269337c41f", "metadata": {}, "source": [ - "Now we can set `RippleLFPSelection`." + "Now we can insert into `RippleLFPSelection` and it's part table - `RippleLFPSelection.RippleLFPElectrode`
We'll pass the key for the entry from `LFPBandV1`, our `electrode_list`, and the `group_name` into `set_lfp_electrodes`" ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 18, "id": "345709c2-2892-407d-ab2d-d3fd36f67d69", "metadata": {}, "outputs": [], "source": [ - "RippleLFPSelection.set_lfp_electrodes(\n", - " nwb_file_name,\n", - " electrode_list,\n", - " group_name=\"CA1\",\n", + "group_name = \"CA1_test\"\n", + "lfp_band_key = (LFPBandV1() & {\"filter_name\": filter_name, \"nwb_file_name\": nwb_file_name}).fetch1(\"KEY\")\n", + "sgrip.RippleLFPSelection.set_lfp_electrodes(\n", + " lfp_band_key,\n", + " electrode_list=electrode_list,\n", + " group_name=group_name,\n", ")" ] }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 20, "id": "96eb2aae-e93a-4214-a5e2-8c729767634b", "metadata": {}, "outputs": [ @@ -1609,21 +888,23 @@ "\n", " \n", " \n", + " \n", + " \n", + "
\n", + " \n", + " \n", + " \n", + "
\n", + "

nwb_file_name

\n", + " \n", + "
\n", + "

sort_group_id

\n", + " \n", + "
\n", + "

sort_interval_name

\n", + " \n", + "
\n", + "

filter_parameter_set_name

\n", + " \n", + "
\n", + "

sorter_name

\n", + " \n", + "
\n", + "

spikesorter_parameter_set_name

\n", + " \n", + "
\n", + "

sorting_id

\n", + " \n", + "
\n", + "

analysis_file_name

\n", + " \n", + "
\n", + "

time_of_sort

\n", + " in Unix time, to the nearest second\n", + "
\n", + "

units_object_id

\n", + " \n", + "
\n", + " \n", + "

Total: 0

\n", + " " + ], + "text/plain": [ + "*nwb_file_name *sort_group_id *sort_interval *filter_parame *sorter_name *spikesorter_p sorting_id analysis_file_ time_of_sort units_object_i\n", + "+------------+ +------------+ +------------+ +------------+ +------------+ +------------+ +------------+ +------------+ +------------+ +------------+\n", + "\n", + " (Total: 0)" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from spyglass.common import SpikeSortingBackUp\n", + "\n", + "SpikeSortingBackUp()" + ] + }, + { + "cell_type": "markdown", + "id": "c6850095", + "metadata": {}, + "source": [ + "Next, we'll try [inserting data](./01_Insert_Data.ipynb)\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.16" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/00_intro.ipynb b/notebooks/00_intro.ipynb deleted file mode 100644 index 374dd5d86..000000000 --- a/notebooks/00_intro.ipynb +++ /dev/null @@ -1,524 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "tags": [] - }, - "source": [ - "## Spyglass tutorial 0\n", - "\n", - "**Note: make a copy of this notebook and run the copy to avoid git conflicts in the future**\n", - "\n", - "This is the zeroth in a multi-part tutorial on the Spyglass pipeline used in Loren Frank's lab, UCSF. It gives a general introduction to Datajoint and shows how to insert an NWB file into the Datajoint database, inspect and query the data, and delete it.\n", - "\n", - "Let's start by importing the `spyglass` package, along with a few others. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "import os\n", - "import numpy as np\n", - "\n", - "import spyglass as sg\n", - "import datajoint as dj\n", - "\n", - "# ignore datajoint+jupyter async warnings\n", - "import warnings\n", - "\n", - "warnings.simplefilter(\"ignore\", category=DeprecationWarning)\n", - "warnings.simplefilter(\"ignore\", category=ResourceWarning)\n", - "warnings.simplefilter(\"ignore\", category=UserWarning)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# We also import spyglass.common so we can call tables more easily\n", - "import spyglass.common as sgc\n", - "\n", - "# We import spyglass.data_import to allow for inserting an NWB file into the database\n", - "import spyglass.data_import as sdi" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "tags": [] - }, - "source": [ - "### Visualizing the database\n", - "\n", - "Datajoint enables users to use Python to build and interact with a *Relational Database*. A *Relational Database* stores and provides access to data stored in row-features and column-features. Each row provide information about different features of an individivial object while each column provide information about a single feature for a collection of objects. It supports the ability to create a new object, read an existing object, update an existing object and delete an object.\n", - "\n", - "The following diagram (called *entity relationship diagram*) shows all the tables in our database and their relationships.\n", - "\n", - "Polygons are tables:\n", - "* Blue oval: tables whose entries are imported from external files (e.g. NWB file).\n", - "* Green rectangle: tables whose entries are entered manually.\n", - "* Red circle: tables whose entries are computed from entries of other tables.\n", - "* No shape (only text): tables whose entries are part of the table upstream\n", - "\n", - "Lines are *dependencies* between tables:\n", - "* Bold lines: downstream table inherits the *primary key* ^ of upstream table as its sole primary key\n", - "* Solid lines: downstream table inherits the primary key of upstream table as part of its primary key\n", - "* Dashed lines: downstream table inherits the primary key of upstream table as non-primary key\n", - "\n", - "^ Primary key: a set of attributes (i.e. column names) used to uniquely define an entry (i.e. a row)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Draw tables that are three levels below and one level above Session\n", - "dj.ERD(sgc.Session) - 1 + 3" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Example data" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now that we have a general idea of how our database is organized, we will try inserting new data to it. We assume that the data is a neural recording (along with other auxiliary data) that has already been converted to the NWB format. For the purposes of this tutorial, we will use `montague20200802.nwb`. If you're accessing the Frank lab database on the UCSF network, this file can be found in `/stelmo/nwb/raw` directory (assuming you have mounted `stelmo` at `/`). If you do not have access to Frank lab database, then download `montague20200802.nwb` from [here](https://www.dropbox.com/scl/fo/4i5b1z4iapetzxfps0grf/h?dl=0&preview=montague20200802_tutorial_.nwb&rlkey=ctahes9v0r7bxes8yceh86gzg) - It is about 8 GB in size. \n", - "\n", - "Once you have the NWB file, you should copy it and rename the copy to something unique (e.g. `montague20200802_yourname.nwb`). This is because many people will be using this example file to practice inserting data, and a file can only be inserted once (the file name acts as a *primary key* in the `Session` table). " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Define the name of the file that you copied and renamed; make sure it's something unique.\n", - "nwb_file_name = \"montague20200802_tutorial.nwb\"\n", - "filename, file_extension = os.path.splitext(nwb_file_name)\n", - "# This is a copy of the original nwb file, except it doesn't contain the raw data (for storage reasons)\n", - "nwb_copy_file_name = filename + \"_\" + file_extension" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "nwb_file_name" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Inserting data\n", - "\n", - "As you may know, the NWB file contains a lot of information, such as information about the experimenter (e.g. who did the experiment, where was it done, etc); the animal's behavior (e.g. video recording of the animal's position in an environment during the experiment); the neural activity (extracellular recording of multiple brain areas) etc. We wish to enter this information into the tables of our Datajoint database so that we can easily access them later. If we have an NWB file that has been properly generated, this is straightforward: just run the `sg.insert_session` function, which will populate many of the tables automatically. Let's do this for our example NWB file.\n", - "\n", - "Note: this may take a while because it makes a copy of the NWB file." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "sdi.insert_sessions(nwb_file_name)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "tags": [] - }, - "source": [ - "### Inspecting and querying data\n", - "\n", - "To look at the tables, just call it (don't forget the `()` at the end, as tables are like Python classes). Let's try calling the `Lab` table." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sgc.Lab()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There is only one attribute (`lab_name`) and two entries (`Loren Frank`, `Giocomo`) in this table. Note that even though `Lab` is one of the tables that has to be manually entered (i.e. the green rectangles in our ERD), `sg.insert_sessions` populates it from the NWB file." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's look at a more interesting table: `Session`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sgc.Session()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This session has multiple attributes. The attributes that make up the primary key are shown in bold. In this case, there is only one attribute in the primary key: `nwb_file_name`. Given that many downstream tables are connected to `Session` via bold lines, you can use this attribute to uniquely define data entries in many tables in our database." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# can also look at the docstring\n", - "sgc.Session.describe()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To look at specific entries from a table, include the appropriate condition with the `&` operator. The condition must be in the form of a key-value pair, or a dictionary. As an example, let's view only the entry whose `nwb_file_name` is our example NWB file in `Session`:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sgc.Session & {\"nwb_file_name\": nwb_copy_file_name}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's go to a downstream table: `Raw`. This table is connected to `Session` table with a bold line, so it has the same primary key." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sgc.Raw & {\"nwb_file_name\": nwb_copy_file_name}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`IntervalList` table is connected to `Session` table with a solid line, as it inherits `nwb_file_name` as one of the two attributes that make up the primary key. This means that you need to know both `nwb_file_name` and `interval_list_name` to uniquely identify an entry." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sgc.IntervalList & {\"nwb_file_name\": nwb_copy_file_name}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As you can see, some of the data is shown in the table (e.g. `interval_list_name`) while others are obscured (e.g. `valid_times` are shown as `=BLOB=`). To inspect the data, use the `fetch` (for getting multiple entries) or `fetch1` (for getting just one entry) methods. The following query returns `valid_times` of an interval list called `04_r2`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "(\n", - " sgc.IntervalList\n", - " & {\"nwb_file_name\": nwb_copy_file_name, \"interval_list_name\": \"04_r2\"}\n", - ").fetch1(\"valid_times\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Query supports many operations and conditions - just make sure the conditions are in the form of a dictionary. We have already seen that `&` represents the set-theoretic intersection. `-`, on the other hand, is like the set-theoretic complement. The following query returns all `interval_list_name` that is not `01_s1` or `04_r2`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "(\n", - " (\n", - " (sgc.IntervalList & {\"nwb_file_name\": nwb_copy_file_name})\n", - " - {\"interval_list_name\": \"01_s1\"}\n", - " )\n", - " - {\"interval_list_name\": \"04_r2\"}\n", - ").fetch(\"interval_list_name\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Other available operations are described [here](https://docs.datajoint.org/python/queries/05-Operators.html). Also feel free to inspect other tables and learn what kind of data they contain." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Deleting data \n", - "\n", - "Another neat feature of Datajoint is that it automatically maintains the integrity of your data. For example, if we were to delete our entry in the `Session` table, the associated entries in all of the downstream tables (e.g. `Raw`, `IntervalList`, `ElectrodeGroup` to name a few) will also be deleted. That way, there is no 'orphan' data whose origin cannot be tracked. We will do this now using the `delete` method." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# our data is currently in Session table\n", - "sgc.Session & {\"nwb_file_name\": nwb_copy_file_name}" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Type `yes` when prompted to delete\n", - "(sgc.Session & {\"nwb_file_name\": nwb_copy_file_name}).delete()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Check that delete worked\n", - "sgc.Session & {\"nwb_file_name\": nwb_copy_file_name}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`delete` method is useful when you need to re-do something. We discourage editing an entry because this will affect the associated entries in downstream tables and violate data integrity. Instead it is recommended that you just delete and re-enter it. This is easy to do, as most data entry is automated in our pipeline." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Entries are also gone from downstream tables, e.g. IntervalList\n", - "sgc.IntervalList & {\"nwb_file_name\": nwb_copy_file_name}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We're not quite done yet. Not only should we delete our entry from `Session`, we should also delete the associated entry in `Nwbfile`. Recall from the entity relationship diagram that `Nwbfile` is upstream of `Session`. That means getting rid of our entry from `Session` doesn't affect the corresponding entry in `Nwbfile` - this has to be manually removed. To do so, we again use the `delete` method, but in the case of `Nwbfile` there is an extra step: we need to remove the NWB file itself as well as the entry from `Nwbfile` table. To remove the files, we run the `cleanup` method with the `delete_files` argument as `True`. \n", - "\n", - "Note that the same idea applies to deleting files from `AnalysisNwbfile` table. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Check out the Nwb file\n", - "sgc.Nwbfile & {\"nwb_file_name\": nwb_copy_file_name}" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Let's delete the entry\n", - "(sgc.Nwbfile & {\"nwb_file_name\": nwb_copy_file_name}).delete()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Note that the file (ends with _.nwb) has not been deleted, even though the entry is\n", - "!ls $SPYGLASS_BASE_DIR/raw" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# We clean it up\n", - "sgc.Nwbfile().cleanup(delete_files=True)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Now the file is gone as well\n", - "!ls $SPYGLASS_BASE_DIR/raw" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Creating a Lab Team\n", - "\n", - "Before we end this tutorial, there is one last thing we must do: create a lab team. A lab team is a set of lab members who own a set of NWB files and the associated information in our Datajoint database. Think of this as a \"subgroup\" within the lab that collaborates on the same projects. Only the members of a lab team will be able to delete table entries they made (this permission system is not yet implemented; we're working on it). Right now we need to set a lab team so that the permission for manual curation of spike sorted data can be set (this will be covered in [tutorial 2](2_curation.ipynb)).\n", - "\n", - "The `LabMember` table contains the list of lab members. It has a parts table called `LabMemberInfo`, where the Google account of each member can be found (for authentication purposes). Similarly, `LabTeam` table contains the list of lab teams and has a parts table called `LabTeamMember` which specifies which of the lab members (as entered in `LabMember`) belongs to each lab team. Both `LabMember` and `LabTeam` are `dj.Manual` tables, which means the data can be entered manually (although when we add our NWB file with `nd.insert_sessions(nwb_file_name)`, the owner of the NWB file (as specified in the `experimenter` field) is automatically entered into `LabMember` table). \n", - "\n", - "To proceed, we will create a new team using the `create_new_team` method of `LabTeam`. You will give this team a name, and add yourself (and your Google account) to this team. Later, when we do spike sorting, we will specify the team the sorting belongs to. This will give everyone in the team (in this case, just you) the permission to add curation labels." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# take a look at the lab members\n", - "sgc.LabMember()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# LabMember also has a Parts table called LabMemberInfo\n", - "sgc.LabMember.LabMemberInfo()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# these are the existing lab teams\n", - "sgc.LabTeam()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# create a new team\n", - "# change team_name to something unique\n", - "# change team_members\n", - "# team_description is optional\n", - "sgc.LabTeam().create_new_team(\n", - " team_name=\"Beans\", team_members=[\"Alison Comrie\"], team_description=\"test\"\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# add info about the team members\n", - "# add your name and your google account\n", - "sgc.LabMember.LabMemberInfo.insert(\n", - " [[\"Alison Comrie\", \"comrie.alison@gmail.com\", \"alison\"]],\n", - " skip_duplicates=True,\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sgc.LabMember.LabMemberInfo()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python [conda env:spyglass_si]", - "language": "python", - "name": "conda-env-spyglass_si-py" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.13" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/notebooks/01_Insert_Data.ipynb b/notebooks/01_Insert_Data.ipynb new file mode 100644 index 000000000..4f19895b4 --- /dev/null +++ b/notebooks/01_Insert_Data.ipynb @@ -0,0 +1,2564 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "# Insert Data\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Intro\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "_Developer Note:_ if you may make a PR in the future, be sure to copy this\n", + "notebook, and use the `gitignore` prefix `temp` to avoid future conflicts.\n", + "\n", + "This is one notebook in a multi-part series on Spyglass.\n", + "\n", + "- To set up your Spyglass environment and database, see\n", + " [the Setup notebook](./00_Setup.ipynb)\n", + "- For additional info on DataJoint syntax, including table definitions and\n", + " inserts, see\n", + " [these additional tutorials](https://github.com/datajoint/datajoint-tutorials)\n", + "\n", + "Let's start by importing the `spyglass` package, along with a few others.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[2023-07-18 17:58:44,303][INFO]: Connecting root@localhost:3306\n", + "[2023-07-18 17:58:44,332][INFO]: Connected root@localhost:3306\n" + ] + } + ], + "source": [ + "import os\n", + "import datajoint as dj\n", + "\n", + "# change to the upper level folder to detect dj_local_conf.json\n", + "if os.path.basename(os.getcwd()) == \"notebooks\":\n", + " os.chdir(\"..\")\n", + "dj.config.load(\"dj_local_conf.json\") # load config for database connection info\n", + "\n", + "# ignore datajoint+jupyter async warnings\n", + "import warnings\n", + "\n", + "warnings.simplefilter(\"ignore\", category=DeprecationWarning)\n", + "warnings.simplefilter(\"ignore\", category=ResourceWarning)\n", + "warnings.simplefilter(\"ignore\", category=UserWarning)\n", + "\n", + "# spyglass.common has the most frequently used tables\n", + "import spyglass.common as sgc\n", + "\n", + "# spyglass.data_import has tools for inserting NWB files into the database\n", + "import spyglass.data_import as sgi" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "## Visualizing the database\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Datajoint enables users to use Python to build and interact with a _Relational Database_. In a [Relational Data Model](https://www.smartsheet.com/relational-database-modeling), each table is an object that can reference\n", + "information in other tables to avoid redundancy.\n", + "\n", + "DataJoint has built-in tools for generating/saving a _Diagram_ of the\n", + "relationships between tables.\n", + "[This page](https://datajoint.com/docs/core/datajoint-python/0.14/design/diagrams/) describes the notation used.\n", + "\n", + "Polygons are tables, colors reference\n", + "[table type](https://datajoint.com/docs/core/datajoint-python/0.14/design/tables/tiers/):\n", + "\n", + "- Green rectangle: tables whose entries are entered _manually_.\n", + "- Blue oval: tables whose entries are _imported_ from external files\n", + " (e.g. NWB file).\n", + "- Red circle: tables whose entries are _computed_ from entries of other tables.\n", + "- No shape (only text): tables whose entries are _part_ of the table upstream\n", + "\n", + "Lines are _dependencies_ between tables. An _upstream_ table is connected to a\n", + "_downstream_ table via _inheritance_ of the\n", + "[_primary key_](https://docs.datajoint.org/python/definition/07-Primary-Key.html).\n", + "This is the set of attributes (i.e., column names) used to uniquely define an\n", + "entry (i.e., a row)\n", + "\n", + "- Bold lines: the upstream primary key is the sole downstream primary key\n", + "- Solid lines: the upstream table as part of the downstream primary key\n", + "- Dashed lines: the primary key of upstream table as non-primary key\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "0\n", + "\n", + "0\n", + "\n", + "\n", + "\n", + "sgc.LFPBandSelection\n", + "\n", + "\n", + "sgc.LFPBandSelection\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "0->sgc.LFPBandSelection\n", + "\n", + "\n", + "\n", + "\n", + "sgc.TaskEpoch\n", + "\n", + "\n", + "sgc.TaskEpoch\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.VideoFile\n", + "\n", + "\n", + "sgc.VideoFile\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.TaskEpoch->sgc.VideoFile\n", + "\n", + "\n", + "\n", + "\n", + "sgc.StateScriptFile\n", + "\n", + "\n", + "sgc.StateScriptFile\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.TaskEpoch->sgc.StateScriptFile\n", + "\n", + "\n", + "\n", + "\n", + "sgc.Subject\n", + "\n", + "\n", + "sgc.Subject\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.Session\n", + "\n", + "\n", + "sgc.Session\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.Subject->sgc.Session\n", + "\n", + "\n", + "\n", + "\n", + "sgc.common_session.SessionGroupSession\n", + "\n", + "\n", + "sgc.common_session.SessionGroupSession\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.Session.Experimenter\n", + "\n", + "\n", + "sgc.Session.Experimenter\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.Session.DataAcquisitionDevice\n", + "\n", + "\n", + "sgc.Session.DataAcquisitionDevice\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.Session->sgc.TaskEpoch\n", + "\n", + "\n", + "\n", + "\n", + "sgc.Session->sgc.common_session.SessionGroupSession\n", + "\n", + "\n", + "\n", + "\n", + "sgc.Session->sgc.Session.Experimenter\n", + "\n", + "\n", + "\n", + "\n", + "sgc.Session->sgc.Session.DataAcquisitionDevice\n", + "\n", + "\n", + "\n", + "\n", + "sgc.SensorData\n", + "\n", + "\n", + "sgc.SensorData\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.Session->sgc.SensorData\n", + "\n", + "\n", + "\n", + "\n", + "sgc.IntervalList\n", + "\n", + "\n", + "sgc.IntervalList\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.Session->sgc.IntervalList\n", + "\n", + "\n", + "\n", + "\n", + "sgc.LFPSelection\n", + "\n", + "\n", + "sgc.LFPSelection\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.Session->sgc.LFPSelection\n", + "\n", + "\n", + "\n", + "\n", + "sgc.SampleCount\n", + "\n", + "\n", + "sgc.SampleCount\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.Session->sgc.SampleCount\n", + "\n", + "\n", + "\n", + "\n", + "sgc.Raw\n", + "\n", + "\n", + "sgc.Raw\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.Session->sgc.Raw\n", + "\n", + "\n", + "\n", + "\n", + "sgc.ElectrodeGroup\n", + "\n", + "\n", + "sgc.ElectrodeGroup\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.Session->sgc.ElectrodeGroup\n", + "\n", + "\n", + "\n", + "\n", + "sgc.DIOEvents\n", + "\n", + "\n", + "sgc.DIOEvents\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.Session->sgc.DIOEvents\n", + "\n", + "\n", + "\n", + "\n", + "sgc.PositionSource\n", + "\n", + "\n", + "sgc.PositionSource\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.Session->sgc.PositionSource\n", + "\n", + "\n", + "\n", + "\n", + "sgc.IntervalPositionInfo\n", + "\n", + "\n", + "sgc.IntervalPositionInfo\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.IntervalLinearizationSelection\n", + "\n", + "\n", + "sgc.IntervalLinearizationSelection\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.IntervalPositionInfo->sgc.IntervalLinearizationSelection\n", + "\n", + "\n", + "\n", + "\n", + "sgc.IntervalLinearizedPosition\n", + "\n", + "\n", + "sgc.IntervalLinearizedPosition\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.IntervalPositionInfoSelection\n", + "\n", + "\n", + "sgc.IntervalPositionInfoSelection\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.IntervalPositionInfoSelection->sgc.IntervalPositionInfo\n", + "\n", + "\n", + "\n", + "\n", + "sgc.IntervalLinearizationSelection->sgc.IntervalLinearizedPosition\n", + "\n", + "\n", + "\n", + "\n", + "sgc.Nwbfile\n", + "\n", + "\n", + "sgc.Nwbfile\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.Nwbfile->sgc.Session\n", + "\n", + "\n", + "\n", + "\n", + "sgc.AnalysisNwbfile\n", + "\n", + "\n", + "sgc.AnalysisNwbfile\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.Nwbfile->sgc.AnalysisNwbfile\n", + "\n", + "\n", + "\n", + "\n", + "sgc.NwbfileKachery\n", + "\n", + "\n", + "sgc.NwbfileKachery\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.Nwbfile->sgc.NwbfileKachery\n", + "\n", + "\n", + "\n", + "\n", + "sgc.AnalysisNwbfile->sgc.IntervalPositionInfo\n", + "\n", + "\n", + "\n", + "\n", + "sgc.AnalysisNwbfile->sgc.IntervalLinearizedPosition\n", + "\n", + "\n", + "\n", + "\n", + "sgc.AnalysisNwbfileKachery\n", + "\n", + "\n", + "sgc.AnalysisNwbfileKachery\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.AnalysisNwbfile->sgc.AnalysisNwbfileKachery\n", + "\n", + "\n", + "\n", + "\n", + "sgc.LFP\n", + "\n", + "\n", + "sgc.LFP\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.AnalysisNwbfile->sgc.LFP\n", + "\n", + "\n", + "\n", + "\n", + "sgc.LFPBand\n", + "\n", + "\n", + "sgc.LFPBand\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.AnalysisNwbfile->sgc.LFPBand\n", + "\n", + "\n", + "\n", + "\n", + "sgc.Lab\n", + "\n", + "\n", + "sgc.Lab\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.Lab->sgc.Session\n", + "\n", + "\n", + "\n", + "\n", + "sgc.Institution\n", + "\n", + "\n", + "sgc.Institution\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.Institution->sgc.Session\n", + "\n", + "\n", + "\n", + "\n", + "sgc.IntervalList->0\n", + "\n", + "\n", + "\n", + "\n", + "sgc.IntervalList->sgc.TaskEpoch\n", + "\n", + "\n", + "\n", + "\n", + "sgc.IntervalList->sgc.SensorData\n", + "\n", + "\n", + "\n", + "\n", + "sgc.IntervalList->sgc.IntervalPositionInfoSelection\n", + "\n", + "\n", + "\n", + "\n", + "sgc.IntervalList->sgc.Raw\n", + "\n", + "\n", + "\n", + "\n", + "sgc.IntervalList->sgc.LFP\n", + "\n", + "\n", + "\n", + "\n", + "sgc.IntervalList->sgc.LFPBand\n", + "\n", + "\n", + "\n", + "\n", + "sgc.IntervalList->sgc.DIOEvents\n", + "\n", + "\n", + "\n", + "\n", + "sgc.IntervalList->sgc.PositionSource\n", + "\n", + "\n", + "\n", + "\n", + "sgc.LFPSelection.LFPElectrode\n", + "\n", + "\n", + "sgc.LFPSelection.LFPElectrode\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.LFPSelection->sgc.LFPSelection.LFPElectrode\n", + "\n", + "\n", + "\n", + "\n", + "sgc.LFPSelection->sgc.LFP\n", + "\n", + "\n", + "\n", + "\n", + "sgc.LFPBandSelection->sgc.LFPBand\n", + "\n", + "\n", + "\n", + "\n", + "sgc.LFP->sgc.LFPBandSelection\n", + "\n", + "\n", + "\n", + "\n", + "sgc.Electrode\n", + "\n", + "\n", + "sgc.Electrode\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.ElectrodeGroup->sgc.Electrode\n", + "\n", + "\n", + "\n", + "\n", + "sgc.Electrode->sgc.LFPSelection.LFPElectrode\n", + "\n", + "\n", + "\n", + "\n", + "sgc.RawPosition\n", + "\n", + "\n", + "sgc.RawPosition\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.PositionSource->sgc.RawPosition\n", + "\n", + "\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Draw tables that are two levels below and one level above Session\n", + "dj.Diagram(sgc.Session) - 1 + 2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "By adding diagrams together, of adding and subtracting levels, we can visualize\n", + "key parts of Spyglass.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Example data\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "After exploring the pipeline's structure, we'll now grab some example data.\n", + "Spyglass will assume that the data is a neural recording with relevant auxiliary\n", + "in NWB.\n", + "\n", + "We offer a few examples:\n", + "\n", + "- `minirec20230622.nwb`, .3 GB: minimal recording, on\n", + " [Box](https://ucsf.box.com/s/k3sgql6z475oia848q1rgms4zdh4rkjn)\n", + "- `montague20200802.nwb`, 8 GB: full recording, on\n", + " [DropBox](https://www.dropbox.com/scl/fo/4i5b1z4iapetzxfps0grf/h?dl=0&preview=montague20200802_tutorial_.nwb&rlkey=ctahes9v0r7bxes8yceh86gzg)\n", + "- For those in the UCSF network, these and many others on `/stelmo/nwb/raw`\n", + "\n", + "If you are connected to the Frank lab database, please rename any downloaded\n", + "files (e.g., `example20200101_yourname.nwb`) to avoid naming collisions, as the\n", + "file name acts as the primary key across key tables.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# Define the name of the file that you copied and renamed\n", + "nwb_file_name = \"minirec20230622.nwb\"\n", + "filename, file_extension = os.path.splitext(nwb_file_name)\n", + "# By convention, Spyglass will add an underscore before the extension and copy\n", + "# the file, removing raw data.\n", + "nwb_copy_file_name = filename + \"_\" + file_extension" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'minirec20230622.nwb'" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "nwb_file_name" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Basic Inserts: Lab Team\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's start small by inserting personnel information.\n", + "\n", + "The `LabMember` table lists all lab members, with an additional part table for\n", + "`LabMemberInfo`. This holds Google account and DataJoint username info for each\n", + "member, for authentication purposes.\n", + "\n", + "We can insert lab member information using the NWB file `experimenter` field\n", + "as follows...\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "# take a look at the lab members\n", + "sgc.LabMember.insert_from_nwbfile(nwb_file_name)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can [insert](https://datajoint.com/docs/core/datajoint-python/0.14/manipulation/insert/)\n", + "into `LabMemberInfo` directly with a list of lists that reflect the order of\n", + "the fields present in the table. See\n", + "[this notebook](https://github.com/datajoint/datajoint-tutorials/blob/main/00-Getting_Started/01-DataJoint%20Basics%20-%20Interactive.ipynb)\n", + "for examples of inserting with `dicts`.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " \n", + " \n", + " Information about lab member in the context of Frank lab network\n", + "
\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
\n", + "

lab_member_name

\n", + " \n", + "
\n", + "

google_user_name

\n", + " used for permission to curate\n", + "
\n", + "

datajoint_user_name

\n", + " used for permission to delete entries\n", + "
Alison Comriecomrie.alison@gmail.comalison
Firstname Lastnameexample1@gmail.comexample1
Firstname2 Lastname2example2@gmail.comexample2
\n", + " \n", + "

Total: 3

\n", + " " + ], + "text/plain": [ + "*lab_member_na google_user_na datajoint_user\n", + "+------------+ +------------+ +------------+\n", + "Alison Comrie comrie.alison@ alison \n", + "Firstname Last example1@gmail example1 \n", + "Firstname2 Las example2@gmail example2 \n", + " (Total: 3)" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sgc.LabMember.LabMemberInfo.insert(\n", + " [ # Full name, Google email address, DataJont username\n", + " [\"Firstname Lastname\", \"example1@gmail.com\", \"example1\"],\n", + " [\"Firstname2 Lastname2\", \"example2@gmail.com\", \"example2\"],\n", + " ],\n", + " skip_duplicates=True,\n", + ")\n", + "sgc.LabMember.LabMemberInfo()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A `LabTeam` is a set of lab members who own a set of NWB files and the\n", + "associated information in the database. This is often a subgroup that\n", + "collaborates on the same projects. Data is associated with a given team,\n", + "granting members analysis (e.g., curation) and deletion (coming soon)\n", + "privelages.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "sgc.LabTeam().create_new_team(\n", + " team_name=\"My Team\", # Should be unique\n", + " team_members=[\"Firstname Lastname\", \"Firstname2 Lastname2\"],\n", + " team_description=\"test\", # Optional\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "By default, each member is part of their own team. We can see all teams and\n", + "members by looking at the\n", + "[part table](https://datajoint.com/docs/core/datajoint-python/0.14/design/tables/master-part/)\n", + "`LabTeam.LabTeamMember`.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
\n", + "

team_name

\n", + " \n", + "
\n", + "

lab_member_name

\n", + " \n", + "
BeansAlison Comrie
Firstname LastnameFirstname Lastname
My TeamFirstname Lastname
Firstname2 Lastname2Firstname2 Lastname2
My TeamFirstname2 Lastname2
\n", + " \n", + "

Total: 5

\n", + " " + ], + "text/plain": [ + "*team_name *lab_member_na\n", + "+------------+ +------------+\n", + "Beans Alison Comrie \n", + "Firstname Last Firstname Last\n", + "My Team Firstname Last\n", + "Firstname2 Las Firstname2 Las\n", + "My Team Firstname2 Las\n", + " (Total: 5)" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sgc.LabTeam.LabTeamMember()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Inserting from NWB\n", + "\n", + "`spyglass.data_import.insert_sessions` helps take the many fields of data\n", + "present in an NWB file and insert them into various tables across Spyglass. If\n", + "the NWB file is properly composed, this includes...\n", + "\n", + "- the experimenter (replicating part of the process above)\n", + "- animal behavior (e.g. video recording of position)\n", + "- neural activity (extracellular recording of multiple brain areas)\n", + "- etc.\n", + "\n", + "_Note:_ this may take a while because it makes a copy of the NWB file.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Creating a copy of NWB file minirec20230622.nwb with link to raw ephys data: minirec20230622_.nwb\n", + "Populate Session...\n", + "No config found at file path /home/cb/wrk/zOther/data/raw/minirec20230622_spyglass_config.yaml\n", + "Institution...\n", + "Lab...\n", + "LabMember...\n", + "Subject...\n", + "Populate DataAcquisitionDevice...\n", + "Inserted or referenced data acquisition device(s): dict_keys(['dataacq_device0'])\n", + "\n", + "Populate CameraDevice...\n", + "Inserted camera devices ['test camera 1']\n", + "\n", + "Populate Probe...\n", + "Probe ID '128c-4s6mm6cm-15um-26um-sl' already exists in the database. Spyglass will use that and not create a new Probe, Shanks, or Electrodes.\n", + "Inserted probes {'128c-4s6mm6cm-15um-26um-sl'}\n", + "\n", + "Skipping Apparatus for now...\n", + "IntervalList...\n", + "LabMember with name lastname, firstname does not exist. Cannot link Session with LabMember in Session.Experimenter.\n", + "LabMember with name lastname2, firstname2 does not exist. Cannot link Session with LabMember in Session.Experimenter.\n", + "Populate ElectrodeGroup...\n", + "Populate Electrode...\n", + "No config found at file path /home/cb/wrk/zOther/data/raw/minirec20230622_spyglass_config.yaml\n", + "Populate Raw...\n", + "Estimating sampling rate...\n", + "Estimated sampling rate: 30000.0\n", + "Importing raw data: Sampling rate:\t30000.0 Hz\n", + "Number of valid intervals:\t2\n", + "Populate SampleCount...\n", + "Populate DIOEvents...\n", + "Populate TaskEpochs\n", + "Populate StateScriptFile\n", + "Populate VideoFile\n", + "No video found corresponding to epoch 01_s1\n", + "No video found corresponding to epoch 02_s2\n", + "RawPosition...\n", + "Processing raw position data. Estimated sampling rate: 30.0 Hz\n", + "Processing raw position data. Estimated sampling rate: 30.0 Hz\n", + "Processing raw position data. Estimated sampling rate: 30.0 Hz\n", + "Processing raw position data. Estimated sampling rate: 30.0 Hz\n" + ] + } + ], + "source": [ + "sgi.insert_sessions(nwb_file_name)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "## Inspecting the data\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To look at data, we can\n", + "[query](https://datajoint.com/docs/core/datajoint-python/0.14/query/principles/)\n", + "a table with `Table()` syntax.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + " \n", + " \n", + "
\n", + "

lab_name

\n", + " \n", + "
Loren Frank Lab
\n", + " \n", + "

Total: 1

\n", + " " + ], + "text/plain": [ + "*lab_name \n", + "+------------+\n", + "Loren Frank La\n", + " (Total: 1)" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sgc.Lab()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `Session` table has considerably more fields\n" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['nwb_file_name',\n", + " 'subject_id',\n", + " 'institution_name',\n", + " 'lab_name',\n", + " 'session_id',\n", + " 'session_description',\n", + " 'session_start_time',\n", + " 'timestamps_reference_time',\n", + " 'experiment_description']" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sgc.Session.heading.names" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "But a short primary key\n" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['nwb_file_name']" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sgc.Session.heading.primary_key" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The primary key is shown in bold in the html\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " \n", + " \n", + " Table for holding experimental sessions.\n", + "
\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
\n", + "

nwb_file_name

\n", + " name of the NWB file\n", + "
\n", + "

subject_id

\n", + " \n", + "
\n", + "

institution_name

\n", + " \n", + "
\n", + "

lab_name

\n", + " \n", + "
\n", + "

session_id

\n", + " \n", + "
\n", + "

session_description

\n", + " \n", + "
\n", + "

session_start_time

\n", + " \n", + "
\n", + "

timestamps_reference_time

\n", + " \n", + "
\n", + "

experiment_description

\n", + " \n", + "
minirec20230622_.nwb54321UCSFLoren Frank Lab12345test yaml insertion2023-06-22 15:59:581970-01-01 00:00:00Test Conversion
\n", + " \n", + "

Total: 1

\n", + " " + ], + "text/plain": [ + "*nwb_file_name subject_id institution_na lab_name session_id session_descri session_start_ timestamps_ref experiment_des\n", + "+------------+ +------------+ +------------+ +------------+ +------------+ +------------+ +------------+ +------------+ +------------+\n", + "minirec2023062 54321 UCSF Loren Frank La 12345 test yaml inse 2023-06-22 15: 1970-01-01 00: Test Conversio\n", + " (Total: 1)" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sgc.Session()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Text only interfaces designate the primary key fields with `*`\n" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "*nwb_file_name subject_id institution_na lab_name session_id session_descri session_start_ timestamps_ref experiment_des\n", + "+------------+ +------------+ +------------+ +------------+ +------------+ +------------+ +------------+ +------------+ +------------+\n", + "minirec2023062 54321 UCSF Loren Frank La 12345 test yaml inse 2023-06-22 15: 1970-01-01 00: Test Conversio\n", + " (Total: 1)\n", + "\n" + ] + } + ], + "source": [ + "print(sgc.Session())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To see a the\n", + "[table definition](https://datajoint.com/docs/core/datajoint-python/0.14/design/tables/declare/),\n", + "including\n", + "[data types](https://datajoint.com/docs/core/datajoint-python/0.14/design/tables/attributes/),\n", + "use `describe`.\n", + "\n", + "- `---` separates the primary key\n", + "- `:` are used to separate field name from data type\n", + "- `#` can be used to add comments to a field\n" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "('# Table for holding experimental sessions.\\n'\n", + " '-> sgc.Nwbfile\\n'\n", + " '---\\n'\n", + " '-> [nullable] sgc.Subject\\n'\n", + " '-> [nullable] sgc.Institution\\n'\n", + " '-> [nullable] sgc.Lab\\n'\n", + " 'session_id=null : varchar(200) \\n'\n", + " 'session_description : varchar(2000) \\n'\n", + " 'session_start_time : datetime \\n'\n", + " 'timestamps_reference_time : datetime \\n'\n", + " 'experiment_description=null : varchar(2000) \\n')\n" + ] + } + ], + "source": [ + "from pprint import pprint # adds line breaks\n", + "\n", + "pprint(sgc.Session.describe())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To look at specific entries in a table, we can use the `&`\n", + "[operator](https://datajoint.com/docs/core/datajoint-python/0.14/query/operators/).\n", + "Below, we _restrict_ based on a `dict`, but you can also use a\n", + "[string](https://datajoint.com/docs/core/datajoint-python/0.14/query/restrict/#restriction-by-a-string).\n" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " \n", + " \n", + " Table for holding experimental sessions.\n", + "
\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
\n", + "

nwb_file_name

\n", + " name of the NWB file\n", + "
\n", + "

subject_id

\n", + " \n", + "
\n", + "

institution_name

\n", + " \n", + "
\n", + "

lab_name

\n", + " \n", + "
\n", + "

session_id

\n", + " \n", + "
\n", + "

session_description

\n", + " \n", + "
\n", + "

session_start_time

\n", + " \n", + "
\n", + "

timestamps_reference_time

\n", + " \n", + "
\n", + "

experiment_description

\n", + " \n", + "
minirec20230622_.nwb54321UCSFLoren Frank Lab12345test yaml insertion2023-06-22 15:59:581970-01-01 00:00:00Test Conversion
\n", + " \n", + "

Total: 1

\n", + " " + ], + "text/plain": [ + "*nwb_file_name subject_id institution_na lab_name session_id session_descri session_start_ timestamps_ref experiment_des\n", + "+------------+ +------------+ +------------+ +------------+ +------------+ +------------+ +------------+ +------------+ +------------+\n", + "minirec2023062 54321 UCSF Loren Frank La 12345 test yaml inse 2023-06-22 15: 1970-01-01 00: Test Conversio\n", + " (Total: 1)" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sgc.Session & {\"nwb_file_name\": nwb_copy_file_name}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`Raw` is connected to `Session` with a bold line, so it has the same primary key.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.Raw\n", + "\n", + "\n", + "sgc.Raw\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.Session\n", + "\n", + "\n", + "sgc.Session\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.Session->sgc.Raw\n", + "\n", + "\n", + "\n", + "\n", + "sgc.IntervalList\n", + "\n", + "\n", + "sgc.IntervalList\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sgc.Session->sgc.IntervalList\n", + "\n", + "\n", + "\n", + "\n", + "sgc.IntervalList->sgc.Raw\n", + "\n", + "\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dj.Diagram(sgc.Session) + dj.Diagram(sgc.Raw)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " \n", + " \n", + " Raw voltage timeseries data, ElectricalSeries in NWB.\n", + "
\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
\n", + "

nwb_file_name

\n", + " name of the NWB file\n", + "
\n", + "

interval_list_name

\n", + " descriptive name of this interval list\n", + "
\n", + "

raw_object_id

\n", + " the NWB object ID for loading this object from the file\n", + "
\n", + "

sampling_rate

\n", + " Sampling rate calculated from data, in Hz\n", + "
\n", + "

comments

\n", + " \n", + "
\n", + "

description

\n", + " \n", + "
minirec20230622_.nwbraw data valid times4e756642-9203-4f00-b9d0-0e9747c1449330000.0No commentRecording of extracellular voltage
\n", + " \n", + "

Total: 1

\n", + " " + ], + "text/plain": [ + "*nwb_file_name interval_list_ raw_object_id sampling_rate comments description \n", + "+------------+ +------------+ +------------+ +------------+ +------------+ +------------+\n", + "minirec2023062 raw data valid 4e756642-9203- 30000.0 No comment Recording of e\n", + " (Total: 1)" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sgc.Raw & {\"nwb_file_name\": nwb_copy_file_name}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`IntervalList` is connected to `Session` with a solid line because it has\n", + "additional primary key attributes. Here, you need to know both `nwb_file_name`\n", + "and `interval_list_name` to uniquely identify an entry.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "('# Time intervals used for analysis\\n'\n", + " '-> sgc.Session\\n'\n", + " 'interval_list_name : varchar(200) # descriptive name of this interval list\\n'\n", + " '---\\n'\n", + " 'valid_times: longblob # numpy array with start and end times for each '\n", + " 'interval\\n')\n" + ] + } + ], + "source": [ + "# join/split condenses long spaces before field comments\n", + "pprint(\"\".join(sgc.IntervalList.describe().split(\" \")))" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " \n", + " \n", + " Time intervals used for analysis\n", + "
\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
\n", + "

nwb_file_name

\n", + " name of the NWB file\n", + "
\n", + "

interval_list_name

\n", + " descriptive name of this interval list\n", + "
\n", + "

valid_times

\n", + " numpy array with start and end times for each interval\n", + "
minirec20230622_.nwb01_s1=BLOB=
minirec20230622_.nwb02_s2=BLOB=
minirec20230622_.nwbpos 0 valid times=BLOB=
minirec20230622_.nwbpos 1 valid times=BLOB=
minirec20230622_.nwbpos 2 valid times=BLOB=
minirec20230622_.nwbpos 3 valid times=BLOB=
minirec20230622_.nwbraw data valid times=BLOB=
\n", + " \n", + "

Total: 7

\n", + " " + ], + "text/plain": [ + "*nwb_file_name *interval_list valid_time\n", + "+------------+ +------------+ +--------+\n", + "minirec2023062 01_s1 =BLOB= \n", + "minirec2023062 02_s2 =BLOB= \n", + "minirec2023062 pos 0 valid ti =BLOB= \n", + "minirec2023062 pos 1 valid ti =BLOB= \n", + "minirec2023062 pos 2 valid ti =BLOB= \n", + "minirec2023062 pos 3 valid ti =BLOB= \n", + "minirec2023062 raw data valid =BLOB= \n", + " (Total: 7)" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sgc.IntervalList & {\"nwb_file_name\": nwb_copy_file_name}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Raw [data types](https://datajoint.com/docs/core/datajoint-python/0.14/design/tables/attributes/) like `valid_times` are shown as `=BLOB=`. We can inspect\n", + "these with [`fetch`](https://datajoint.com/docs/core/datajoint-python/0.14/query/fetch/)\n", + "\n", + "_Note:_ like `insert`/`insert1`, `fetch` can be uses as `fetch1` to raise an\n", + "error when many (or no) etries are retrieved. To limit to one entry when there\n", + "may be many, use `query.fetch(limit=1)[0]`\n" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([], shape=(0, 2), dtype=float64)" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "(\n", + " sgc.IntervalList\n", + " & {\n", + " \"nwb_file_name\": nwb_copy_file_name,\n", + " \"interval_list_name\": \"pos 1 valid times\",\n", + " }\n", + ").fetch1(\"valid_times\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In DataJoint [operators](https://datajoint.com/docs/core/datajoint-python/0.14/query/restrict/#restriction-by-a-string),\n", + "`&` selects by a condition and `-` removes a condition.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array(['01_s1', '02_s2', 'pos 0 valid times', 'pos 3 valid times',\n", + " 'raw data valid times'], dtype=object)" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "(\n", + " (\n", + " (sgc.IntervalList & {\"nwb_file_name\": nwb_copy_file_name})\n", + " - {\"interval_list_name\": \"pos 1 valid times\"}\n", + " )\n", + " - {\"interval_list_name\": \"pos 2 valid times\"}\n", + ").fetch(\"interval_list_name\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Deleting data\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Another neat feature of DataJoint is that it automatically maintains\n", + "[data integrity](https://datajoint.com/docs/core/datajoint-python/0.14/design/integrity/)\n", + "with _cascading deletes_. For example, if we delete our `Session` entry, all\n", + "associated downstream entries are also deleted (e.g. `Raw`, `IntervalList`).\n" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " \n", + " \n", + " Table for holding experimental sessions.\n", + "
\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
\n", + "

nwb_file_name

\n", + " name of the NWB file\n", + "
\n", + "

subject_id

\n", + " \n", + "
\n", + "

institution_name

\n", + " \n", + "
\n", + "

lab_name

\n", + " \n", + "
\n", + "

session_id

\n", + " \n", + "
\n", + "

session_description

\n", + " \n", + "
\n", + "

session_start_time

\n", + " \n", + "
\n", + "

timestamps_reference_time

\n", + " \n", + "
\n", + "

experiment_description

\n", + " \n", + "
minirec20230622_.nwb54321UCSFLoren Frank Lab12345test yaml insertion2023-06-22 15:59:581970-01-01 00:00:00Test Conversion
\n", + " \n", + "

Total: 1

\n", + " " + ], + "text/plain": [ + "*nwb_file_name subject_id institution_na lab_name session_id session_descri session_start_ timestamps_ref experiment_des\n", + "+------------+ +------------+ +------------+ +------------+ +------------+ +------------+ +------------+ +------------+ +------------+\n", + "minirec2023062 54321 UCSF Loren Frank La 12345 test yaml inse 2023-06-22 15: 1970-01-01 00: Test Conversio\n", + " (Total: 1)" + ] + }, + "execution_count": 48, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "session_entry = sgc.Session & {\"nwb_file_name\": nwb_copy_file_name}\n", + "session_entry" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "By default, DataJoint is cautious about deletes and will prompt before deleting.\n", + "To delete, respond `yes` in the prompt.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[2023-07-18 18:51:35,382][INFO]: Deleting 4 rows from `common_behav`.`_raw_position`\n", + "INFO:datajoint:Deleting 4 rows from `common_behav`.`_raw_position`\n", + "[2023-07-18 18:51:35,388][INFO]: Deleting 4 rows from `common_behav`.`position_source`\n", + "INFO:datajoint:Deleting 4 rows from `common_behav`.`position_source`\n", + "[2023-07-18 18:51:35,393][INFO]: Deleting 7 rows from `common_dio`.`_d_i_o_events`\n", + "INFO:datajoint:Deleting 7 rows from `common_dio`.`_d_i_o_events`\n", + "[2023-07-18 18:51:35,406][INFO]: Deleting 128 rows from `common_ephys`.`_electrode`\n", + "INFO:datajoint:Deleting 128 rows from `common_ephys`.`_electrode`\n", + "[2023-07-18 18:51:35,408][INFO]: Deleting 1 rows from `common_ephys`.`_electrode_group`\n", + "INFO:datajoint:Deleting 1 rows from `common_ephys`.`_electrode_group`\n", + "[2023-07-18 18:51:35,412][INFO]: Deleting 1 rows from `common_ephys`.`_raw`\n", + "INFO:datajoint:Deleting 1 rows from `common_ephys`.`_raw`\n", + "[2023-07-18 18:51:35,415][INFO]: Deleting 1 rows from `common_ephys`.`_sample_count`\n", + "INFO:datajoint:Deleting 1 rows from `common_ephys`.`_sample_count`\n", + "[2023-07-18 18:51:35,426][INFO]: Deleting 2 rows from `common_task`.`_task_epoch`\n", + "INFO:datajoint:Deleting 2 rows from `common_task`.`_task_epoch`\n", + "[2023-07-18 18:51:35,434][INFO]: Deleting 7 rows from `common_interval`.`interval_list`\n", + "INFO:datajoint:Deleting 7 rows from `common_interval`.`interval_list`\n", + "[2023-07-18 18:51:35,441][INFO]: Deleting 1 rows from `common_session`.`_session__data_acquisition_device`\n", + "INFO:datajoint:Deleting 1 rows from `common_session`.`_session__data_acquisition_device`\n", + "[2023-07-18 18:51:35,442][INFO]: Deleting 1 rows from `common_session`.`_session`\n", + "INFO:datajoint:Deleting 1 rows from `common_session`.`_session`\n", + "[2023-07-18 18:51:36,986][INFO]: Deletes committed.\n", + "INFO:datajoint:Deletes committed.\n" + ] + }, + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "session_entry.delete()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can check that delete worked, both for `Session` and `IntervalList`\n" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " \n", + " \n", + " Table for holding experimental sessions.\n", + "
\n", + " \n", + " \n", + " \n", + "
\n", + "

nwb_file_name

\n", + " name of the NWB file\n", + "
\n", + "

subject_id

\n", + " \n", + "
\n", + "

institution_name

\n", + " \n", + "
\n", + "

lab_name

\n", + " \n", + "
\n", + "

session_id

\n", + " \n", + "
\n", + "

session_description

\n", + " \n", + "
\n", + "

session_start_time

\n", + " \n", + "
\n", + "

timestamps_reference_time

\n", + " \n", + "
\n", + "

experiment_description

\n", + " \n", + "
\n", + " \n", + "

Total: 0

\n", + " " + ], + "text/plain": [ + "*nwb_file_name subject_id institution_na lab_name session_id session_descri session_start_ timestamps_ref experiment_des\n", + "+------------+ +------------+ +------------+ +----------+ +------------+ +------------+ +------------+ +------------+ +------------+\n", + "\n", + " (Total: 0)" + ] + }, + "execution_count": 51, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sgc.Session & {\"nwb_file_name\": nwb_copy_file_name}" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " \n", + " \n", + " Time intervals used for analysis\n", + "
\n", + " \n", + " \n", + " \n", + "
\n", + "

nwb_file_name

\n", + " name of the NWB file\n", + "
\n", + "

interval_list_name

\n", + " descriptive name of this interval list\n", + "
\n", + "

valid_times

\n", + " numpy array with start and end times for each interval\n", + "
\n", + " \n", + "

Total: 0

\n", + " " + ], + "text/plain": [ + "*nwb_file_name *interval_list valid_time\n", + "+------------+ +------------+ +--------+\n", + "\n", + " (Total: 0)" + ] + }, + "execution_count": 52, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sgc.IntervalList & {\"nwb_file_name\": nwb_copy_file_name}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`delete` is useful for re-running something. Editing entries is possible, but\n", + "discouraged because it can lead to\n", + "[integrity](https://datajoint.com/docs/core/datajoint-python/0.14/design/integrity/)\n", + "issues. Instead, re-enter and let the automation handle the rest.\n", + "\n", + "Spyglass falls short, however, in that deleting from `Session` doesn't also\n", + "delete the associated entry in `Nwbfile`, which has to be removed separately\n", + "(for now). This table offers a `cleanup` method to remove the added files (with\n", + "the `delete_files` argument as `True`).\n", + "\n", + "_Note:_ this also applies to deleting files from `AnalysisNwbfile` table.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[2023-07-18 19:01:15,343][INFO]: Deleting 1 rows from `common_nwbfile`.`nwbfile`\n", + "INFO:datajoint:Deleting 1 rows from `common_nwbfile`.`nwbfile`\n", + "[2023-07-18 19:01:17,130][INFO]: Deletes committed.\n", + "INFO:datajoint:Deletes committed.\n" + ] + }, + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 53, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Let's delete the entry\n", + "(sgc.Nwbfile & {\"nwb_file_name\": nwb_copy_file_name}).delete()" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "minirec20230622.nwb\n", + "minirec20230622_.nwb\n", + "montague20200802_tutorial.nwb\n", + "montague20200802_tutorial_.nwb\n", + "montague20200802_tutorial__.nwb\n", + "sub-despereaux_ses-despereaux-08_behavior+ecephys_trim.nwb\n", + "sub-despereaux_ses-despereaux-08_behavior+ecephys_trim_.nwb\n", + "tonks20211103_.nwb\n" + ] + } + ], + "source": [ + "# Note that the file (ends with _.nwb) has not been deleted, even though the entry is\n", + "!ls $SPYGLASS_BASE_DIR/raw" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100%|██████████| 1/1 [00:00<00:00, 304.24it/s]\n" + ] + } + ], + "source": [ + "# We clean it up\n", + "sgc.Nwbfile().cleanup(delete_files=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "minirec20230622.nwb\n", + "montague20200802_tutorial.nwb\n", + "montague20200802_tutorial_.nwb\n", + "montague20200802_tutorial__.nwb\n", + "sub-despereaux_ses-despereaux-08_behavior+ecephys_trim.nwb\n", + "sub-despereaux_ses-despereaux-08_behavior+ecephys_trim_.nwb\n", + "tonks20211103_.nwb\n" + ] + } + ], + "source": [ + "# Now the file is gone as well\n", + "!ls $SPYGLASS_BASE_DIR/raw" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the [next notebook](./02_Spike_Sorting.ipynb), we'll dive into the Spike\n", + "Sorting pipeline.\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "spy", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.16" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/notebooks/01_spikesorting.ipynb b/notebooks/01_spikesorting.ipynb deleted file mode 100644 index 4dd320282..000000000 --- a/notebooks/01_spikesorting.ipynb +++ /dev/null @@ -1,773 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Spyglass Spike Sorting Tutorial\n", - "\n", - "**Note: make a copy of this notebook and run the copy to avoid git conflicts in the future**\n", - "\n", - "This is the second in a multi-part tutorial on the Spyglass pipeline used in Loren Frank's lab, UCSF. It demonstrates how to run spike sorting and curate units within the pipeline.\n", - "\n", - "If you have not done [tutorial 0](0_intro.ipynb) yet, make sure to do so before proceeding. It is also recommended that you complete the [datajoint tutorials](https://tutorials.datajoint.io/) before starting this. \n", - "\n", - "**Note 2: Make sure you are running this within the spyglass Conda environment)**" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Spike Sorting Overview - With associated tables\n", - "#### [Extracting the recording from the NWB file](#section1)
\n", - "1. Specifying your [NWB](#Specifying-your-NWB-filename) file.
\n", - "2. Specifying which electrodes involved in the recording to sort data from. - [`SortGroup`](#SortGroup)
\n", - "3. Specifying the time segment of the recording we want to sort. - [`IntervalList`](#IntervalList), [`SortInterval`](#SortInterval)
\n", - "4. Specifying the parameters to use for filtering the recording. - [`SpikeSortingPreprocessingParameters`](#SpikeSortingPreprocessingParameters)
\n", - "5. Combining these parameters. - [`SpikeSortingRecordingSelection`](#SpikeSortingRecordingSelection)
\n", - "6. Extracting the recording. - [`SpikeSortingRecording`](#SpikeSortingRecording)
\n", - "7. Specifying the parameters to apply for artifact detection/removal. -[`ArtifactDetectionParameters`](#ArtifactDetectionParameters)
\n", - " \n", - "#### [Spike sorting the extracted recording](#section2)
\n", - "1. Specify the spike sorter and parameters to use. - [`SpikeSorterParameters`](#SpikeSorterParameters)
\n", - "2. Combine these parameters. - [`SpikeSortingSelection`](#SpikeSortingSelection)
\n", - "3. Spike sort the extracted recording according to chose parameter set. - [`SpikeSorting`](#SpikeSorting)
\n", - "\n", - "\n", - "" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's start by importing tables from spyglass along with some other useful packages" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "import os\n", - "import numpy as np\n", - "import datajoint as dj\n", - "import spyglass as sg\n", - "import spyglass.common as sgc\n", - "import spyglass.spikesorting as sgss\n", - "\n", - "# ignore datajoint+jupyter async warnings\n", - "import warnings\n", - "\n", - "warnings.simplefilter(\"ignore\", category=DeprecationWarning)\n", - "warnings.simplefilter(\"ignore\", category=ResourceWarning)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's make sure that you're a part of the LorenLab `LabTeam`, so you'll have the right permissions for this tutorial.
Replace `your_name`, `your_email`, and `datajoint_username`, with your information." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "your_name = \"FirstName LastName\"\n", - "your_email = \"gmail@gmail.com\"\n", - "datajoint_username = \"user\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "lorenlab_team_members = (\n", - " (sgc.LabTeam().LabTeamMember() & {\"team_name\": \"LorenLab\"})\n", - " .fetch(\"lab_member_name\")\n", - " .tolist()\n", - ")\n", - "sgc.LabMember.insert_from_name(your_name)\n", - "sgc.LabMember.LabMemberInfo.insert1(\n", - " [your_name, your_email, datajoint_username], skip_duplicates=True\n", - ")\n", - "sgc.LabTeam.LabTeamMember.insert1(\n", - " {\"team_name\": \"LorenLab\", \"lab_member_name\": your_name},\n", - " skip_duplicates=True,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now try and use the `fetch` command and the example above to complete the code below and query the `LabTeam` table to double-check that you are a part of the `LorenLab` team." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "if your_name in (sgc.LabTeam._____() & {___: ____}).fetch(______).tolist():\n", - " print(\"You made it in!\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Specifying your NWB filename\n", - "NWB filenames take the form of an animal name plus the date of the recording.
For this tutorial, we will use the nwb file `'montague20200802_tutorial_.nwb'`. The animal name is `montague` and the date of the recording is `20200802`, the `tutorial` is unique to this setting :-).
We'll first re-insert the NWB file that you deleted at the end of `0_intro`. This file may already be in the table, in which case there will be a warning, that's ok!
**Note**: If you're not on the Frank Lab server, this file will be accessible as `montague20200802.nwb` on DANDI through this URL: **insert-url**" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import spyglass.data_import as sdi\n", - "\n", - "sdi.insert_sessions(\"montague20200802_tutorial.nwb\")\n", - "nwb_file_name = \"montague20200802_tutorial_.nwb\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### **NOTE**: This is a common file for this tutorial, table entries may change during use if others are also working through." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Extracting the recording from the NWB file" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### `SortGroup`\n", - "For each NWB file there will be multiple electrodes available to sort spikes from.
We commonly sort over multiple electrodes at a time, also referred to as a `SortGroup`.
This is accomplished by grouping electrodes according to what tetrode or shank of a probe they were on.
**NOTE**: answer 'yes' when prompted" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# answer 'yes' when prompted\n", - "sgss.SortGroup().set_group_by_shank(nwb_file_name)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Each electrode will have an `electrode_id` and be associated with an `electrode_group_name`, which will correspond with a `sort_group_id`. In this case, the data was recorded from a 32 tetrode (128 channel) drive, and thus results in 128 unique `electrode_id`, 32 unique `electrode_group_name`, and 32 unique `sort_group_id`. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sgss.SortGroup.SortGroupElectrode & {\"nwb_file_name\": nwb_file_name}" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "tags": [] - }, - "source": [ - "### `IntervalList`\n", - "Next, we make a decision about the time interval for our spike sorting. Let's re-examine `IntervalList`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "sgc.IntervalList & {\"nwb_file_name\": nwb_file_name}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "For our example, let's choose to start with the first run interval (`02_r1`) as our sort interval. We first fetch `valid_times` for this interval." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "interval_list_name = \"02_r1\"\n", - "interval_list = (\n", - " sgc.IntervalList\n", - " & {\"nwb_file_name\": nwb_file_name, \"interval_list_name\": interval_list_name}\n", - ").fetch1(\"valid_times\")\n", - "print(\n", - " f\"IntervalList begins as a {np.round((interval_list[0][1] - interval_list[0][0]) / 60,0):g} min long epoch\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### `SortInterval`\n", - "For brevity's sake, we'll select only the first 180 seconds of that 90 minute epoch as our sort interval. To do so, we define our new sort interval as the start time of `interval_list` from the previous cell, plus 180 seconds." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sort_interval = interval_list[0]\n", - "sort_interval_name = interval_list_name + \"_first180\"\n", - "sort_interval = np.copy(interval_list[0])\n", - "sort_interval[1] = sort_interval[0] + 180" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can now add this `sort_interval` with the specified `sort_interval_name` `'02_r1_first180'` to the `SortInterval` table. The `SortInterval.insert()` function requires the arguments input as a dictionary with keys `nwb_file_name`, `sort_interval_name`, and `sort_interval`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sgss.SortInterval.insert1(\n", - " {\n", - " \"nwb_file_name\": nwb_file_name,\n", - " \"sort_interval_name\": sort_interval_name,\n", - " \"sort_interval\": sort_interval,\n", - " },\n", - " skip_duplicates=True,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now that we've inserted the entry into `SortInterval` you can see that entry by querying `SortInterval` using the `nwb_file_name` and `sort_interval_name`. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sgss.SortInterval & {\n", - " \"nwb_file_name\": nwb_file_name,\n", - " \"sort_interval_name\": sort_interval_name,\n", - "}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now using the `.fetch()` command, you can retrieve your user-defined sort interval from the `SortInterval` table.
A quick double-check will show that it is indeed a 180 second segment." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fetched_sort_interval = (\n", - " sgss.SortInterval\n", - " & {\"nwb_file_name\": nwb_file_name, \"sort_interval_name\": sort_interval_name}\n", - ").fetch1(\"sort_interval\")\n", - "print(\n", - " f\"The sort interval goes from {fetched_sort_interval[0]} to {fetched_sort_interval[1]}, \\\n", - "which is {(fetched_sort_interval[1] - fetched_sort_interval[0])} seconds. COOL!\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### `SpikeSortingPreprocessingParameters`\n", - "Let's first take a look at the `SpikeSortingPreprocessingParameters` table, which contains the parameters used to filter the recorded data in the spike band prior to spike sorting it." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sgss.SpikeSortingPreprocessingParameters()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's set the filtering parameters. Here we insert the default parameters, and then fetch the default parameter dictionary." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sgss.SpikeSortingPreprocessingParameters().insert_default()\n", - "preproc_params = (\n", - " sgss.SpikeSortingPreprocessingParameters()\n", - " & {\"preproc_params_name\": \"default\"}\n", - ").fetch1(\"preproc_params\")\n", - "print(preproc_params)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Lets first adjust the `frequency_min` parameter to 600, which is the preference for hippocampal data. Now we can insert that into `SpikeSortingPreprocessingParameters` as a new set of filtering parameters for hippocampal data, named `'franklab_default_hippocampus'`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "preproc_params[\"frequency_min\"] = 600\n", - "sgss.SpikeSortingPreprocessingParameters().insert1(\n", - " {\n", - " \"preproc_params_name\": \"franklab_default_hippocampus\",\n", - " \"preproc_params\": preproc_params,\n", - " },\n", - " skip_duplicates=True,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Setting a key\n", - "Now we set up the parameters of the recording we are interested in, and make a dictionary to hold all these values, which will make querying and inserting into tables all the easier moving forward.
We'll assign this to `ssr_key` as these values are relvant to the recording we'll use to spike sort, also referred to as the spike sorting recording **(ssr)** :-)
The `sort_group_id` refers back to the `SortGroup` table we populated at the beginning of the tutorial. We'll use `sort_group_id` 10 here.
Our `sort_interval_name` is the same as above: `'02_r1_first600'`.
Our `preproc_params_name` is the same ones we just inserted into `SpikeSortingPreprocessingParameters`.
The `interval_list` was also set above as `'02_r1'`. Unlike `sort_interval_name`, which reflects our subsection of the recording, we keep `interval_list` unchanged from the original epoch name." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "key = dict()\n", - "key[\"nwb_file_name\"] = nwb_file_name\n", - "key[\"sort_group_id\"] = 10\n", - "key[\"sort_interval_name\"] = \"02_r1_first180\"\n", - "key[\"preproc_params_name\"] = \"franklab_default_hippocampus\"\n", - "key[\"interval_list_name\"] = \"02_r1\"\n", - "key[\"team_name\"] = \"LorenLab\"\n", - "\n", - "ssr_key = key" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### `SpikeSortingRecordingSelection`\n", - "We now insert all of these parameters into the `SpikeSortingRecordingSelection` table, which we will use to specify what time/tetrode/etc of the recording we want to extract." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sgss.SpikeSortingRecordingSelection.insert1(ssr_key, skip_duplicates=True)\n", - "sgss.SpikeSortingRecordingSelection() & ssr_key" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### `SpikeSortingRecording`\n", - "And now we're ready to extract the recording! We use the `.proj()` command to pass along all of the primary keys from the `SpikeSortingRecordingSelection` table to the `SpikeSortingRecording` table, so it knows exactly what to extract.
**Note**: This step might take a bit with longer duration sort intervals" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sgss.SpikeSortingRecording.populate(\n", - " [(sgss.SpikeSortingRecordingSelection & ssr_key).proj()]\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Now we can see our recording in the table. _E x c i t i n g !_" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sgss.SpikeSortingRecording() & ssr_key" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### `ArtifactDetectionParameters`\n", - "Similarly, we set up the `ArtifactDetectionParameters`, which can allow us to remove artifacts from the data.
Specifically, we want to target artifact signal that is within the frequency band of our filter (600Hz-6KHz), and thus will not get removed by filtering.
For the moment we just set up a `\"none\"` parameter set, which will do nothing when used." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sgss.ArtifactDetectionParameters().insert_default()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "artifact_key = (sgss.SpikeSortingRecording() & ssr_key).fetch1(\"KEY\")\n", - "artifact_key[\"artifact_params_name\"] = \"none\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we can pair your choice of artifact detection parameters (as entered into `ArtifactParameters`) with the recording you just extracted through population of `SpikeSortingRecording` and insert into `ArtifactDetectionSelection`. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sgss.ArtifactDetectionSelection().insert1(artifact_key)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sgss.ArtifactDetectionSelection() & artifact_key" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now that we've inserted into `ArtifactDetectionSelection` we're ready to populate the `ArtifactDetection` table, which will find periods where there are artifacts (as specified by your parameters) in the recording." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sgss.ArtifactDetection.populate(artifact_key)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Populating `ArtifactDetection` also inserts an entry into `ArtifactRemovedIntervalList`, which stores the interval without detected artifacts. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sgss.ArtifactRemovedIntervalList() & artifact_key" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Spike sorting the extracted recording" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### `SpikeSorterParameters`\n", - "For our example, we will be using `mountainsort4`. There are already some default parameters in the `SpikeSorterParameters` table we'll `fetch`. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "sgss.SpikeSorterParameters().insert_default()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Let's look at the default params\n", - "sorter_name = \"mountainsort4\"\n", - "ms4_default_params = (\n", - " sgss.SpikeSorterParameters\n", - " & {\"sorter\": sorter_name, \"sorter_params_name\": \"default\"}\n", - ").fetch1()\n", - "print(ms4_default_params)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we can change these default parameters to line up more closely with our preferences. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "param_dict = ms4_default_params[\"sorter_params\"]\n", - "# Detect downward going spikes (1 is for upward, 0 is for both up and down)\n", - "param_dict[\"detect_sign\"] = -1\n", - "# We will sort electrodes together that are within 100 microns of each other\n", - "param_dict[\"adjacency_radius\"] = 100\n", - "# Turn filter off since we will filter it prior to starting sort\n", - "param_dict[\"filter\"] = False\n", - "param_dict[\"freq_min\"] = 0\n", - "param_dict[\"freq_max\"] = 0\n", - "# Turn whiten off since we will whiten it prior to starting sort\n", - "param_dict[\"whiten\"] = False\n", - "# set num_workers to be the same number as the number of electrodes\n", - "param_dict[\"num_workers\"] = 4\n", - "param_dict[\"verbose\"] = True\n", - "# set clip size as number of samples for 1.33 millisecond based on the sampling rate\n", - "param_dict[\"clip_size\"] = np.int(\n", - " 1.33e-3\n", - " * (sgc.Raw & {\"nwb_file_name\": nwb_file_name}).fetch1(\"sampling_rate\")\n", - ")\n", - "param_dict" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's go ahead and insert a new `sorter_params_name` and `sorter_params` dict into the `SpikeSorterParameters` table named `franklab_hippocampus_tutorial`. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "parameter_set_name = \"franklab_hippocampus_tutorial\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we insert our parameters for use by the spike sorter into `SpikeSorterParameters` and double-check that it made it in to the table. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "sgss.SpikeSorterParameters.insert1(\n", - " {\n", - " \"sorter\": sorter_name,\n", - " \"sorter_params_name\": parameter_set_name,\n", - " \"sorter_params\": param_dict,\n", - " },\n", - " skip_duplicates=True,\n", - ")\n", - "# Check that insert was successful\n", - "p = (\n", - " sgss.SpikeSorterParameters\n", - " & {\"sorter\": sorter_name, \"sorter_params_name\": parameter_set_name}\n", - ").fetch1()\n", - "p" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### `SpikeSortingSelection`\n", - "##### Gearing up to Spike Sort!\n", - "We now collect all the decisions we made up to here and put it into the `SpikeSortingSelection` table, which is specific to this recording and eventual sorting segment.
We'll add in a few parameters to our key and call it `ss_key`.
(**note**: the spike *sorter* parameters defined above are for the sorter, `mountainsort4` in this case.)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "ss_key = (sgss.ArtifactDetection & ssr_key).fetch1(\"KEY\")\n", - "ss_key.update((sgss.ArtifactRemovedIntervalList() & key).fetch1(\"KEY\"))\n", - "ss_key[\"sorter\"] = sorter_name\n", - "ss_key[\"sorter_params_name\"] = parameter_set_name\n", - "del ss_key[\"artifact_params_name\"]\n", - "sgss.SpikeSortingSelection.insert1(ss_key, skip_duplicates=True)\n", - "(sgss.SpikeSortingSelection & ss_key)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### `SpikeSorting`\n", - "Now we can run spike sorting. It's nothing more than populating a table (`SpikeSorting`) based on the entries of `SpikeSortingSelection`.
**Note**: This will take a little bit with longer data sets." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "sgss.SpikeSorting.populate([(sgss.SpikeSortingSelection & ss_key).proj()])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Check to make sure the table populated" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sgss.SpikeSorting() & ss_key" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Congratulations, you've spike sorted! See 2_curation for the next tutorial" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3.10.5 64-bit", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.5" - }, - "vscode": { - "interpreter": { - "hash": "8a94588eda9d64d9e9a351ab8144e55b1fabf5113b54e67dd26a8c27df0381b3" - } - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/notebooks/02_Spike_Sorting.ipynb b/notebooks/02_Spike_Sorting.ipynb new file mode 100644 index 000000000..5f42891a1 --- /dev/null +++ b/notebooks/02_Spike_Sorting.ipynb @@ -0,0 +1,2442 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Spike Sorting\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "_Developer Note:_ if you may make a PR in the future, be sure to copy this\n", + "notebook, and use the `gitignore` prefix `temp` to avoid future conflicts.\n", + "\n", + "This is one notebook in a multi-part series on Spyglass.\n", + "\n", + "- To set up your Spyglass environment and database, see\n", + " [the Setup notebook](./00_Setup.ipynb)\n", + "- For additional info on DataJoint syntax, including table definitions and\n", + " inserts, see\n", + " [the Insert Data notebook](./01_Insert_Data.ipynb)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### [Extract the recording](#section1)
\n", + "\n", + "1. Specifying your [NWB](#Specifying-your-NWB-filename) file.
\n", + "2. Specifying which electrodes involved in the recording to sort data from. - [`SortGroup`](#SortGroup)
\n", + "3. Specifying the time segment of the recording we want to sort. - [`IntervalList`](#IntervalList), [`SortInterval`](#SortInterval)
\n", + "4. Specifying the parameters to use for filtering the recording. - [`SpikeSortingPreprocessingParameters`](#SpikeSortingPreprocessingParameters)
\n", + "5. Combining these parameters. - [`SpikeSortingRecordingSelection`](#SpikeSortingRecordingSelection)
\n", + "6. Extracting the recording. - [`SpikeSortingRecording`](#SpikeSortingRecording)
\n", + "7. Specifying the parameters to apply for artifact detection/removal. -[`ArtifactDetectionParameters`](#ArtifactDetectionParameters)
\n", + "\n", + "### [Spike sorting the recording](#section2)
\n", + "\n", + "1. Specify the spike sorter and parameters to use. - [`SpikeSorterParameters`](#SpikeSorterParameters)
\n", + "2. Combine these parameters. - [`SpikeSortingSelection`](#SpikeSortingSelection)
\n", + "3. Spike sort the extracted recording according to chose parameter set. - [`SpikeSorting`](#SpikeSorting)
\n", + "\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Imports\n", + "\n", + "Let's start by importing tables from Spyglass and quieting warnings caused by\n", + "some dependencies.\n", + "\n", + "_Note:_ It the imports below throw a `FileNotFoundError`, make a cell with `!env | grep X` where X is part of the problematic directory. This will show the variable causing issues. Make another cell that sets this variable elsewhere with `%env VAR=\"/your/path/\"`\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "import os\n", + "import datajoint as dj\n", + "import numpy as np\n", + "\n", + "# change to the upper level folder to detect dj_local_conf.json\n", + "if os.path.basename(os.getcwd()) == \"notebooks\":\n", + " os.chdir(\"..\")\n", + "dj.config.load(\"dj_local_conf.json\") # load config for database connection info\n", + "\n", + "import spyglass.common as sgc\n", + "import spyglass.spikesorting as sgs\n", + "\n", + "# ignore datajoint+jupyter async warnings\n", + "import warnings\n", + "\n", + "warnings.simplefilter(\"ignore\", category=DeprecationWarning)\n", + "warnings.simplefilter(\"ignore\", category=ResourceWarning)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Fetch Exercise\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you haven't already done so, add yourself to `LabTeam`\n" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "name, email, dj_user = \"Firstname Lastname\", \"example@gmail.com\", \"user\"\n", + "sgc.LabMember.insert_from_name(name)\n", + "sgc.LabMember.LabMemberInfo.insert1(\n", + " [name, email, dj_user], skip_duplicates=True\n", + ")\n", + "sgc.LabTeam.LabTeamMember.insert1(\n", + " {\"team_name\": \"My Team\", \"lab_member_name\": name},\n", + " skip_duplicates=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can try `fetch` to confirm.\n", + "\n", + "_Exercise:_ Try to write a fer lines to generate a dictionary with team names as\n", + "keys and lists of members as values. It may be helpful to add more data with the\n", + "code above and use `fetch(as_dict=True)`.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "You made it in!\n" + ] + } + ], + "source": [ + "my_team_members = (\n", + " (sgc.LabTeam.LabTeamMember & {\"team_name\": \"My Team\"})\n", + " .fetch(\"lab_member_name\")\n", + " .tolist()\n", + ")\n", + "if name in my_team_members:\n", + " print(\"You made it in!\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "_Exercise_ code hidden here\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Adding an NWB file\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Import Data\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you haven't already, load an NWB file. For more details on downloading and\n", + "importing data, see [this notebook](./01_Insert_Data.ipynb).\n" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/cb/wrk/spyglass/src/spyglass/data_import/insert_sessions.py:41: UserWarning: Cannot insert data from minirec20230622.nwb: minirec20230622_.nwbis already in Nwbfile table.\n", + " warnings.warn(\n" + ] + } + ], + "source": [ + "import spyglass.data_import as sdi\n", + "\n", + "sdi.insert_sessions(\"minirec20230622.nwb\")\n", + "nwb_file_name = \"minirec20230622_.nwb\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Extracting the recording\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### `SortGroup`\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Each NWB file will have multiple electrodes we can use for spike sorting. We\n", + "commonly use multiple electrodes in a `SortGroup` selected by what tetrode or\n", + "shank of a probe they were on.\n", + "\n", + "_Note:_ This will delete any existing entries. Answer 'yes' when prompted.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[2023-07-21 13:56:24,232][INFO]: Deleting 128 rows from `spikesorting_recording`.`sort_group__sort_group_electrode`\n", + "[2023-07-21 13:56:24,234][INFO]: Deleting 4 rows from `spikesorting_recording`.`sort_group`\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[2023-07-21 13:56:27,358][INFO]: Deletes committed.\n" + ] + } + ], + "source": [ + "sgs.SortGroup().set_group_by_shank(nwb_file_name)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Each electrode has an `electrode_id` and is associated with an\n", + "`electrode_group_name`, which corresponds with a `sort_group_id`.\n", + "\n", + "For example, data recorded from a 32 tetrode (128 channel) drive results in 128\n", + "unique `electrode_id`. This could result in 32 unique `electrode_group_name` and\n", + "32 unique `sort_group_id`.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
\n", + "

nwb_file_name

\n", + " name of the NWB file\n", + "
\n", + "

sort_group_id

\n", + " identifier for a group of electrodes\n", + "
\n", + "

electrode_group_name

\n", + " electrode group name from NWBFile\n", + "
\n", + "

electrode_id

\n", + " the unique number for this electrode\n", + "
minirec20230622_.nwb000
minirec20230622_.nwb001
minirec20230622_.nwb002
minirec20230622_.nwb003
minirec20230622_.nwb004
minirec20230622_.nwb005
minirec20230622_.nwb006
minirec20230622_.nwb007
minirec20230622_.nwb008
minirec20230622_.nwb009
minirec20230622_.nwb0010
minirec20230622_.nwb0011
\n", + "

...

\n", + "

Total: 128

\n", + " " + ], + "text/plain": [ + "*nwb_file_name *sort_group_id *electrode_gro *electrode_id \n", + "+------------+ +------------+ +------------+ +------------+\n", + "minirec2023062 0 0 0 \n", + "minirec2023062 0 0 1 \n", + "minirec2023062 0 0 2 \n", + "minirec2023062 0 0 3 \n", + "minirec2023062 0 0 4 \n", + "minirec2023062 0 0 5 \n", + "minirec2023062 0 0 6 \n", + "minirec2023062 0 0 7 \n", + "minirec2023062 0 0 8 \n", + "minirec2023062 0 0 9 \n", + "minirec2023062 0 0 10 \n", + "minirec2023062 0 0 11 \n", + " ...\n", + " (Total: 128)" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sgs.SortGroup.SortGroupElectrode & {\"nwb_file_name\": nwb_file_name}" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "#### `IntervalList`\n", + "\n", + "Next, we make a decision about the time interval for our spike sorting using\n", + "`IntervalList`.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " \n", + " \n", + " Time intervals used for analysis\n", + "
\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
\n", + "

nwb_file_name

\n", + " name of the NWB file\n", + "
\n", + "

interval_list_name

\n", + " descriptive name of this interval list\n", + "
\n", + "

valid_times

\n", + " numpy array with start and end times for each interval\n", + "
minirec20230622_.nwb01_s1=BLOB=
minirec20230622_.nwb02_s2=BLOB=
minirec20230622_.nwbpos 0 valid times=BLOB=
minirec20230622_.nwbpos 1 valid times=BLOB=
minirec20230622_.nwbpos 2 valid times=BLOB=
minirec20230622_.nwbpos 3 valid times=BLOB=
minirec20230622_.nwbraw data valid times=BLOB=
\n", + " \n", + "

Total: 7

\n", + " " + ], + "text/plain": [ + "*nwb_file_name *interval_list valid_time\n", + "+------------+ +------------+ +--------+\n", + "minirec2023062 01_s1 =BLOB= \n", + "minirec2023062 02_s2 =BLOB= \n", + "minirec2023062 pos 0 valid ti =BLOB= \n", + "minirec2023062 pos 1 valid ti =BLOB= \n", + "minirec2023062 pos 2 valid ti =BLOB= \n", + "minirec2023062 pos 3 valid ti =BLOB= \n", + "minirec2023062 raw data valid =BLOB= \n", + " (Total: 7)" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sgc.IntervalList & {\"nwb_file_name\": nwb_file_name}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's start with the first run interval (`01_s1`) and fetch corresponding `valid_times`. For the `minirec` example, this is relatively short.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This interval list is 10 seconds long\n" + ] + } + ], + "source": [ + "interval_list_name = \"01_s1\"\n", + "interval_list = (\n", + " sgc.IntervalList\n", + " & {\"nwb_file_name\": nwb_file_name, \"interval_list_name\": interval_list_name}\n", + ").fetch1(\"valid_times\")[0]\n", + "\n", + "\n", + "def print_interval_duration(interval_list: np.ndarray):\n", + " duration = np.round((interval_list[1] - interval_list[0]))\n", + " print(f\"This interval list is {duration:g} seconds long\")\n", + "\n", + "\n", + "print_interval_duration(interval_list)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### `SortInterval`\n", + "\n", + "For longer recordings, Spyglass subsets this interval with `SortInterval`.\n", + "Below, we select the first `n` seconds of this interval.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [], + "source": [ + "n = 9\n", + "sort_interval_name = interval_list_name + f\"_first{n}\"\n", + "sort_interval = np.array([interval_list[0], interval_list[0] + n])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With the above, we can insert into `SortInterval`\n" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [], + "source": [ + "sgs.SortInterval.insert1(\n", + " {\n", + " \"nwb_file_name\": nwb_file_name,\n", + " \"sort_interval_name\": sort_interval_name,\n", + " \"sort_interval\": sort_interval,\n", + " },\n", + " skip_duplicates=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And verify the entry\n" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This interval list is 9 seconds long\n" + ] + } + ], + "source": [ + "print_interval_duration(\n", + " (\n", + " sgs.SortInterval\n", + " & {\n", + " \"nwb_file_name\": nwb_file_name,\n", + " \"sort_interval_name\": sort_interval_name,\n", + " }\n", + " ).fetch1(\"sort_interval\")\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Preprocessing Parameters\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`SpikeSortingPreprocessingParameters` contains the parameters used to filter the\n", + "recorded data in the spike band prior to sorting.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + " \n", + " \n", + "\n", + "
\n", + "

preproc_params_name

\n", + " \n", + "
\n", + "

preproc_params

\n", + " \n", + "
default=BLOB=
\n", + " \n", + "

Total: 1

\n", + " " + ], + "text/plain": [ + "*preproc_param preproc_pa\n", + "+------------+ +--------+\n", + "default =BLOB= \n", + " (Total: 1)" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sgs.SpikeSortingPreprocessingParameters()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here, we insert the default parameters and then fetch them.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'frequency_min': 300, 'frequency_max': 6000, 'margin_ms': 5, 'seed': 0}\n" + ] + } + ], + "source": [ + "sgs.SpikeSortingPreprocessingParameters().insert_default()\n", + "preproc_params = (\n", + " sgs.SpikeSortingPreprocessingParameters()\n", + " & {\"preproc_params_name\": \"default\"}\n", + ").fetch1(\"preproc_params\")\n", + "print(preproc_params)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's adjust the `frequency_min` to 600, the preference for hippocampal data,\n", + "and insert that into the table as a new set of parameters for hippocampal data.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [], + "source": [ + "preproc_params[\"frequency_min\"] = 600\n", + "sgs.SpikeSortingPreprocessingParameters().insert1(\n", + " {\n", + " \"preproc_params_name\": \"default_hippocampus\",\n", + " \"preproc_params\": preproc_params,\n", + " },\n", + " skip_duplicates=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Processing a key\n", + "\n", + "_key_ is often used to describe an entry we want to move through the pipeline,\n", + "and keys are often managed as dictionaries. Here, we'll manage the spike sort\n", + "recording key, `ssr_key`.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'01_s1'" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "interval_list_name" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [], + "source": [ + "ssr_key = dict(\n", + " nwb_file_name=nwb_file_name,\n", + " sort_group_id=0, # See SortGroup\n", + " sort_interval_name=sort_interval_name, # First N seconds above\n", + " preproc_params_name=\"default_hippocampus\", # See preproc_params\n", + " interval_list_name=interval_list_name,\n", + " team_name=\"My Team\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Recording Selection\n", + "\n", + "We now insert this key `SpikeSortingRecordingSelection` table to specify what\n", + "time/tetrode/etc. of the recording we want to extract.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " \n", + " \n", + " Defines recordings to be sorted\n", + "
\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
\n", + "

nwb_file_name

\n", + " name of the NWB file\n", + "
\n", + "

sort_group_id

\n", + " identifier for a group of electrodes\n", + "
\n", + "

sort_interval_name

\n", + " name for this interval\n", + "
\n", + "

preproc_params_name

\n", + " \n", + "
\n", + "

team_name

\n", + " \n", + "
\n", + "

interval_list_name

\n", + " descriptive name of this interval list\n", + "
minirec20230622_.nwb001_s1_first9default_hippocampusMy Team01_s1
\n", + " \n", + "

Total: 1

\n", + " " + ], + "text/plain": [ + "*nwb_file_name *sort_group_id *sort_interval *preproc_param *team_name interval_list_\n", + "+------------+ +------------+ +------------+ +------------+ +-----------+ +------------+\n", + "minirec2023062 0 01_s1_first9 default_hippoc My Team 01_s1 \n", + " (Total: 1)" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sgs.SpikeSortingRecordingSelection.insert1(ssr_key, skip_duplicates=True)\n", + "sgs.SpikeSortingRecordingSelection() & ssr_key" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `SpikeSortingRecording`\n", + "\n", + "And now we're ready to extract the recording! The\n", + "[`populate` command](https://datajoint.com/docs/core/datajoint-python/0.14/compute/populate/)\n", + "will automatically process data in Computed or Imported\n", + "[table tiers](https://datajoint.com/docs/core/datajoint-python/0.14/design/tables/tiers/).\n", + "\n", + "If we only want to process certain entries, we can grab their primary key with\n", + "the [`.proj()` command](https://datajoint.com/docs/core/datajoint-python/0.14/query/project/)\n", + "and use a list of primary keys when calling `populate`.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "write_binary_recording with n_jobs = 8 and chunk_size = 299593\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "0b6d4bd70bba4a92bdf77c88d07d4b08", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "write_binary_recording: 0%| | 0/1 [00:00\n", + " .Table{\n", + " border-collapse:collapse;\n", + " }\n", + " .Table th{\n", + " background: #A0A0A0; color: #ffffff; padding:4px; border:#f0e0e0 1px solid;\n", + " font-weight: normal; font-family: monospace; font-size: 100%;\n", + " }\n", + " .Table td{\n", + " padding:4px; border:#f0e0e0 1px solid; font-size:100%;\n", + " }\n", + " .Table tr:nth-child(odd){\n", + " background: #ffffff;\n", + " color: #000000;\n", + " }\n", + " .Table tr:nth-child(even){\n", + " background: #f3f1ff;\n", + " color: #000000;\n", + " }\n", + " /* Tooltip container */\n", + " .djtooltip {\n", + " }\n", + " /* Tooltip text */\n", + " .djtooltip .djtooltiptext {\n", + " visibility: hidden;\n", + " width: 120px;\n", + " background-color: black;\n", + " color: #fff;\n", + " text-align: center;\n", + " padding: 5px 0;\n", + " border-radius: 6px;\n", + " /* Position the tooltip text - see examples below! */\n", + " position: absolute;\n", + " z-index: 1;\n", + " }\n", + " #primary {\n", + " font-weight: bold;\n", + " color: black;\n", + " }\n", + " #nonprimary {\n", + " font-weight: normal;\n", + " color: white;\n", + " }\n", + "\n", + " /* Show the tooltip text when you mouse over the tooltip container */\n", + " .djtooltip:hover .djtooltiptext {\n", + " visibility: visible;\n", + " }\n", + " \n", + " \n", + " \n", + "
\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
\n", + "

nwb_file_name

\n", + " name of the NWB file\n", + "
\n", + "

sort_group_id

\n", + " identifier for a group of electrodes\n", + "
\n", + "

sort_interval_name

\n", + " name for this interval\n", + "
\n", + "

preproc_params_name

\n", + " \n", + "
\n", + "

team_name

\n", + " \n", + "
\n", + "

recording_path

\n", + " \n", + "
\n", + "

sort_interval_list_name

\n", + " descriptive name of this interval list\n", + "
minirec20230622_.nwb001_s1_first9default_hippocampusMy Team/home/cb/wrk/zOther/data/recording/minirec20230622_.nwb_01_s1_first9_0_default_hippocampusminirec20230622_.nwb_01_s1_first9_0_default_hippocampus
\n", + " \n", + "

Total: 1

\n", + " " + ], + "text/plain": [ + "*nwb_file_name *sort_group_id *sort_interval *preproc_param *team_name recording_path sort_interval_\n", + "+------------+ +------------+ +------------+ +------------+ +-----------+ +------------+ +------------+\n", + "minirec2023062 0 01_s1_first9 default_hippoc My Team /home/cb/wrk/z minirec2023062\n", + " (Total: 1)" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sgs.SpikeSortingRecording() & ssr_key" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Artifact Detection\n", + "\n", + "`ArtifactDetectionParameters` establishes the parameters for removing artifacts\n", + "from the data. We may want to target artifact signal that is within the\n", + "frequency band of our filter (600Hz-6KHz), and thus will not get removed by\n", + "filtering.\n", + "\n", + "For this demo, we'll use a parameter set to skip this step.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [], + "source": [ + "sgs.ArtifactDetectionParameters().insert_default()\n", + "artifact_key = (sgs.SpikeSortingRecording() & ssr_key).fetch1(\"KEY\")\n", + "artifact_key[\"artifact_params_name\"] = \"none\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We then pair artifact detection parameters in `ArtifactParameters` with a\n", + "recording extracted through population of `SpikeSortingRecording` and insert\n", + "into `ArtifactDetectionSelection`.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " \n", + " \n", + " Specifies artifact detection parameters to apply to a sort group's recording.\n", + "
\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
\n", + "

nwb_file_name

\n", + " name of the NWB file\n", + "
\n", + "

sort_group_id

\n", + " identifier for a group of electrodes\n", + "
\n", + "

sort_interval_name

\n", + " name for this interval\n", + "
\n", + "

preproc_params_name

\n", + " \n", + "
\n", + "

team_name

\n", + " \n", + "
\n", + "

artifact_params_name

\n", + " \n", + "
\n", + "

custom_artifact_detection

\n", + " \n", + "
minirec20230622_.nwb001_s1_first9default_hippocampusMy Teamnone0
\n", + " \n", + "

Total: 1

\n", + " " + ], + "text/plain": [ + "*nwb_file_name *sort_group_id *sort_interval *preproc_param *team_name *artifact_para custom_artifac\n", + "+------------+ +------------+ +------------+ +------------+ +-----------+ +------------+ +------------+\n", + "minirec2023062 0 01_s1_first9 default_hippoc My Team none 0 \n", + " (Total: 1)" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sgs.ArtifactDetectionSelection().insert1(artifact_key)\n", + "sgs.ArtifactDetectionSelection() & artifact_key" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then, we can populate `ArtifactDetection`, which will find periods where there\n", + "are artifacts, as specified by the parameters.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Amplitude and zscore thresholds are both None, skipping artifact detection\n" + ] + } + ], + "source": [ + "sgs.ArtifactDetection.populate(artifact_key)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Populating `ArtifactDetection` also inserts an entry into `ArtifactRemovedIntervalList`, which stores the interval without detected artifacts.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " \n", + " \n", + " Stores intervals without detected artifacts.\n", + "
\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
\n", + "

artifact_removed_interval_list_name

\n", + " \n", + "
\n", + "

nwb_file_name

\n", + " name of the NWB file\n", + "
\n", + "

sort_group_id

\n", + " identifier for a group of electrodes\n", + "
\n", + "

sort_interval_name

\n", + " name for this interval\n", + "
\n", + "

preproc_params_name

\n", + " \n", + "
\n", + "

team_name

\n", + " \n", + "
\n", + "

artifact_params_name

\n", + " \n", + "
\n", + "

artifact_removed_valid_times

\n", + " \n", + "
\n", + "

artifact_times

\n", + " np array of artifact intervals\n", + "
minirec20230622_.nwb_01_s1_first9_0_default_hippocampus_none_artifact_removed_valid_timesminirec20230622_.nwb001_s1_first9default_hippocampusMy Teamnone=BLOB==BLOB=
\n", + " \n", + "

Total: 1

\n", + " " + ], + "text/plain": [ + "*artifact_remo nwb_file_name sort_group_id sort_interval_ preproc_params team_name artifact_param artifact_r artifact_t\n", + "+------------+ +------------+ +------------+ +------------+ +------------+ +-----------+ +------------+ +--------+ +--------+\n", + "minirec2023062 minirec2023062 0 01_s1_first9 default_hippoc My Team none =BLOB= =BLOB= \n", + " (Total: 1)" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sgs.ArtifactRemovedIntervalList() & artifact_key" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Spike sorting\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `SpikeSorterParameters`\n", + "\n", + "For our example, we will be using `mountainsort4`. There are already some default parameters in the `SpikeSorterParameters` table we'll `fetch`.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'sorter': 'mountainsort4', 'sorter_params_name': 'default', 'sorter_params': {'detect_sign': -1, 'adjacency_radius': -1, 'freq_min': 300, 'freq_max': 6000, 'filter': True, 'whiten': True, 'num_workers': 1, 'clip_size': 50, 'detect_threshold': 3, 'detect_interval': 10, 'tempdir': None}}\n" + ] + } + ], + "source": [ + "sgs.SpikeSorterParameters().insert_default()\n", + "\n", + "# Let's look at the default params\n", + "sorter_name = \"mountainsort4\"\n", + "ms4_default_params = (\n", + " sgs.SpikeSorterParameters\n", + " & {\"sorter\": sorter_name, \"sorter_params_name\": \"default\"}\n", + ").fetch1()\n", + "print(ms4_default_params)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can change these default parameters to line up more closely with our preferences.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'adjacency_radius': 100,\n", + " 'clip_size': 39,\n", + " 'detect_interval': 10,\n", + " 'detect_sign': -1,\n", + " 'detect_threshold': 3,\n", + " 'filter': False,\n", + " 'freq_max': 0,\n", + " 'freq_min': 0,\n", + " 'num_workers': 4,\n", + " 'tempdir': None,\n", + " 'verbose': True,\n", + " 'whiten': False}\n" + ] + } + ], + "source": [ + "sorter_params = {\n", + " **ms4_default_params[\"sorter_params\"], # start with defaults\n", + " \"detect_sign\": -1, # downward going spikes (1 for upward, 0 for both)\n", + " \"adjacency_radius\": 100, # Sort electrodes together within 100 microns\n", + " \"filter\": False, # No filter, since we filter prior to starting sort\n", + " \"freq_min\": 0,\n", + " \"freq_max\": 0,\n", + " \"whiten\": False, # Turn whiten, since we whiten it prior to starting sort\n", + " \"num_workers\": 4, # same number as number of electrodes\n", + " \"verbose\": True,\n", + " \"clip_size\": np.int64(\n", + " 1.33e-3 # same as # of samples for 1.33 ms based on the sampling rate\n", + " * (sgc.Raw & {\"nwb_file_name\": nwb_file_name}).fetch1(\"sampling_rate\")\n", + " ),\n", + "}\n", + "from pprint import pprint\n", + "\n", + "pprint(sorter_params)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can give these `sorter_params` a `sorter_params_name` and insert into `SpikeSorterParameters`.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'sorter': 'mountainsort4',\n", + " 'sorter_params_name': 'hippocampus_tutorial',\n", + " 'sorter_params': {'detect_sign': -1,\n", + " 'adjacency_radius': 100,\n", + " 'freq_min': 0,\n", + " 'freq_max': 0,\n", + " 'filter': False,\n", + " 'whiten': False,\n", + " 'num_workers': 4,\n", + " 'clip_size': 39,\n", + " 'detect_threshold': 3,\n", + " 'detect_interval': 10,\n", + " 'tempdir': None,\n", + " 'verbose': True}}" + ] + }, + "execution_count": 53, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sorter_params_name = \"hippocampus_tutorial\"\n", + "sgs.SpikeSorterParameters.insert1(\n", + " {\n", + " \"sorter\": sorter_name,\n", + " \"sorter_params_name\": sorter_params_name,\n", + " \"sorter_params\": sorter_params,\n", + " },\n", + " skip_duplicates=True,\n", + ")\n", + "(\n", + " sgs.SpikeSorterParameters\n", + " & {\"sorter\": sorter_name, \"sorter_params_name\": sorter_params_name}\n", + ").fetch1()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `SpikeSortingSelection`\n", + "\n", + "**Gearing up to Spike Sort!**\n", + "\n", + "We now collect our various keys to insert into `SpikeSortingSelection`, which is specific to this recording and eventual sorting segment.\n", + "\n", + "_Note:_ the spike _sorter_ parameters defined above are specific to\n", + "`mountainsort4` and may not work for other sorters.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'nwb_file_name': 'minirec20230622_.nwb',\n", + " 'sort_group_id': 0,\n", + " 'sort_interval_name': '01_s1_first9',\n", + " 'preproc_params_name': 'default_hippocampus',\n", + " 'team_name': 'My Team',\n", + " 'artifact_removed_interval_list_name': 'minirec20230622_.nwb_01_s1_first9_0_default_hippocampus_none_artifact_removed_valid_times',\n", + " 'sorter': 'mountainsort4',\n", + " 'sorter_params_name': 'hippocampus_tutorial'}" + ] + }, + "execution_count": 59, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ss_key = dict(\n", + " **(sgs.ArtifactDetection & ssr_key).fetch1(\"KEY\"),\n", + " **(sgs.ArtifactRemovedIntervalList() & ssr_key).fetch1(\"KEY\"),\n", + " sorter=sorter_name,\n", + " sorter_params_name=sorter_params_name,\n", + ")\n", + "ss_key.pop(\"artifact_params_name\")\n", + "ss_key" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " \n", + " \n", + " Table for holding selection of recording and parameters for each spike sorting run\n", + "
\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
\n", + "

nwb_file_name

\n", + " name of the NWB file\n", + "
\n", + "

sort_group_id

\n", + " identifier for a group of electrodes\n", + "
\n", + "

sort_interval_name

\n", + " name for this interval\n", + "
\n", + "

preproc_params_name

\n", + " \n", + "
\n", + "

team_name

\n", + " \n", + "
\n", + "

sorter

\n", + " \n", + "
\n", + "

sorter_params_name

\n", + " \n", + "
\n", + "

artifact_removed_interval_list_name

\n", + " \n", + "
\n", + "

import_path

\n", + " optional path to previous curated sorting output\n", + "
minirec20230622_.nwb001_s1_first9default_hippocampusMy Teammountainsort4hippocampus_tutorialminirec20230622_.nwb_01_s1_first9_0_default_hippocampus_none_artifact_removed_valid_times
\n", + " \n", + "

Total: 1

\n", + " " + ], + "text/plain": [ + "*nwb_file_name *sort_group_id *sort_interval *preproc_param *team_name *sorter *sorter_params *artifact_remo import_path \n", + "+------------+ +------------+ +------------+ +------------+ +-----------+ +------------+ +------------+ +------------+ +------------+\n", + "minirec2023062 0 01_s1_first9 default_hippoc My Team mountainsort4 hippocampus_tu minirec2023062 \n", + " (Total: 1)" + ] + }, + "execution_count": 60, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sgs.SpikeSortingSelection.insert1(ss_key, skip_duplicates=True)\n", + "(sgs.SpikeSortingSelection & ss_key)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `SpikeSorting`\n", + "\n", + "After adding to `SpikeSortingSelection`, we can simply populate `SpikeSorting`.\n", + "\n", + "_Note:_ This may take time with longer data sets. Be sure to `pip install mountainsort4` if this is your first time spike sorting.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Running spike sorting on {'nwb_file_name': 'minirec20230622_.nwb', 'sort_group_id': 0, 'sort_interval_name': '01_s1_first9', 'preproc_params_name': 'default_hippocampus', 'team_name': 'My Team', 'sorter': 'mountainsort4', 'sorter_params_name': 'hippocampus_tutorial', 'artifact_removed_interval_list_name': 'minirec20230622_.nwb_01_s1_first9_0_default_hippocampus_none_artifact_removed_valid_times'}...\n", + "Mountainsort4 use the OLD spikeextractors mapped with NewToOldRecording\n", + "Using temporary directory /home/cb/wrk/zOther/data/tmp/tmpr9_xzjwk\n", + "Using 4 workers.\n", + "Using tempdir: /home/cb/wrk/zOther/data/tmp/tmpr9_xzjwk/tmpo_xved1i\n", + "Num. workers = 4\n", + "Preparing /home/cb/wrk/zOther/data/tmp/tmpr9_xzjwk/tmpo_xved1i/timeseries.hdf5...\n", + "Preparing neighborhood sorters (M=31, N=269997)...\n", + "Neighboorhood of channel 29 has 5 channels.Neighboorhood of channel 28 has 6 channels.\n", + "\n", + "Detecting events on channel 29 (phase1)...\n", + "Detecting events on channel 30 (phase1)...\n", + "Neighboorhood of channel 23 has 7 channels.\n", + "Detecting events on channel 24 (phase1)...\n", + "Neighboorhood of channel 7 has 7 channels.\n", + "Detecting events on channel 8 (phase1)...\n", + "Elapsed time for detect on neighborhood: 0:00:00.022525\n", + "Num events detected on channel 30 (phase1): 1\n", + "Computing PCA features for channel 30 (phase1)...\n", + "Elapsed time for detect on neighborhood: 0:00:00.025604\n", + "Num events detected on channel 29 (phase1): 6\n", + "Computing PCA features for channel 29 (phase1)...\n", + "Elapsed time for detect on neighborhood: 0:00:00.028793\n", + "Num events detected on channel 24 (phase1): 5\n", + "Computing PCA features for channel 24 (phase1)...\n", + "Elapsed time for detect on neighborhood: 0:00:00.029814\n", + "Num events detected on channel 8 (phase1): 5\n", + "Computing PCA features for channel 8 (phase1)...\n", + "Clustering for channel 30 (phase1)...\n", + "Found 1 clusters for channel 30 (phase1)...\n", + "Computing templates for channel 30 (phase1)...\n", + "Re-assigning events for channel 30 (phase1)...\n", + "Neighboorhood of channel 17 has 7 channels.\n", + "Detecting events on channel 18 (phase1)...\n", + "Elapsed time for detect on neighborhood: 0:00:00.096352\n", + "Num events detected on channel 18 (phase1): 5\n", + "Computing PCA features for channel 18 (phase1)...\n", + "Clustering for channel 24 (phase1)...\n", + "Found 1 clusters for channel 24 (phase1)...Clustering for channel 29 (phase1)...\n", + "\n", + "Computing templates for channel 24 (phase1)...\n", + "Found 1 clusters for channel 29 (phase1)...\n", + "Computing templates for channel 29 (phase1)...\n", + "Clustering for channel 8 (phase1)...\n", + "Found 1 clusters for channel 8 (phase1)...\n", + "Computing templates for channel 8 (phase1)...\n", + "Re-assigning events for channel 29 (phase1)...Re-assigning events for channel 24 (phase1)...\n", + "Neighboorhood of channel 20 has 7 channels.\n", + "Detecting events on channel 21 (phase1)...\n", + "\n", + "Neighboorhood of channel 25 has 7 channels.\n", + "Detecting events on channel 26 (phase1)...\n", + "Clustering for channel 18 (phase1)...\n", + "Found 1 clusters for channel 18 (phase1)...\n", + "Computing templates for channel 18 (phase1)...\n", + "Re-assigning events for channel 8 (phase1)...\n", + "Neighboorhood of channel 26 has 7 channels.\n", + "Detecting events on channel 27 (phase1)...\n", + "Elapsed time for detect on neighborhood: 0:00:00.039213\n", + "Num events detected on channel 26 (phase1): 4\n", + "Computing PCA features for channel 26 (phase1)...\n", + "Elapsed time for detect on neighborhood:Re-assigning events for channel 18 (phase1)...\n", + " 0:00:00.055824\n", + "Num events detected on channel 21 (phase1): 14\n", + "Neighboorhood of channel 14 has 7 channels.Computing PCA features for channel 21 (phase1)...\n", + "\n", + "Detecting events on channel 15 (phase1)...\n", + "Elapsed time for detect on neighborhood: 0:00:00.029223\n", + "Num events detected on channel 27 (phase1): 8\n", + "Computing PCA features for channel 27 (phase1)...\n", + "Elapsed time for detect on neighborhood:Clustering for channel 27 (phase1)...\n", + "Found 1 clusters for channel 27 (phase1)... 0:00:00.086340\n", + "Num events detected on channel 15 (phase1): 2\n", + "Computing PCA features for channel 15 (phase1)...\n", + "\n", + "Computing templates for channel 27 (phase1)...\n", + "Clustering for channel 26 (phase1)...\n", + "Found 1 clusters for channel 26 (phase1)...\n", + "Computing templates for channel 26 (phase1)...\n", + "Clustering for channel 21 (phase1)...\n", + "Found 1 clusters for channel 21 (phase1)...\n", + "Computing templates for channel 21 (phase1)...\n", + "Re-assigning events for channel 26 (phase1)...Re-assigning events for channel 27 (phase1)...\n", + "Neighboorhood of channel 4 has 7 channels.\n", + "Detecting events on channel 5 (phase1)...\n", + "Re-assigning events for channel 21 (phase1)...\n", + "\n", + "Neighboorhood of channel 15 has 7 channels.Neighboorhood of channel 16 has 7 channels.\n", + "Detecting events on channel 16 (phase1)...\n", + "\n", + "Detecting events on channel 17 (phase1)...\n", + "Elapsed time for detect on neighborhood: 0:00:00.027093\n", + "Num events detected on channel 5 (phase1): 18\n", + "Computing PCA features for channel 5 (phase1)...\n", + "Elapsed time for detect on neighborhood: 0:00:00.035564\n", + "Num events detected on channel 16 (phase1): 6\n", + "Computing PCA features for channel 16 (phase1)...\n", + "Clustering for channel 5 (phase1)...\n", + "Found 1 clusters for channel 5 (phase1)...\n", + "Computing templates for channel 5 (phase1)...\n", + "Clustering for channel 16 (phase1)...\n", + "Found 1 clusters for channel 16 (phase1)...\n", + "Computing templates for channel 16 (phase1)...\n", + "Elapsed time for detect on neighborhood: 0:00:00.091005\n", + "Num events detected on channel 17 (phase1): 17\n", + "Computing PCA features for channel 17 (phase1)...\n", + "Clustering for channel 15 (phase1)...Re-assigning events for channel 5 (phase1)...\n", + "Found 1 clusters for channel 15 (phase1)...\n", + "Computing templates for channel 15 (phase1)...\n", + "\n", + "Neighboorhood of channel 11 has 7 channels.\n", + "Detecting events on channel 12 (phase1)...\n", + "Re-assigning events for channel 16 (phase1)...\n", + "Neighboorhood of channel 12 has 7 channels.\n", + "Detecting events on channel 13 (phase1)...\n", + "Elapsed time for detect on neighborhood:Re-assigning events for channel 15 (phase1)... 0:00:00.040278\n", + "Num events detected on channel 12 (phase1): 7\n", + "Computing PCA features for channel 12 (phase1)...\n", + "\n", + "Neighboorhood of channel 6 has 7 channels.\n", + "Detecting events on channel 7 (phase1)...\n", + "Clustering for channel 17 (phase1)...\n", + "Found 1 clusters for channel 17 (phase1)...\n", + "Computing templates for channel 17 (phase1)...\n", + "Re-assigning events for channel 17 (phase1)...\n", + "Neighboorhood of channel 21 has 7 channels.\n", + "Detecting events on channel 22 (phase1)...\n", + "Elapsed time for detect on neighborhood: 0:00:00.033808\n", + "Num events detected on channel 7 (phase1): 10\n", + "Computing PCA features for channel 7 (phase1)...\n", + "Elapsed time for detect on neighborhood: 0:00:00.076235\n", + "Num events detected on channel 13 (phase1): 1\n", + "Computing PCA features for channel 13 (phase1)...\n", + "Clustering for channel 12 (phase1)...\n", + "Found 1 clusters for channel 12 (phase1)...\n", + "Computing templates for channel 12 (phase1)...\n", + "Clustering for channel 13 (phase1)...Re-assigning events for channel 12 (phase1)...\n", + "Neighboorhood of channel 0 has 4 channels.\n", + "Detecting events on channel 1 (phase1)...\n", + "\n", + "Found 1 clusters for channel 13 (phase1)...\n", + "Computing templates for channel 13 (phase1)...\n", + "Elapsed time for detect on neighborhood:Re-assigning events for channel 13 (phase1)...\n", + "Neighboorhood of channel 5 has 7 channels.\n", + "Detecting events on channel 6 (phase1)...\n", + " 0:00:00.026181\n", + "Num events detected on channel 1 (phase1): 3\n", + "Computing PCA features for channel 1 (phase1)...\n", + "Elapsed time for detect on neighborhood: 0:00:00.133353\n", + "Num events detected on channel 22 (phase1): 3\n", + "Computing PCA features for channel 22 (phase1)...\n", + "Elapsed time for detect on neighborhood: 0:00:00.025383\n", + "Num events detected on channel 6 (phase1): 2\n", + "Computing PCA features for channel 6 (phase1)...\n", + "Clustering for channel 1 (phase1)...Clustering for channel 7 (phase1)...\n", + "Found 1 clusters for channel 1 (phase1)...\n", + "Computing templates for channel 1 (phase1)...\n", + "\n", + "Found 1 clusters for channel 7 (phase1)...\n", + "Computing templates for channel 7 (phase1)...\n", + "Re-assigning events for channel 1 (phase1)...\n", + "Neighboorhood of channel 13 has 7 channels.Re-assigning events for channel 7 (phase1)...\n", + "Detecting events on channel 14 (phase1)...\n", + "\n", + "Neighboorhood of channel 8 has 7 channels.\n", + "Detecting events on channel 9 (phase1)...\n", + "Clustering for channel 6 (phase1)...\n", + "Found 1 clusters for channel 6 (phase1)...\n", + "Computing templates for channel 6 (phase1)...\n", + "Elapsed time for detect on neighborhood: 0:00:00.033709\n", + "Num events detected on channel 9 (phase1): 6\n", + "Computing PCA features for channel 9 (phase1)...\n", + "Elapsed time for detect on neighborhood:Re-assigning events for channel 6 (phase1)... 0:00:00.055517\n", + "Num events detected on channel 14 (phase1): 4\n", + "Computing PCA features for channel 14 (phase1)...\n", + "\n", + "Neighboorhood of channel 22 has 7 channels.\n", + "Detecting events on channel 23 (phase1)...\n", + "Elapsed time for detect on neighborhood: 0:00:00.020576\n", + "Num events detected on channel 23 (phase1): 17\n", + "Computing PCA features for channel 23 (phase1)...\n", + "Clustering for channel 23 (phase1)...Clustering for channel 14 (phase1)...\n", + "Found 1 clusters for channel 14 (phase1)...\n", + "Computing templates for channel 14 (phase1)...\n", + "Clustering for channel 22 (phase1)...\n", + "Found 1 clusters for channel 22 (phase1)...\n", + "Computing templates for channel 22 (phase1)...\n", + "Clustering for channel 9 (phase1)...\n", + "Found 1 clusters for channel 9 (phase1)...\n", + "Computing templates for channel 9 (phase1)...\n", + "\n", + "Found 1 clusters for channel 23 (phase1)...\n", + "Computing templates for channel 23 (phase1)...\n", + "Re-assigning events for channel 14 (phase1)...\n", + "Re-assigning events for channel 9 (phase1)...Neighboorhood of channel 18 has 7 channels.\n", + "Detecting events on channel 19 (phase1)...\n", + "\n", + "Neighboorhood of channel 9 has 7 channels.\n", + "Detecting events on channel 10 (phase1)...\n", + "Re-assigning events for channel 23 (phase1)...\n", + "Neighboorhood of channel 27 has 7 channels.\n", + "Detecting events on channel 28 (phase1)...\n", + "Re-assigning events for channel 22 (phase1)...\n", + "Neighboorhood of channel 3 has 7 channels.\n", + "Detecting events on channel 4 (phase1)...\n", + "Elapsed time for detect on neighborhood: 0:00:00.035256\n", + "Num events detected on channel 19 (phase1): 11\n", + "Computing PCA features for channel 19 (phase1)...\n", + "Elapsed time for detect on neighborhood: 0:00:00.040792\n", + "Num events detected on channel 10 (phase1): 5\n", + "Computing PCA features for channel 10 (phase1)...\n", + "Elapsed time for detect on neighborhood: 0:00:00.033487\n", + "Num events detected on channel 28 (phase1): 4\n", + "Computing PCA features for channel 28 (phase1)...\n", + "Elapsed time for detect on neighborhood: 0:00:00.029246\n", + "Num events detected on channel 4 (phase1): 10\n", + "Computing PCA features for channel 4 (phase1)...\n", + "Clustering for channel 28 (phase1)...\n", + "Found 1 clusters for channel 28 (phase1)...\n", + "Computing templates for channel 28 (phase1)...\n", + "Re-assigning events for channel 28 (phase1)...\n", + "Clustering for channel 10 (phase1)...\n", + "Found 1 clusters for channel 10 (phase1)...\n", + "Computing templates for channel 10 (phase1)...\n", + "Re-assigning events for channel 10 (phase1)...\n", + "Clustering for channel 19 (phase1)...\n", + "Found 1 clusters for channel 19 (phase1)...\n", + "Computing templates for channel 19 (phase1)...\n", + "Re-assigning events for channel 19 (phase1)...\n", + "Neighboorhood of channel 1 has 5 channels.\n", + "Detecting events on channel 2 (phase1)...\n", + "Elapsed time for detect on neighborhood: 0:00:00.019415\n", + "Num events detected on channel 2 (phase1): 3\n", + "Computing PCA features for channel 2 (phase1)...\n", + "Clustering for channel 4 (phase1)...\n", + "Found 1 clusters for channel 4 (phase1)...\n", + "Computing templates for channel 4 (phase1)...\n", + "Clustering for channel 2 (phase1)...\n", + "Found 1 clusters for channel 2 (phase1)...\n", + "Computing templates for channel 2 (phase1)...\n", + "Re-assigning events for channel 2 (phase1)...\n", + "Neighboorhood of channel 30 has 4 channels.\n", + "Detecting events on channel 31 (phase1)...\n", + "Elapsed time for detect on neighborhood: 0:00:00.012684\n", + "Num events detected on channel 31 (phase1): 0\n", + "Computing PCA features for channel 31 (phase1)...\n", + "Clustering for channel 31 (phase1)...\n", + "Found 0 clusters for channel 31 (phase1)...\n", + "Computing templates for channel 31 (phase1)...\n", + "Re-assigning events for channel 31 (phase1)...\n", + "Neighboorhood of channel 24 has 7 channels.\n", + "Detecting events on channel 25 (phase1)...\n", + "Elapsed time for detect on neighborhood: 0:00:00.017826\n", + "Num events detected on channel 25 (phase1): 14\n", + "Computing PCA features for channel 25 (phase1)...\n", + "Re-assigning events for channel 4 (phase1)...\n", + "Neighboorhood of channel 19 has 7 channels.\n", + "Detecting events on channel 20 (phase1)...\n", + "Clustering for channel 25 (phase1)...\n", + "Found 1 clusters for channel 25 (phase1)...\n", + "Computing templates for channel 25 (phase1)...\n", + "Elapsed time for detect on neighborhood: 0:00:00.022288\n", + "Num events detected on channel 20 (phase1): 14\n", + "Computing PCA features for channel 20 (phase1)...\n", + "Re-assigning events for channel 25 (phase1)...\n", + "Neighboorhood of channel 2 has 6 channels.\n", + "Detecting events on channel 3 (phase1)...\n", + "Elapsed time for detect on neighborhood: 0:00:00.018741\n", + "Num events detected on channel 3 (phase1): 11\n", + "Computing PCA features for channel 3 (phase1)...\n", + "Clustering for channel 3 (phase1)...\n", + "Found 1 clusters for channel 3 (phase1)...\n", + "Computing templates for channel 3 (phase1)...\n", + "Re-assigning events for channel 3 (phase1)...\n", + "Neighboorhood of channel 10 has 7 channels.\n", + "Detecting events on channel 11 (phase1)...\n", + "Clustering for channel 20 (phase1)...\n", + "Found 1 clusters for channel 20 (phase1)...\n", + "Computing templates for channel 20 (phase1)...\n", + "Re-assigning events for channel 20 (phase1)...\n", + "Elapsed time for detect on neighborhood: 0:00:00.035092\n", + "Num events detected on channel 11 (phase1): 6\n", + "Computing PCA features for channel 11 (phase1)...\n", + "Clustering for channel 11 (phase1)...\n", + "Found 1 clusters for channel 11 (phase1)...\n", + "Computing templates for channel 11 (phase1)...\n", + "Re-assigning events for channel 11 (phase1)...\n", + "Neighboorhood of channel 17 has 7 channels.\n", + "Computing PCA features for channel 18 (phase2)...\n", + "No duplicate events found for channel 17 in phase2\n", + "Neighboorhood of channel 25 has 7 channels.\n", + "Computing PCA features for channel 26 (phase2)...\n", + "No duplicate events found for channel 25 in phase2\n", + "Neighboorhood of channel 4 has 7 channels.\n", + "Computing PCA features for channel 5 (phase2)...\n", + "No duplicate events found for channel 4 in phase2\n", + "Neighboorhood of channel 29 has 5 channels.\n", + "Computing PCA features for channel 30 (phase2)...\n", + "No duplicate events found for channel 29 in phase2\n", + "Clustering for channel 30 (phase2)...\n", + "Found 1 clusters for channel 30 (phase2)...\n", + "Neighboorhood of channel 8 has 7 channels.\n", + "Computing PCA features for channel 9 (phase2)...\n", + "No duplicate events found for channel 8 in phase2\n", + "Clustering for channel 18 (phase2)...\n", + "Found 1 clusters for channel 18 (phase2)...\n", + "Neighboorhood of channel 24 has 7 channels.\n", + "Computing PCA features for channel 25 (phase2)...\n", + "No duplicate events found for channel 24 in phase2\n", + "Clustering for channel 5 (phase2)...\n", + "Found 1 clusters for channel 5 (phase2)...\n", + "Neighboorhood of channel 1 has 5 channels.\n", + "Computing PCA features for channel 2 (phase2)...\n", + "No duplicate events found for channel 1 in phase2\n", + "Clustering for channel 9 (phase2)...\n", + "Found 1 clusters for channel 9 (phase2)...\n", + "Neighboorhood of channel 14 has 7 channels.\n", + "Computing PCA features for channel 15 (phase2)...\n", + "No duplicate events found for channel 14 in phase2\n", + "Clustering for channel 2 (phase2)...\n", + "Found 1 clusters for channel 2 (phase2)...\n", + "Neighboorhood of channel 12 has 7 channels.\n", + "Computing PCA features for channel 13 (phase2)...\n", + "No duplicate events found for channel 12 in phase2\n", + "Clustering for channel 26 (phase2)...\n", + "Found 1 clusters for channel 26 (phase2)...\n", + "Neighboorhood of channel 27 has 7 channels.\n", + "Computing PCA features for channel 28 (phase2)...\n", + "No duplicate events found for channel 27 in phase2\n", + "Clustering for channel 15 (phase2)...\n", + "Found 1 clusters for channel 15 (phase2)...\n", + "Neighboorhood of channel 28 has 6 channels.\n", + "Computing PCA features for channel 29 (phase2)...\n", + "No duplicate events found for channel 28 in phase2\n", + "Clustering for channel 13 (phase2)...\n", + "Found 1 clusters for channel 13 (phase2)...\n", + "Clustering for channel 29 (phase2)...\n", + "Found 1 clusters for channel 29 (phase2)...\n", + "Neighboorhood of channel 16 has 7 channels.\n", + "Computing PCA features for channel 17 (phase2)...\n", + "No duplicate events found for channel 16 in phase2\n", + "Neighboorhood of channel 13 has 7 channels.\n", + "Computing PCA features for channel 14 (phase2)...\n", + "No duplicate events found for channel 13 in phase2\n", + "Clustering for channel 17 (phase2)...\n", + "Found 1 clusters for channel 17 (phase2)...\n", + "Neighboorhood of channel 26 has 7 channels.\n", + "Computing PCA features for channel 27 (phase2)...\n", + "No duplicate events found for channel 26 in phase2\n", + "Clustering for channel 27 (phase2)...Clustering for channel 14 (phase2)...\n", + "\n", + "Found 1 clusters for channel 14 (phase2)...\n", + "Found 1 clusters for channel 27 (phase2)...\n", + "Neighboorhood of channel 18 has 7 channels.\n", + "Computing PCA features for channel 19 (phase2)...\n", + "No duplicate events found for channel 18 in phase2\n", + "Neighboorhood of channel 11 has 7 channels.\n", + "Computing PCA features for channel 12 (phase2)...Clustering for channel 28 (phase2)...\n", + "\n", + "No duplicate events found for channel 11 in phase2\n", + "Found 1 clusters for channel 28 (phase2)...\n", + "Neighboorhood of channel 15 has 7 channels.\n", + "Computing PCA features for channel 16 (phase2)...\n", + "No duplicate events found for channel 15 in phase2\n", + "Clustering for channel 25 (phase2)...\n", + "Found 1 clusters for channel 25 (phase2)...\n", + "Neighboorhood of channel 9 has 7 channels.\n", + "Computing PCA features for channel 10 (phase2)...\n", + "No duplicate events found for channel 9 in phase2\n", + "Clustering for channel 12 (phase2)...\n", + "Found 1 clusters for channel 12 (phase2)...\n", + "Neighboorhood of channel 10 has 7 channels.\n", + "Computing PCA features for channel 11 (phase2)...\n", + "No duplicate events found for channel 10 in phase2\n", + "Clustering for channel 19 (phase2)...\n", + "Found 1 clusters for channel 19 (phase2)...\n", + "Neighboorhood of channel 3 has 7 channels.\n", + "Computing PCA features for channel 4 (phase2)...\n", + "No duplicate events found for channel 3 in phase2\n", + "Clustering for channel 11 (phase2)...\n", + "Found 1 clusters for channel 11 (phase2)...\n", + "Neighboorhood of channel 6 has 7 channels.\n", + "Computing PCA features for channel 7 (phase2)...\n", + "No duplicate events found for channel 6 in phase2\n", + "Clustering for channel 4 (phase2)...\n", + "Found 1 clusters for channel 4 (phase2)...\n", + "Neighboorhood of channel 23 has 7 channels.\n", + "Computing PCA features for channel 24 (phase2)...\n", + "No duplicate events found for channel 23 in phase2\n", + "Clustering for channel 7 (phase2)...\n", + "Found 1 clusters for channel 7 (phase2)...\n", + "Neighboorhood of channel 22 has 7 channels.\n", + "Computing PCA features for channel 23 (phase2)...\n", + "No duplicate events found for channel 22 in phase2\n", + "Clustering for channel 23 (phase2)...Clustering for channel 16 (phase2)...\n", + "\n", + "Found 1 clusters for channel 16 (phase2)...\n", + "Found 1 clusters for channel 23 (phase2)...\n", + "Neighboorhood of channel 5 has 7 channels.\n", + "Computing PCA features for channel 6 (phase2)...\n", + "No duplicate events found for channel 5 in phase2\n", + "Neighboorhood of channel 20 has 7 channels.\n", + "Computing PCA features for channel 21 (phase2)...\n", + "No duplicate events found for channel 20 in phase2\n", + "Clustering for channel 10 (phase2)...\n", + "Found 1 clusters for channel 10 (phase2)...\n", + "Neighboorhood of channel 2 has 6 channels.\n", + "Computing PCA features for channel 3 (phase2)...\n", + "No duplicate events found for channel 2 in phase2\n", + "Clustering for channel 24 (phase2)...\n", + "Found 1 clusters for channel 24 (phase2)...\n", + "Clustering for channel 21 (phase2)...\n", + "Found 1 clusters for channel 21 (phase2)...\n", + "Neighboorhood of channel 21 has 7 channels.\n", + "Computing PCA features for channel 22 (phase2)...\n", + "No duplicate events found for channel 21 in phase2\n", + "Clustering for channel 6 (phase2)...\n", + "Found 1 clusters for channel 6 (phase2)...\n", + "Neighboorhood of channel 7 has 7 channels.\n", + "Clustering for channel 22 (phase2)...\n", + "Found 1 clusters for channel 22 (phase2)...\n", + "Computing PCA features for channel 8 (phase2)...\n", + "No duplicate events found for channel 7 in phase2\n", + "Clustering for channel 3 (phase2)...\n", + "Found 1 clusters for channel 3 (phase2)...\n", + "Neighboorhood of channel 0 has 4 channels.\n", + "Computing PCA features for channel 1 (phase2)...\n", + "No duplicate events found for channel 0 in phase2\n", + "Clustering for channel 1 (phase2)...\n", + "Found 1 clusters for channel 1 (phase2)...\n", + "Neighboorhood of channel 30 has 4 channels.\n", + "Computing PCA features for channel 31 (phase2)...\n", + "No duplicate events found for channel 30 in phase2\n", + "Clustering for channel 31 (phase2)...\n", + "Found 0 clusters for channel 31 (phase2)...\n", + "Clustering for channel 8 (phase2)...\n", + "Found 1 clusters for channel 8 (phase2)...\n", + "Neighboorhood of channel 19 has 7 channels.\n", + "Computing PCA features for channel 20 (phase2)...\n", + "No duplicate events found for channel 19 in phase2\n", + "Clustering for channel 20 (phase2)...\n", + "Found 1 clusters for channel 20 (phase2)...\n", + "Preparing output...\n", + "Done with ms4alg.\n", + "Cleaning tempdir::::: /home/cb/wrk/zOther/data/tmp/tmpr9_xzjwk/tmpo_xved1i\n", + "mountainsort4 run time 5.69s\n", + "Saving sorting results...\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/cb/miniconda3/envs/spy/lib/python3.9/site-packages/spikeinterface/core/basesorting.py:212: UserWarning: The registered recording will not be persistent on disk, but only available in memory\n", + " warnings.warn(\"The registered recording will not be persistent on disk, but only available in memory\")\n", + "/home/cb/miniconda3/envs/spy/lib/python3.9/tempfile.py:821: ResourceWarning: Implicitly cleaning up \n", + " _warnings.warn(warn_message, ResourceWarning)\n" + ] + } + ], + "source": [ + "# [(sgs.SpikeSortingSelection & ss_key).proj()]\n", + "sgs.SpikeSorting.populate()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Check to make sure the table populated\n" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
\n", + "

nwb_file_name

\n", + " name of the NWB file\n", + "
\n", + "

sort_group_id

\n", + " identifier for a group of electrodes\n", + "
\n", + "

sort_interval_name

\n", + " name for this interval\n", + "
\n", + "

preproc_params_name

\n", + " \n", + "
\n", + "

team_name

\n", + " \n", + "
\n", + "

sorter

\n", + " \n", + "
\n", + "

sorter_params_name

\n", + " \n", + "
\n", + "

artifact_removed_interval_list_name

\n", + " \n", + "
\n", + "

sorting_path

\n", + " \n", + "
\n", + "

time_of_sort

\n", + " in Unix time, to the nearest second\n", + "
minirec20230622_.nwb001_s1_first9default_hippocampusMy Teammountainsort4hippocampus_tutorialminirec20230622_.nwb_01_s1_first9_0_default_hippocampus_none_artifact_removed_valid_times/home/cb/wrk/zOther/data/\"sorting\"/minirec20230622_.nwb_01_s1_first9_0_default_hippocampus_3335c236_spikesorting1689971050
\n", + " \n", + "

Total: 1

\n", + " " + ], + "text/plain": [ + "*nwb_file_name *sort_group_id *sort_interval *preproc_param *team_name *sorter *sorter_params *artifact_remo sorting_path time_of_sort \n", + "+------------+ +------------+ +------------+ +------------+ +-----------+ +------------+ +------------+ +------------+ +------------+ +------------+\n", + "minirec2023062 0 01_s1_first9 default_hippoc My Team mountainsort4 hippocampus_tu minirec2023062 /home/cb/wrk/z 1689971050 \n", + " (Total: 1)" + ] + }, + "execution_count": 63, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sgs.SpikeSorting() & ss_key" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Next Steps\n", + "\n", + "Congratulations, you've spike sorted! See our\n", + "[next notebook](./03_Curation.ipynb) for curation steps.\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.10.5 64-bit", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.16" + }, + "vscode": { + "interpreter": { + "hash": "8a94588eda9d64d9e9a351ab8144e55b1fabf5113b54e67dd26a8c27df0381b3" + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/notebooks/02_curation.ipynb b/notebooks/02_curation.ipynb deleted file mode 100644 index 35b1d92fb..000000000 --- a/notebooks/02_curation.ipynb +++ /dev/null @@ -1,495 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Curation\n", - "\n", - "**Note: make a copy of this notebook and run the copy to avoid git conflicts in the future**\n", - "\n", - "This is the second in a multi-part tutorial on the NWB-Datajoint pipeline used in Loren Frank's lab, UCSF. It demonstrates how to curate the results of spike sorting.\n", - "\n", - "Finish [tutorial 0](0_intro.ipynb) and [tutorial 1](1_spikesorting.ipynb) before proceeding.\n", - "\n", - "Let's start by importing the `spyglass` package, along with a few others. " - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[2022-08-01 17:21:49,989][INFO]: Connecting zoldello@lmf-db.cin.ucsf.edu:3306\n", - "[2022-08-01 17:21:50,035][INFO]: Connected zoldello@lmf-db.cin.ucsf.edu:3306\n" - ] - }, - { - "data": { - "application/javascript": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n\n if (typeof root._bokeh_onload_callbacks === \"undefined\" || force === true) {\n root._bokeh_onload_callbacks = [];\n root._bokeh_is_loading = undefined;\n }\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n\n root._bokeh_onload_callbacks.push(callback);\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0) {\n run_callbacks();\n return null;\n }\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'gridstack': 'https://cdn.jsdelivr.net/npm/gridstack@4.2.5/dist/gridstack-h5', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {'gridstack': {'exports': 'GridStack'}}});\n require([\"gridstack\"], function(GridStack) {\n\twindow.GridStack = GridStack\n\ton_load()\n })\n require([\"notyf\"], function() {\n\ton_load()\n })\n root._bokeh_is_loading = css_urls.length + 2;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length;\n } if (((window['GridStack'] !== undefined) && (!(window['GridStack'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.jsdelivr.net/npm/gridstack@4.2.5/dist/gridstack-h5.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['Notyf'] !== undefined) && (!(window['Notyf'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.jsdelivr.net/npm/notyf@3/notyf.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) >= 0) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) >= 0) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.jsdelivr.net/npm/notyf@3/notyf.min.js\"];\n var js_modules = [];\n var css_urls = [\"https://cdn.jsdelivr.net/npm/notyf@3/notyf.min.css\", \"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css\"];\n var inline_js = [ function(Bokeh) {\n inject_raw_css(\".codehilite .hll { background-color: #ffffcc }\\n.codehilite { background: #f8f8f8; }\\n.codehilite .c { color: #408080; font-style: italic } /* Comment */\\n.codehilite .err { border: 1px solid #FF0000 } /* Error */\\n.codehilite .k { color: #008000; font-weight: bold } /* Keyword */\\n.codehilite .o { color: #666666 } /* Operator */\\n.codehilite .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\\n.codehilite .cm { color: #408080; font-style: italic } /* Comment.Multiline */\\n.codehilite .cp { color: #BC7A00 } /* Comment.Preproc */\\n.codehilite .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\\n.codehilite .c1 { color: #408080; font-style: italic } /* Comment.Single */\\n.codehilite .cs { color: #408080; font-style: italic } /* Comment.Special */\\n.codehilite .gd { color: #A00000 } /* Generic.Deleted */\\n.codehilite .ge { font-style: italic } /* Generic.Emph */\\n.codehilite .gr { color: #FF0000 } /* Generic.Error */\\n.codehilite .gh { color: #000080; font-weight: bold } /* Generic.Heading */\\n.codehilite .gi { color: #00A000 } /* Generic.Inserted */\\n.codehilite .go { color: #888888 } /* Generic.Output */\\n.codehilite .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\\n.codehilite .gs { font-weight: bold } /* Generic.Strong */\\n.codehilite .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\\n.codehilite .gt { color: #0044DD } /* Generic.Traceback */\\n.codehilite .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\\n.codehilite .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\\n.codehilite .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\\n.codehilite .kp { color: #008000 } /* Keyword.Pseudo */\\n.codehilite .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\\n.codehilite .kt { color: #B00040 } /* Keyword.Type */\\n.codehilite .m { color: #666666 } /* Literal.Number */\\n.codehilite .s { color: #BA2121 } /* Literal.String */\\n.codehilite .na { color: #7D9029 } /* Name.Attribute */\\n.codehilite .nb { color: #008000 } /* Name.Builtin */\\n.codehilite .nc { color: #0000FF; font-weight: bold } /* Name.Class */\\n.codehilite .no { color: #880000 } /* Name.Constant */\\n.codehilite .nd { color: #AA22FF } /* Name.Decorator */\\n.codehilite .ni { color: #999999; font-weight: bold } /* Name.Entity */\\n.codehilite .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\\n.codehilite .nf { color: #0000FF } /* Name.Function */\\n.codehilite .nl { color: #A0A000 } /* Name.Label */\\n.codehilite .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\\n.codehilite .nt { color: #008000; font-weight: bold } /* Name.Tag */\\n.codehilite .nv { color: #19177C } /* Name.Variable */\\n.codehilite .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\\n.codehilite .w { color: #bbbbbb } /* Text.Whitespace */\\n.codehilite .mb { color: #666666 } /* Literal.Number.Bin */\\n.codehilite .mf { color: #666666 } /* Literal.Number.Float */\\n.codehilite .mh { color: #666666 } /* Literal.Number.Hex */\\n.codehilite .mi { color: #666666 } /* Literal.Number.Integer */\\n.codehilite .mo { color: #666666 } /* Literal.Number.Oct */\\n.codehilite .sa { color: #BA2121 } /* Literal.String.Affix */\\n.codehilite .sb { color: #BA2121 } /* Literal.String.Backtick */\\n.codehilite .sc { color: #BA2121 } /* Literal.String.Char */\\n.codehilite .dl { color: #BA2121 } /* Literal.String.Delimiter */\\n.codehilite .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\\n.codehilite .s2 { color: #BA2121 } /* Literal.String.Double */\\n.codehilite .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\\n.codehilite .sh { color: #BA2121 } /* Literal.String.Heredoc */\\n.codehilite .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\\n.codehilite .sx { color: #008000 } /* Literal.String.Other */\\n.codehilite .sr { color: #BB6688 } /* Literal.String.Regex */\\n.codehilite .s1 { color: #BA2121 } /* Literal.String.Single */\\n.codehilite .ss { color: #19177C } /* Literal.String.Symbol */\\n.codehilite .bp { color: #008000 } /* Name.Builtin.Pseudo */\\n.codehilite .fm { color: #0000FF } /* Name.Function.Magic */\\n.codehilite .vc { color: #19177C } /* Name.Variable.Class */\\n.codehilite .vg { color: #19177C } /* Name.Variable.Global */\\n.codehilite .vi { color: #19177C } /* Name.Variable.Instance */\\n.codehilite .vm { color: #19177C } /* Name.Variable.Magic */\\n.codehilite .il { color: #666666 } /* Literal.Number.Integer.Long */\\n\\n.markdown h1 { margin-block-start: 0.34em }\\n.markdown h2 { margin-block-start: 0.42em }\\n.markdown h3 { margin-block-start: 0.5em }\\n.markdown h4 { margin-block-start: 0.67em }\\n.markdown h5 { margin-block-start: 0.84em }\\n.markdown h6 { margin-block-start: 1.17em }\\n.markdown ul { padding-inline-start: 2em }\\n.markdown ol { padding-inline-start: 2em }\\n.markdown strong { font-weight: 600 }\\n.markdown a { color: -webkit-link }\\n.markdown a { color: -moz-hyperlinkText }\\n\");\n }, function(Bokeh) {\n inject_raw_css(\".bk.card {\\n border: 1px solid rgba(0,0,0,.125);\\n border-radius: 0.25rem;\\n}\\n.bk.accordion {\\n border: 1px solid rgba(0,0,0,.125);\\n}\\n.bk.card-header {\\n align-items: center;\\n background-color: rgba(0, 0, 0, 0.03);\\n border-radius: 0.25rem;\\n display: inline-flex;\\n justify-content: start;\\n width: 100%;\\n}\\n.bk.accordion-header {\\n align-items: center;\\n background-color: rgba(0, 0, 0, 0.03);\\n border-radius: 0;\\n display: flex;\\n justify-content: start;\\n width: 100%;\\n}\\n.bk.card-button {\\n background-color: transparent;\\n margin-left: 0.5em;\\n}\\n.bk.card-header-row {\\n position: relative !important;\\n}\\n.bk.card-title {\\n align-items: center;\\n font-size: 1.4em;\\n font-weight: bold;\\n overflow-wrap: break-word;\\n}\\n.bk.card-header-row > .bk {\\n overflow-wrap: break-word;\\n text-align: center;\\n}\\n\");\n }, function(Bokeh) {\n inject_raw_css(\".bk.panel-widget-box {\\n min-height: 20px;\\n background-color: #f5f5f5;\\n border: 1px solid #e3e3e3;\\n border-radius: 4px;\\n -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.05);\\n box-shadow: inset 0 1px 1px rgba(0,0,0,.05);\\n overflow-x: hidden;\\n overflow-y: hidden;\\n}\\n\\n.scrollable {\\n overflow: scroll;\\n}\\n\\nprogress {\\n appearance: none;\\n -moz-appearance: none;\\n -webkit-appearance: none;\\n border: none;\\n height: 20px;\\n background-color: whiteSmoke;\\n border-radius: 3px;\\n box-shadow: 0 2px 3px rgba(0,0,0,.5) inset;\\n color: royalblue;\\n position: relative;\\n margin: 0 0 1.5em;\\n}\\n\\nprogress[value]::-webkit-progress-bar {\\n background-color: whiteSmoke;\\n border-radius: 3px;\\n box-shadow: 0 2px 3px rgba(0,0,0,.5) inset;\\n}\\n\\nprogress[value]::-webkit-progress-value {\\n position: relative;\\n background-size: 35px 20px, 100% 100%, 100% 100%;\\n border-radius:3px;\\n}\\n\\nprogress.active:not([value])::before {\\n background-position: 10%;\\n animation-name: stripes;\\n animation-duration: 3s;\\n animation-timing-function: linear;\\n animation-iteration-count: infinite;\\n}\\n\\nprogress[value]::-moz-progress-bar {\\n background-size: 35px 20px, 100% 100%, 100% 100%;\\n border-radius:3px;\\n}\\n\\nprogress:not([value])::-moz-progress-bar {\\n border-radius:3px;\\n background: linear-gradient(-45deg, transparent 33%, rgba(0, 0, 0, 0.2) 33%, rgba(0, 0, 0, 0.2) 66%, transparent 66%) left/2.5em 1.5em;\\n}\\n\\nprogress.active:not([value])::-moz-progress-bar {\\n background-position: 10%;\\n animation-name: stripes;\\n animation-duration: 3s;\\n animation-timing-function: linear;\\n animation-iteration-count: infinite;\\n}\\n\\nprogress.active:not([value])::-webkit-progress-bar {\\n background-position: 10%;\\n animation-name: stripes;\\n animation-duration: 3s;\\n animation-timing-function: linear;\\n animation-iteration-count: infinite;\\n}\\n\\nprogress.primary[value]::-webkit-progress-value { background-color: #007bff; }\\nprogress.primary:not([value])::before { background-color: #007bff; }\\nprogress.primary:not([value])::-webkit-progress-bar { background-color: #007bff; }\\nprogress.primary::-moz-progress-bar { background-color: #007bff; }\\n\\nprogress.secondary[value]::-webkit-progress-value { background-color: #6c757d; }\\nprogress.secondary:not([value])::before { background-color: #6c757d; }\\nprogress.secondary:not([value])::-webkit-progress-bar { background-color: #6c757d; }\\nprogress.secondary::-moz-progress-bar { background-color: #6c757d; }\\n\\nprogress.success[value]::-webkit-progress-value { background-color: #28a745; }\\nprogress.success:not([value])::before { background-color: #28a745; }\\nprogress.success:not([value])::-webkit-progress-bar { background-color: #28a745; }\\nprogress.success::-moz-progress-bar { background-color: #28a745; }\\n\\nprogress.danger[value]::-webkit-progress-value { background-color: #dc3545; }\\nprogress.danger:not([value])::before { background-color: #dc3545; }\\nprogress.danger:not([value])::-webkit-progress-bar { background-color: #dc3545; }\\nprogress.danger::-moz-progress-bar { background-color: #dc3545; }\\n\\nprogress.warning[value]::-webkit-progress-value { background-color: #ffc107; }\\nprogress.warning:not([value])::before { background-color: #ffc107; }\\nprogress.warning:not([value])::-webkit-progress-bar { background-color: #ffc107; }\\nprogress.warning::-moz-progress-bar { background-color: #ffc107; }\\n\\nprogress.info[value]::-webkit-progress-value { background-color: #17a2b8; }\\nprogress.info:not([value])::before { background-color: #17a2b8; }\\nprogress.info:not([value])::-webkit-progress-bar { background-color: #17a2b8; }\\nprogress.info::-moz-progress-bar { background-color: #17a2b8; }\\n\\nprogress.light[value]::-webkit-progress-value { background-color: #f8f9fa; }\\nprogress.light:not([value])::before { background-color: #f8f9fa; }\\nprogress.light:not([value])::-webkit-progress-bar { background-color: #f8f9fa; }\\nprogress.light::-moz-progress-bar { background-color: #f8f9fa; }\\n\\nprogress.dark[value]::-webkit-progress-value { background-color: #343a40; }\\nprogress.dark:not([value])::-webkit-progress-bar { background-color: #343a40; }\\nprogress.dark:not([value])::before { background-color: #343a40; }\\nprogress.dark::-moz-progress-bar { background-color: #343a40; }\\n\\nprogress:not([value])::-webkit-progress-bar {\\n border-radius: 3px;\\n background: linear-gradient(-45deg, transparent 33%, rgba(0, 0, 0, 0.2) 33%, rgba(0, 0, 0, 0.2) 66%, transparent 66%) left/2.5em 1.5em;\\n}\\nprogress:not([value])::before {\\n content:\\\" \\\";\\n position:absolute;\\n height: 20px;\\n top:0;\\n left:0;\\n right:0;\\n bottom:0;\\n border-radius: 3px;\\n background: linear-gradient(-45deg, transparent 33%, rgba(0, 0, 0, 0.2) 33%, rgba(0, 0, 0, 0.2) 66%, transparent 66%) left/2.5em 1.5em;\\n}\\n\\n@keyframes stripes {\\n from {background-position: 0%}\\n to {background-position: 100%}\\n}\\n\\n.bk-root .bk.loader {\\n overflow: hidden;\\n}\\n\\n.bk.loader::after {\\n content: \\\"\\\";\\n border-radius: 50%;\\n -webkit-mask-image: radial-gradient(transparent 50%, rgba(0, 0, 0, 1) 54%);\\n width: 100%;\\n height: 100%;\\n left: 0;\\n top: 0;\\n position: absolute;\\n}\\n\\n.bk-root .bk.loader.dark::after {\\n background: #0f0f0f;\\n}\\n\\n.bk-root .bk.loader.light::after {\\n background: #f0f0f0;\\n}\\n\\n.bk-root .bk.loader.spin::after {\\n animation: spin 2s linear infinite;\\n}\\n\\n.bk-root div.bk.loader.spin.primary-light::after {\\n background: linear-gradient(135deg, #f0f0f0 50%, transparent 50%), linear-gradient(45deg, #f0f0f0 50%, #007bff 50%);\\n}\\n\\n.bk-root div.bk.loader.spin.secondary-light::after {\\n background: linear-gradient(135deg, #f0f0f0 50%, transparent 50%), linear-gradient(45deg, #f0f0f0 50%, #6c757d 50%);\\n}\\n\\n.bk-root div.bk.loader.spin.success-light::after {\\n background: linear-gradient(135deg, #f0f0f0 50%, transparent 50%), linear-gradient(45deg, #f0f0f0 50%, #28a745 50%);\\n}\\n\\n.bk-root div.bk.loader.spin.danger-light::after {\\n background: linear-gradient(135deg, #f0f0f0 50%, transparent 50%), linear-gradient(45deg, #f0f0f0 50%, #dc3545 50%);\\n}\\n\\n.bk-root div.bk.loader.spin.warning-light::after {\\n background: linear-gradient(135deg, #f0f0f0 50%, transparent 50%), linear-gradient(45deg, #f0f0f0 50%, #ffc107 50%);\\n}\\n\\n.bk-root div.bk.loader.spin.info-light::after {\\n background: linear-gradient(135deg, #f0f0f0 50%, transparent 50%), linear-gradient(45deg, #f0f0f0 50%, #17a2b8 50%);\\n}\\n\\n.bk-root div.bk.loader.spin.light-light::after {\\n background: linear-gradient(135deg, #f0f0f0 50%, transparent 50%), linear-gradient(45deg, #f0f0f0 50%, #f8f9fa 50%);\\n}\\n\\n.bk-root div.bk.loader.dark-light::after {\\n background: linear-gradient(135deg, #f0f0f0 50%, transparent 50%), linear-gradient(45deg, #f0f0f0 50%, #343a40 50%);\\n}\\n\\n.bk-root div.bk.loader.spin.primary-dark::after {\\n background: linear-gradient(135deg, #0f0f0f 50%, transparent 50%), linear-gradient(45deg, #0f0f0f 50%, #007bff 50%);\\n}\\n\\n.bk-root div.bk.loader.spin.secondary-dark::after {\\n background: linear-gradient(135deg, #0f0f0f 50%, transparent 50%), linear-gradient(45deg, #0f0f0f 50%, #6c757d 50%);\\n}\\n\\n.bk-root div.bk.loader.spin.success-dark::after {\\n background: linear-gradient(135deg, #0f0f0f 50%, transparent 50%), linear-gradient(45deg, #0f0f0f 50%, #28a745 50%);\\n}\\n\\n.bk-root div.bk.loader.spin.danger-dark::after {\\n background: linear-gradient(135deg, #0f0f0f 50%, transparent 50%), linear-gradient(45deg, #0f0f0f 50%, #dc3545 50%)\\n}\\n\\n.bk-root div.bk.loader.spin.warning-dark::after {\\n background: linear-gradient(135deg, #0f0f0f 50%, transparent 50%), linear-gradient(45deg, #0f0f0f 50%, #ffc107 50%);\\n}\\n\\n.bk-root div.bk.loader.spin.info-dark::after {\\n background: linear-gradient(135deg, #0f0f0f 50%, transparent 50%), linear-gradient(45deg, #0f0f0f 50%, #17a2b8 50%);\\n}\\n\\n.bk-root div.bk.loader.spin.light-dark::after {\\n background: linear-gradient(135deg, #0f0f0f 50%, transparent 50%), linear-gradient(45deg, #0f0f0f 50%, #f8f9fa 50%);\\n}\\n\\n.bk-root div.bk.loader.spin.dark-dark::after {\\n background: linear-gradient(135deg, #0f0f0f 50%, transparent 50%), linear-gradient(45deg, #0f0f0f 50%, #343a40 50%);\\n}\\n\\n/* Safari */\\n@-webkit-keyframes spin {\\n 0% { -webkit-transform: rotate(0deg); }\\n 100% { -webkit-transform: rotate(360deg); }\\n}\\n\\n@keyframes spin {\\n 0% { transform: rotate(0deg); }\\n 100% { transform: rotate(360deg); }\\n}\\n\\n.dot div {\\n height: 100%;\\n width: 100%;\\n border: 1px solid #000 !important;\\n background-color: #fff;\\n border-radius: 50%;\\n display: inline-block;\\n}\\n\\n.dot-filled div {\\n height: 100%;\\n width: 100%;\\n border: 1px solid #000 !important;\\n border-radius: 50%;\\n display: inline-block;\\n}\\n\\n.dot-filled.primary div {\\n background-color: #007bff;\\n}\\n\\n.dot-filled.secondary div {\\n background-color: #6c757d;\\n}\\n\\n.dot-filled.success div {\\n background-color: #28a745;\\n}\\n\\n.dot-filled.danger div {\\n background-color: #dc3545;\\n}\\n\\n.dot-filled.warning div {\\n background-color: #ffc107;\\n}\\n\\n.dot-filled.info div {\\n background-color: #17a2b8;\\n}\\n\\n.dot-filled.dark div {\\n background-color: #343a40;\\n}\\n\\n.dot-filled.light div {\\n background-color: #f8f9fa;\\n}\\n\\n/* Slider editor */\\n.slider-edit .bk-input-group .bk-input {\\n border: 0;\\n border-radius: 0;\\n min-height: 0;\\n padding-left: 0;\\n padding-right: 0;\\n font-weight: bold;\\n}\\n\\n.slider-edit .bk-input-group .bk-spin-wrapper {\\n display: contents;\\n}\\n\\n.slider-edit .bk-input-group .bk-spin-wrapper .bk.bk-spin-btn-up {\\n top: -6px;\\n}\\n\\n.slider-edit .bk-input-group .bk-spin-wrapper .bk.bk-spin-btn-down {\\n bottom: 3px;\\n}\\n\\n/* JSON Pane */\\n.bk-root .json-formatter-row .json-formatter-string, .bk-root .json-formatter-row .json-formatter-stringifiable {\\n white-space: pre-wrap;\\n}\\n\\n.ql-bubble .ql-editor {\\n border: 1px solid #ccc;\\n}\\n\");\n }, function(Bokeh) {\n inject_raw_css(\"table.panel-df {\\n margin-left: auto;\\n margin-right: auto;\\n border: none;\\n border-collapse: collapse;\\n border-spacing: 0;\\n color: black;\\n font-size: 12px;\\n table-layout: fixed;\\n width: 100%;\\n}\\n\\n.panel-df tr, .panel-df th, .panel-df td {\\n text-align: right;\\n vertical-align: middle;\\n padding: 0.5em 0.5em !important;\\n line-height: normal;\\n white-space: normal;\\n max-width: none;\\n border: none;\\n}\\n\\n.panel-df tbody {\\n display: table-row-group;\\n vertical-align: middle;\\n border-color: inherit;\\n}\\n\\n.panel-df tbody tr:nth-child(odd) {\\n background: #f5f5f5;\\n}\\n\\n.panel-df thead {\\n border-bottom: 1px solid black;\\n vertical-align: bottom;\\n}\\n\\n.panel-df tr:hover {\\n background: lightblue !important;\\n cursor: pointer;\\n}\\n\");\n }, function(Bokeh) {\n inject_raw_css(\".bk.debugger-card {\\n border: 1px solid rgba(0,0,0,1);\\n color: rgba(255,255,255,1);\\n background-color: rgba(0,0,0,1);\\n border-radius: 0rem;\\n}\\n.bk.debugger-card-header {\\n align-items: center;\\n text-align: left;\\n background-color: rgba(0, 0, 0, 1)!important;\\n color: rgba(255, 255, 255, 1);\\n border-radius: 0rem;\\n display: inline-flex;\\n justify-content: start;\\n width: 100%;\\n}\\n.bk.debugger-card-button {\\n background-color: transparent;\\n color: rgba(255, 255, 255, 1);\\n margin-left: 0.5em;\\n}\\n.bk.debugger-card-title {\\n align-items: center;\\n text-align: left;\\n color: rgba(255, 255, 255, 1);\\n font-size: 1em;\\n overflow-wrap: break-word;\\n}\\n\\n/* Special debugger buttons for clearing and saving */\\n.bk button.special_btn {\\n width: 25px;\\n height: 25px;\\n background-color: black;\\n color: white;\\n display: inline-block;\\n}\\n\\n\\n.bk button.special_btn .tooltiptext {\\n visibility: hidden;\\n width: 100px;\\n background-color: darkgray;\\n color: #fff;\\n text-align: center;\\n border-radius: 6px;\\n padding: 5px 0;\\n\\n /* Position the tooltip */\\n position: relative;\\n z-index: 1;\\n top: 100%;\\n left: 100%;\\n margin-left: -100px;\\n display: block;\\n}\\n\\n.bk button.special_btn:hover .tooltiptext {\\n visibility: visible;\\n}\\n\\n\\n\\n.bk button.clear_btn:hover .shown { display: none;}\\n.bk button.clear_btn:hover:before { content: \\\"\\u2611\\\"; }\\n\");\n }, function(Bokeh) {\n inject_raw_css(\".bk.pn-loading:before {\\n position: absolute;\\n height: 100%;\\n width: 100%;\\n content: '';\\n z-index: 1000;\\n background-color: rgb(255,255,255,0.50);\\n border-color: lightgray;\\n background-repeat: no-repeat;\\n background-position: center;\\n background-size: auto 50%;\\n border-width: 1px;\\n cursor: progress;\\n}\\n.bk.pn-loading.arcs:hover:before {\\n cursor: progress;\\n}\\n\");\n }, function(Bokeh) {\n inject_raw_css(\".bk.alert {\\n padding: 0.75rem 1.25rem;\\n border: 1px solid transparent;\\n border-radius: 0.25rem;\\n /* Don't set margin because that will not render correctly! */\\n /* margin-bottom: 1rem; */\\n margin-top: 15px;\\n margin-bottom: 15px;\\n}\\n.bk.alert a {\\n color: rgb(11, 46, 19); /* #002752; */\\n font-weight: 700;\\n text-decoration: rgb(11, 46, 19);\\n text-decoration-color: rgb(11, 46, 19);\\n text-decoration-line: none;\\n text-decoration-style: solid;\\n text-decoration-thickness: auto;\\n }\\n.bk.alert a:hover {\\n color: rgb(11, 46, 19);\\n font-weight: 700;\\n text-decoration: underline;\\n}\\n\\n.bk.alert-primary {\\n color: #004085;\\n background-color: #cce5ff;\\n border-color: #b8daff;\\n}\\n.bk.alert-primary hr {\\n border-top-color: #9fcdff;\\n}\\n\\n.bk.alert-secondary {\\n color: #383d41;\\n background-color: #e2e3e5;\\n border-color: #d6d8db;\\n }\\n.bk.alert-secondary hr {\\n border-top-color: #c8cbcf;\\n}\\n\\n.bk.alert-success {\\n color: #155724;\\n background-color: #d4edda;\\n border-color: #c3e6cb;\\n }\\n\\n.bk.alert-success hr {\\n border-top-color: #b1dfbb;\\n}\\n\\n.bk.alert-info {\\n color: #0c5460;\\n background-color: #d1ecf1;\\n border-color: #bee5eb;\\n }\\n.bk.alert-info hr {\\n border-top-color: #abdde5;\\n}\\n\\n.bk.alert-warning {\\n color: #856404;\\n background-color: #fff3cd;\\n border-color: #ffeeba;\\n }\\n\\n.bk.alert-warning hr {\\n border-top-color: #ffe8a1;\\n}\\n\\n.bk.alert-danger {\\n color: #721c24;\\n background-color: #f8d7da;\\n border-color: #f5c6cb;\\n}\\n.bk.alert-danger hr {\\n border-top-color: #f1b0b7;\\n}\\n\\n.bk.alert-light {\\n color: #818182;\\n background-color: #fefefe;\\n border-color: #fdfdfe;\\n }\\n.bk.alert-light hr {\\n border-top-color: #ececf6;\\n}\\n\\n.bk.alert-dark {\\n color: #1b1e21;\\n background-color: #d6d8d9;\\n border-color: #c6c8ca;\\n }\\n.bk.alert-dark hr {\\n border-top-color: #b9bbbe;\\n}\\n\\n\\n/* adjf\\u00e6l */\\n\\n.bk.alert-primary a {\\n color: #002752;\\n}\\n\\n.bk.alert-secondary a {\\n color: #202326;\\n}\\n\\n\\n.bk.alert-success a {\\n color: #0b2e13;\\n}\\n\\n\\n.bk.alert-info a {\\n color: #062c33;\\n}\\n\\n\\n.bk.alert-warning a {\\n color: #533f03;\\n}\\n\\n\\n.bk.alert-danger a {\\n color: #491217;\\n}\\n\\n.bk.alert-light a {\\n color: #686868;\\n}\\n\\n.bk.alert-dark a {\\n color: #040505;\\n}\\n\");\n }, function(Bokeh) {\n inject_raw_css(\".json-formatter-row {\\n font-family: monospace;\\n}\\n.json-formatter-row,\\n.json-formatter-row a,\\n.json-formatter-row a:hover {\\n color: black;\\n text-decoration: none;\\n}\\n.json-formatter-row .json-formatter-row {\\n margin-left: 1rem;\\n}\\n.json-formatter-row .json-formatter-children.json-formatter-empty {\\n opacity: 0.5;\\n margin-left: 1rem;\\n}\\n.json-formatter-row .json-formatter-children.json-formatter-empty:after {\\n display: none;\\n}\\n.json-formatter-row .json-formatter-children.json-formatter-empty.json-formatter-object:after {\\n content: \\\"No properties\\\";\\n}\\n.json-formatter-row .json-formatter-children.json-formatter-empty.json-formatter-array:after {\\n content: \\\"[]\\\";\\n}\\n.json-formatter-row .json-formatter-string,\\n.json-formatter-row .json-formatter-stringifiable {\\n color: green;\\n white-space: pre;\\n word-wrap: break-word;\\n}\\n.json-formatter-row .json-formatter-number {\\n color: blue;\\n}\\n.json-formatter-row .json-formatter-boolean {\\n color: red;\\n}\\n.json-formatter-row .json-formatter-null {\\n color: #855A00;\\n}\\n.json-formatter-row .json-formatter-undefined {\\n color: #ca0b69;\\n}\\n.json-formatter-row .json-formatter-function {\\n color: #FF20ED;\\n}\\n.json-formatter-row .json-formatter-date {\\n background-color: rgba(0, 0, 0, 0.05);\\n}\\n.json-formatter-row .json-formatter-url {\\n text-decoration: underline;\\n color: blue;\\n cursor: pointer;\\n}\\n.json-formatter-row .json-formatter-bracket {\\n color: blue;\\n}\\n.json-formatter-row .json-formatter-key {\\n color: #00008B;\\n padding-right: 0.2rem;\\n}\\n.json-formatter-row .json-formatter-toggler-link {\\n cursor: pointer;\\n}\\n.json-formatter-row .json-formatter-toggler {\\n line-height: 1.2rem;\\n font-size: 0.7rem;\\n vertical-align: middle;\\n opacity: 0.6;\\n cursor: pointer;\\n padding-right: 0.2rem;\\n}\\n.json-formatter-row .json-formatter-toggler:after {\\n display: inline-block;\\n transition: transform 100ms ease-in;\\n content: \\\"\\\\25BA\\\";\\n}\\n.json-formatter-row > a > .json-formatter-preview-text {\\n opacity: 0;\\n transition: opacity 0.15s ease-in;\\n font-style: italic;\\n}\\n.json-formatter-row:hover > a > .json-formatter-preview-text {\\n opacity: 0.6;\\n}\\n.json-formatter-row.json-formatter-open > .json-formatter-toggler-link .json-formatter-toggler:after {\\n transform: rotate(90deg);\\n}\\n.json-formatter-row.json-formatter-open > .json-formatter-children:after {\\n display: inline-block;\\n}\\n.json-formatter-row.json-formatter-open > a > .json-formatter-preview-text {\\n display: none;\\n}\\n.json-formatter-row.json-formatter-open.json-formatter-empty:after {\\n display: block;\\n}\\n.json-formatter-dark.json-formatter-row {\\n font-family: monospace;\\n}\\n.json-formatter-dark.json-formatter-row,\\n.json-formatter-dark.json-formatter-row a,\\n.json-formatter-dark.json-formatter-row a:hover {\\n color: white;\\n text-decoration: none;\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-row {\\n margin-left: 1rem;\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-children.json-formatter-empty {\\n opacity: 0.5;\\n margin-left: 1rem;\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-children.json-formatter-empty:after {\\n display: none;\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-children.json-formatter-empty.json-formatter-object:after {\\n content: \\\"No properties\\\";\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-children.json-formatter-empty.json-formatter-array:after {\\n content: \\\"[]\\\";\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-string,\\n.json-formatter-dark.json-formatter-row .json-formatter-stringifiable {\\n color: #31F031;\\n white-space: pre;\\n word-wrap: break-word;\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-number {\\n color: #66C2FF;\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-boolean {\\n color: #EC4242;\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-null {\\n color: #EEC97D;\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-undefined {\\n color: #ef8fbe;\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-function {\\n color: #FD48CB;\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-date {\\n background-color: rgba(255, 255, 255, 0.05);\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-url {\\n text-decoration: underline;\\n color: #027BFF;\\n cursor: pointer;\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-bracket {\\n color: #9494FF;\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-key {\\n color: #23A0DB;\\n padding-right: 0.2rem;\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-toggler-link {\\n cursor: pointer;\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-toggler {\\n line-height: 1.2rem;\\n font-size: 0.7rem;\\n vertical-align: middle;\\n opacity: 0.6;\\n cursor: pointer;\\n padding-right: 0.2rem;\\n}\\n.json-formatter-dark.json-formatter-row .json-formatter-toggler:after {\\n display: inline-block;\\n transition: transform 100ms ease-in;\\n content: \\\"\\\\25BA\\\";\\n}\\n.json-formatter-dark.json-formatter-row > a > .json-formatter-preview-text {\\n opacity: 0;\\n transition: opacity 0.15s ease-in;\\n font-style: italic;\\n}\\n.json-formatter-dark.json-formatter-row:hover > a > .json-formatter-preview-text {\\n opacity: 0.6;\\n}\\n.json-formatter-dark.json-formatter-row.json-formatter-open > .json-formatter-toggler-link .json-formatter-toggler:after {\\n transform: rotate(90deg);\\n}\\n.json-formatter-dark.json-formatter-row.json-formatter-open > .json-formatter-children:after {\\n display: inline-block;\\n}\\n.json-formatter-dark.json-formatter-row.json-formatter-open > a > .json-formatter-preview-text {\\n display: none;\\n}\\n.json-formatter-dark.json-formatter-row.json-formatter-open.json-formatter-empty:after {\\n display: block;\\n}\\n\");\n }, function(Bokeh) {\n inject_raw_css(\"\\n .bk.pn-loading.arcs:before {\\n background-image: url(\\\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBzdHlsZT0ibWFyZ2luOiBhdXRvOyBiYWNrZ3JvdW5kOiBub25lOyBkaXNwbGF5OiBibG9jazsgc2hhcGUtcmVuZGVyaW5nOiBhdXRvOyIgdmlld0JveD0iMCAwIDEwMCAxMDAiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIj4gIDxjaXJjbGUgY3g9IjUwIiBjeT0iNTAiIHI9IjMyIiBzdHJva2Utd2lkdGg9IjgiIHN0cm9rZT0iI2MzYzNjMyIgc3Ryb2tlLWRhc2hhcnJheT0iNTAuMjY1NDgyNDU3NDM2NjkgNTAuMjY1NDgyNDU3NDM2NjkiIGZpbGw9Im5vbmUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCI+ICAgIDxhbmltYXRlVHJhbnNmb3JtIGF0dHJpYnV0ZU5hbWU9InRyYW5zZm9ybSIgdHlwZT0icm90YXRlIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgZHVyPSIxcyIga2V5VGltZXM9IjA7MSIgdmFsdWVzPSIwIDUwIDUwOzM2MCA1MCA1MCI+PC9hbmltYXRlVHJhbnNmb3JtPiAgPC9jaXJjbGU+PC9zdmc+\\\");\\n background-size: auto calc(min(50%, 400px));\\n }\\n \");\n }, function(Bokeh) {\n /* BEGIN bokeh.min.js */\n /*!\n * Copyright (c) 2012 - 2022, Anaconda, Inc., and Bokeh Contributors\n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n * \n * Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n * \n * Neither the name of Anaconda nor the names of any contributors\n * may be used to endorse or promote products derived from this software\n * without specific prior written permission.\n * \n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n * THE POSSIBILITY OF SUCH DAMAGE.\n */\n (function(root, factory) {\n const bokeh = factory();\n bokeh.__bokeh__ = true;\n if (typeof root.Bokeh === \"undefined\" || typeof root.Bokeh.__bokeh__ === \"undefined\") {\n root.Bokeh = bokeh;\n }\n const Bokeh = root.Bokeh;\n Bokeh[bokeh.version] = bokeh;\n })(this, function() {\n let define;\n const parent_require = typeof require === \"function\" && require\n return (function(modules, entry, aliases, externals) {\n if (aliases === undefined) aliases = {};\n if (externals === undefined) externals = {};\n\n const cache = {};\n\n const normalize = function(name) {\n if (typeof name === \"number\")\n return name;\n\n if (name === \"bokehjs\")\n return entry;\n\n if (!externals[name]) {\n const prefix = \"@bokehjs/\"\n if (name.slice(0, prefix.length) === prefix)\n name = name.slice(prefix.length)\n }\n\n const alias = aliases[name]\n if (alias != null)\n return alias;\n\n const trailing = name.length > 0 && name[name.lenght-1] === \"/\";\n const index = aliases[name + (trailing ? \"\" : \"/\") + \"index\"];\n if (index != null)\n return index;\n\n return name;\n }\n\n const require = function(name) {\n let mod = cache[name];\n if (!mod) {\n const id = normalize(name);\n\n mod = cache[id];\n if (!mod) {\n if (!modules[id]) {\n if (externals[id] === false || (externals[id] == true && parent_require)) {\n try {\n mod = {exports: externals[id] ? parent_require(id) : {}};\n cache[id] = cache[name] = mod;\n return mod.exports;\n } catch (e) {}\n }\n\n const err = new Error(\"Cannot find module '\" + name + \"'\");\n err.code = 'MODULE_NOT_FOUND';\n throw err;\n }\n\n mod = {exports: {}};\n cache[id] = cache[name] = mod;\n\n function __esModule() {\n Object.defineProperty(mod.exports, \"__esModule\", {value: true});\n }\n\n function __esExport(name, value) {\n Object.defineProperty(mod.exports, name, {\n enumerable: true, get: function () { return value; }\n });\n }\n\n modules[id].call(mod.exports, require, mod, mod.exports, __esModule, __esExport);\n } else {\n cache[name] = mod;\n }\n }\n\n return mod.exports;\n }\n require.resolve = function(name) {\n return \"\"\n }\n\n const main = require(entry);\n main.require = require;\n\n if (typeof Proxy !== \"undefined\") {\n // allow Bokeh.loader[\"@bokehjs/module/name\"] syntax\n main.loader = new Proxy({}, {\n get: function(_obj, module) {\n return require(module);\n }\n });\n }\n\n main.register_plugin = function(plugin_modules, plugin_entry, plugin_aliases, plugin_externals) {\n if (plugin_aliases === undefined) plugin_aliases = {};\n if (plugin_externals === undefined) plugin_externals = {};\n\n for (let name in plugin_modules) {\n modules[name] = plugin_modules[name];\n }\n\n for (let name in plugin_aliases) {\n aliases[name] = plugin_aliases[name];\n }\n\n for (let name in plugin_externals) {\n externals[name] = plugin_externals[name];\n }\n\n const plugin = require(plugin_entry);\n\n for (let name in plugin) {\n main[name] = plugin[name];\n }\n\n return plugin;\n }\n\n return main;\n })\n ([\n function _(t,_,n,o,r){o();(0,t(1).__exportStar)(t(2),n)},\n function _(t,e,r,n,o){n();var a=function(t,e){return a=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])},a(t,e)};r.__extends=function(t,e){if(\"function\"!=typeof e&&null!==e)throw new TypeError(\"Class extends value \"+String(e)+\" is not a constructor or null\");function r(){this.constructor=t}a(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)};function i(t){var e=\"function\"==typeof Symbol&&Symbol.iterator,r=e&&t[e],n=0;if(r)return r.call(t);if(t&&\"number\"==typeof t.length)return{next:function(){return t&&n>=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?\"Object is not iterable.\":\"Symbol.iterator is not defined.\")}function c(t,e){var r=\"function\"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var n,o,a=r.call(t),i=[];try{for(;(void 0===e||e-- >0)&&!(n=a.next()).done;)i.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=a.return)&&r.call(a)}finally{if(o)throw o.error}}return i}function u(t){return this instanceof u?(this.v=t,this):new u(t)}r.__assign=function(){return r.__assign=Object.assign||function(t){for(var e,r=1,n=arguments.length;r=0;c--)(o=t[c])&&(i=(a<3?o(i):a>3?o(e,r,i):o(e,r))||i);return a>3&&i&&Object.defineProperty(e,r,i),i},r.__param=function(t,e){return function(r,n){e(r,n,t)}},r.__metadata=function(t,e){if(\"object\"==typeof Reflect&&\"function\"==typeof Reflect.metadata)return Reflect.metadata(t,e)},r.__awaiter=function(t,e,r,n){return new(r||(r=Promise))((function(o,a){function i(t){try{u(n.next(t))}catch(t){a(t)}}function c(t){try{u(n.throw(t))}catch(t){a(t)}}function u(t){var e;t.done?o(t.value):(e=t.value,e instanceof r?e:new r((function(t){t(e)}))).then(i,c)}u((n=n.apply(t,e||[])).next())}))},r.__generator=function(t,e){var r,n,o,a,i={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return a={next:c(0),throw:c(1),return:c(2)},\"function\"==typeof Symbol&&(a[Symbol.iterator]=function(){return this}),a;function c(a){return function(c){return function(a){if(r)throw new TypeError(\"Generator is already executing.\");for(;i;)try{if(r=1,n&&(o=2&a[0]?n.return:a[0]?n.throw||((o=n.return)&&o.call(n),0):n.next)&&!(o=o.call(n,a[1])).done)return o;switch(n=0,o&&(a=[2&a[0],o.value]),a[0]){case 0:case 1:o=a;break;case 4:return i.label++,{value:a[1],done:!1};case 5:i.label++,n=a[1],a=[0];continue;case 7:a=i.ops.pop(),i.trys.pop();continue;default:if(!(o=i.trys,(o=o.length>0&&o[o.length-1])||6!==a[0]&&2!==a[0])){i=0;continue}if(3===a[0]&&(!o||a[1]>o[0]&&a[1]1||c(t,e)}))})}function c(t,e){try{(r=o[t](e)).value instanceof u?Promise.resolve(r.value.v).then(f,l):s(a[0][2],r)}catch(t){s(a[0][3],t)}var r}function f(t){c(\"next\",t)}function l(t){c(\"throw\",t)}function s(t,e){t(e),a.shift(),a.length&&c(a[0][0],a[0][1])}},r.__asyncDelegator=function(t){var e,r;return e={},n(\"next\"),n(\"throw\",(function(t){throw t})),n(\"return\"),e[Symbol.iterator]=function(){return this},e;function n(n,o){e[n]=t[n]?function(e){return(r=!r)?{value:u(t[n](e)),done:\"return\"===n}:o?o(e):e}:o}},r.__asyncValues=function(t){if(!Symbol.asyncIterator)throw new TypeError(\"Symbol.asyncIterator is not defined.\");var e,r=t[Symbol.asyncIterator];return r?r.call(t):(t=i(t),e={},n(\"next\"),n(\"throw\"),n(\"return\"),e[Symbol.asyncIterator]=function(){return this},e);function n(r){e[r]=t[r]&&function(e){return new Promise((function(n,o){(function(t,e,r,n){Promise.resolve(n).then((function(e){t({value:e,done:r})}),e)})(n,o,(e=t[r](e)).done,e.value)}))}}},r.__makeTemplateObject=function(t,e){return Object.defineProperty?Object.defineProperty(t,\"raw\",{value:e}):t.raw=e,t};var f=Object.create?function(t,e){Object.defineProperty(t,\"default\",{enumerable:!0,value:e})}:function(t,e){t.default=e};r.__importStar=function(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var n in t)\"default\"!==n&&Object.prototype.hasOwnProperty.call(t,n)&&(0,r.__createBinding)(e,t,n);return f(e,t),e},r.__importDefault=function(t){return t&&t.__esModule?t:{default:t}},r.__classPrivateFieldGet=function(t,e,r,n){if(\"a\"===r&&!n)throw new TypeError(\"Private accessor was defined without a getter\");if(\"function\"==typeof e?t!==e||!n:!e.has(t))throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");return\"m\"===r?n:\"a\"===r?n.call(t):n?n.value:e.get(t)},r.__classPrivateFieldSet=function(t,e,r,n,o){if(\"m\"===n)throw new TypeError(\"Private method is not writable\");if(\"a\"===n&&!o)throw new TypeError(\"Private accessor was defined without a setter\");if(\"function\"==typeof e?t!==e||!o:!e.has(t))throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");return\"a\"===n?o.call(t,r):o?o.value=r:e.set(t,r),r}},\n function _(e,t,o,s,l){s();const n=e(1);l(\"version\",e(3).version),l(\"index\",e(4).index),o.embed=(0,n.__importStar)(e(4)),o.protocol=(0,n.__importStar)(e(406)),o._testing=(0,n.__importStar)(e(407));var r=e(19);l(\"logger\",r.logger),l(\"set_log_level\",r.set_log_level),l(\"settings\",e(28).settings),l(\"Models\",e(7).Models),l(\"documents\",e(5).documents),l(\"safely\",e(408).safely)},\n function _(n,i,o,c,e){c(),o.version=\"2.4.3\"},\n function _(e,o,t,n,s){n();const d=e(5),r=e(19),_=e(34),c=e(13),i=e(8),a=e(16),u=e(397),l=e(399),m=e(398);var f=e(397);s(\"add_document_standalone\",f.add_document_standalone),s(\"index\",f.index),s(\"add_document_from_session\",e(399).add_document_from_session);var g=e(404);async function w(e,o,t,n){(0,i.isString)(e)&&(e=JSON.parse((0,_.unescape)(e)));const s={};for(const[o,t]of(0,c.entries)(e))s[o]=d.Document.from_json(t);const a=[];for(const e of o){const o=(0,m._resolve_element)(e),d=(0,m._resolve_root_elements)(e);if(null!=e.docid)a.push(await(0,u.add_document_standalone)(s[e.docid],o,d,e.use_for_title));else{if(null==e.token)throw new Error(\"Error rendering Bokeh items: either 'docid' or 'token' was expected.\");{const s=(0,l._get_ws_url)(t,n);r.logger.debug(`embed: computed ws url: ${s}`);try{a.push(await(0,l.add_document_from_session)(s,e.token,o,d,e.use_for_title)),console.log(\"Bokeh items were rendered successfully\")}catch(e){console.log(\"Error rendering Bokeh items:\",e)}}}}return a}s(\"embed_items_notebook\",g.embed_items_notebook),s(\"kernels\",g.kernels),s(\"BOKEH_ROOT\",e(398).BOKEH_ROOT),t.embed_item=async function(e,o){const t={},n=(0,_.uuid4)();t[n]=e.doc,null==o&&(o=e.target_id);const s=document.getElementById(o);null!=s&&s.classList.add(m.BOKEH_ROOT);const d={roots:{[e.root_id]:o},root_ids:[e.root_id],docid:n};await(0,a.defer)();const[r]=await w(t,[d]);return r},t.embed_items=async function(e,o,t,n){return await(0,a.defer)(),w(e,o,t,n)}},\n function _(t,_,o,r,n){r();const a=t(1);(0,a.__exportStar)(t(6),o),(0,a.__exportStar)(t(35),o)},\n function _(e,t,s,o,n){o();const i=e(1),r=e(7),l=e(3),_=e(19),a=e(251),c=e(14),d=e(30),h=e(15),f=e(17),u=e(31),m=e(29),g=e(9),v=e(13),p=(0,i.__importStar)(e(77)),w=e(26),b=e(8),y=e(309),k=e(75),M=e(53),j=e(396),z=e(35);class S{constructor(e){this.document=e,this.session=null,this.subscribed_models=new Set}send_event(e){const t=new z.MessageSentEvent(this.document,\"bokeh_event\",e.to_json());this.document._trigger_on_change(t)}trigger(e){for(const t of this.subscribed_models)null!=e.origin&&e.origin!=t||t._process_event(e)}}s.EventManager=S,S.__name__=\"EventManager\",s.documents=[],s.DEFAULT_TITLE=\"Bokeh Application\";class E{constructor(e){var t;s.documents.push(this),this._init_timestamp=Date.now(),this._resolver=null!==(t=null==e?void 0:e.resolver)&&void 0!==t?t:new r.ModelResolver,this._title=s.DEFAULT_TITLE,this._roots=[],this._all_models=new Map,this._all_models_freeze_count=0,this._callbacks=new Map,this._message_callbacks=new Map,this.event_manager=new S(this),this.idle=new h.Signal0(this,\"idle\"),this._idle_roots=new WeakMap,this._interactive_timestamp=null,this._interactive_plot=null}get layoutables(){return this._roots.filter((e=>e instanceof y.LayoutDOM))}get is_idle(){for(const e of this.layoutables)if(!this._idle_roots.has(e))return!1;return!0}notify_idle(e){this._idle_roots.set(e,!0),this.is_idle&&(_.logger.info(`document idle at ${Date.now()-this._init_timestamp} ms`),this.event_manager.send_event(new a.DocumentReady),this.idle.emit())}clear(){this._push_all_models_freeze();try{for(;this._roots.length>0;)this.remove_root(this._roots[0])}finally{this._pop_all_models_freeze()}}interactive_start(e,t=null){null==this._interactive_plot&&(this._interactive_plot=e,this._interactive_plot.trigger_event(new a.LODStart)),this._interactive_finalize=t,this._interactive_timestamp=Date.now()}interactive_stop(){null!=this._interactive_plot&&(this._interactive_plot.trigger_event(new a.LODEnd),null!=this._interactive_finalize&&this._interactive_finalize()),this._interactive_plot=null,this._interactive_timestamp=null,this._interactive_finalize=null}interactive_duration(){return null==this._interactive_timestamp?-1:Date.now()-this._interactive_timestamp}destructively_move(e){if(e===this)throw new Error(\"Attempted to overwrite a document with itself\");e.clear();const t=(0,g.copy)(this._roots);this.clear();for(const e of t)if(null!=e.document)throw new Error(`Somehow we didn't detach ${e}`);if(0!=this._all_models.size)throw new Error(`this._all_models still had stuff in it: ${this._all_models}`);for(const s of t)e.add_root(s);e.set_title(this._title)}_push_all_models_freeze(){this._all_models_freeze_count+=1}_pop_all_models_freeze(){this._all_models_freeze_count-=1,0===this._all_models_freeze_count&&this._recompute_all_models()}_invalidate_all_models(){_.logger.debug(\"invalidating document models\"),0===this._all_models_freeze_count&&this._recompute_all_models()}_recompute_all_models(){let e=new Set;for(const t of this._roots)e=p.union(e,t.references());const t=new Set(this._all_models.values()),s=p.difference(t,e),o=p.difference(e,t),n=new Map;for(const t of e)n.set(t.id,t);for(const e of s)e.detach_document();for(const e of o)e.attach_document(this);this._all_models=n}roots(){return this._roots}add_root(e,t){if(_.logger.debug(`Adding root: ${e}`),!(0,g.includes)(this._roots,e)){this._push_all_models_freeze();try{this._roots.push(e)}finally{this._pop_all_models_freeze()}this._trigger_on_change(new z.RootAddedEvent(this,e,t))}}remove_root(e,t){const s=this._roots.indexOf(e);if(!(s<0)){this._push_all_models_freeze();try{this._roots.splice(s,1)}finally{this._pop_all_models_freeze()}this._trigger_on_change(new z.RootRemovedEvent(this,e,t))}}title(){return this._title}set_title(e,t){e!==this._title&&(this._title=e,this._trigger_on_change(new z.TitleChangedEvent(this,e,t)))}get_model_by_id(e){var t;return null!==(t=this._all_models.get(e))&&void 0!==t?t:null}get_model_by_name(e){const t=[];for(const s of this._all_models.values())s instanceof M.Model&&s.name==e&&t.push(s);switch(t.length){case 0:return null;case 1:return t[0];default:throw new Error(`Multiple models are named '${e}'`)}}on_message(e,t){const s=this._message_callbacks.get(e);null==s?this._message_callbacks.set(e,new Set([t])):s.add(t)}remove_on_message(e,t){var s;null===(s=this._message_callbacks.get(e))||void 0===s||s.delete(t)}_trigger_on_message(e,t){const s=this._message_callbacks.get(e);if(null!=s)for(const e of s)e(t)}on_change(e,t=!1){this._callbacks.has(e)||this._callbacks.set(e,t)}remove_on_change(e){this._callbacks.delete(e)}_trigger_on_change(e){for(const[t,s]of this._callbacks)if(!s&&e instanceof z.DocumentEventBatch)for(const s of e.events)t(s);else t(e)}_notify_change(e,t,s,o,n){this._trigger_on_change(new z.ModelChangedEvent(this,e,t,s,o,null==n?void 0:n.setter_id,null==n?void 0:n.hint))}static _instantiate_object(e,t,s,o){const n=Object.assign(Object.assign({},s),{id:e,__deferred__:!0});return new(o.get(t))(n)}static _instantiate_references_json(e,t,s){var o;const n=new Map;for(const i of e){const e=i.id,r=i.type,l=null!==(o=i.attributes)&&void 0!==o?o:{};let _=t.get(e);null==_&&(_=E._instantiate_object(e,r,l,s),null!=i.subtype&&_.set_subtype(i.subtype)),n.set(_.id,_)}return n}static _resolve_refs(e,t,s,o){function n(e){var i;if((0,f.is_ref)(e)){const o=null!==(i=t.get(e.id))&&void 0!==i?i:s.get(e.id);if(null!=o)return o;throw new Error(`reference ${JSON.stringify(e)} isn't known (not in Document?)`)}if((0,u.is_NDArray_ref)(e)){const{buffer:t,dtype:s,shape:n}=(0,u.decode_NDArray)(e,o);return(0,m.ndarray)(t,{dtype:s,shape:n})}return(0,b.isArray)(e)?function(e){const t=[];for(const s of e)t.push(n(s));return t}(e):(0,b.isPlainObject)(e)?function(e){const t={};for(const[s,o]of(0,v.entries)(e))t[s]=n(o);return t}(e):e}return n(e)}static _initialize_references_json(e,t,s,o){const n=new Map;for(const{id:i,attributes:r}of e){const e=!t.has(i),l=e?s.get(i):t.get(i),_=E._resolve_refs(r,t,s,o);l.setv(_,{silent:!0}),n.set(i,{instance:l,is_new:e})}const i=[],r=new Set;function l(e){if(e instanceof c.HasProps){if(n.has(e.id)&&!r.has(e.id)){r.add(e.id);const{instance:t,is_new:s}=n.get(e.id),{attributes:o}=t;for(const e of(0,v.values)(o))l(e);s&&(t.finalize(),i.push(t))}}else if((0,b.isArray)(e))for(const t of e)l(t);else if((0,b.isPlainObject)(e))for(const t of(0,v.values)(e))l(t)}for(const e of n.values())l(e.instance);for(const e of i)e.connect_signals()}static _event_for_attribute_change(e,t,s,o,n){if(o.get_model_by_id(e.id).property(t).syncable){const i={kind:\"ModelChanged\",model:{id:e.id},attr:t,new:s};return c.HasProps._json_record_references(o,s,n,{recursive:!0}),i}return null}static _events_to_sync_objects(e,t,s,o){const n=Object.keys(e.attributes),i=Object.keys(t.attributes),r=(0,g.difference)(n,i),l=(0,g.difference)(i,n),a=(0,g.intersection)(n,i),c=[];for(const e of r)_.logger.warn(`Server sent key ${e} but we don't seem to have it in our JSON`);for(const n of l){const i=t.attributes[n];c.push(E._event_for_attribute_change(e,n,i,s,o))}for(const n of a){const i=e.attributes[n],r=t.attributes[n];null==i&&null==r||(null==i||null==r?c.push(E._event_for_attribute_change(e,n,r,s,o)):\"data\"==n||(0,w.is_equal)(i,r)||c.push(E._event_for_attribute_change(e,n,r,s,o)))}return c.filter((e=>null!=e))}static _compute_patch_since_json(e,t){const s=t.to_json(!1);function o(e){const t=new Map;for(const s of e.roots.references)t.set(s.id,s);return t}const n=o(e),i=new Map,r=[];for(const t of e.roots.root_ids)i.set(t,n.get(t)),r.push(t);const l=o(s),_=new Map,a=[];for(const e of s.roots.root_ids)_.set(e,l.get(e)),a.push(e);if(r.sort(),a.sort(),(0,g.difference)(r,a).length>0||(0,g.difference)(a,r).length>0)throw new Error(\"Not implemented: computing add/remove of document roots\");const c=new Set;let h=[];for(const e of t._all_models.keys())if(n.has(e)){const s=E._events_to_sync_objects(n.get(e),l.get(e),t,c);h=h.concat(s)}const f=new d.Serializer({include_defaults:!1});return f.to_serializable([...c]),{references:[...f.definitions],events:h}}to_json_string(e=!0){return JSON.stringify(this.to_json(e))}to_json(e=!0){const t=new d.Serializer({include_defaults:e}),s=t.to_serializable(this._roots);return{version:l.version,title:this._title,roots:{root_ids:s.map((e=>e.id)),references:[...t.definitions]}}}static from_json_string(e){const t=JSON.parse(e);return E.from_json(t)}static from_json(e){_.logger.debug(\"Creating Document from JSON\");const t=e.version,s=-1!==t.indexOf(\"+\")||-1!==t.indexOf(\"-\"),o=`Library versions: JS (${l.version}) / Python (${t})`;s||l.version.replace(/-(dev|rc)\\./,\"$1\")==t?_.logger.debug(o):(_.logger.warn(\"JS/Python version mismatch\"),_.logger.warn(o));const n=new r.ModelResolver;null!=e.defs&&(0,j.resolve_defs)(e.defs,n);const i=e.roots,a=i.root_ids,c=i.references,d=E._instantiate_references_json(c,new Map,n);E._initialize_references_json(c,new Map,d,new Map);const h=new E({resolver:n});h._push_all_models_freeze();for(const e of a){const t=d.get(e);null!=t&&h.add_root(t)}return h._pop_all_models_freeze(),h.set_title(e.title),h}replace_with_json(e){E.from_json(e).destructively_move(this)}create_json_patch_string(e){return JSON.stringify(this.create_json_patch(e))}create_json_patch(e){for(const t of e)if(t.document!=this)throw new Error(\"Cannot create a patch using events from a different document\");const t=new d.Serializer,s=t.to_serializable(e);for(const e of this._all_models.values())t.remove_def(e);return{events:s,references:[...t.definitions]}}apply_json_patch(e,t=new Map,s){const o=e.references,n=e.events,i=E._instantiate_references_json(o,this._all_models,this._resolver);t instanceof Map||(t=new Map(t));for(const e of n)switch(e.kind){case\"RootAdded\":case\"RootRemoved\":case\"ModelChanged\":{const t=e.model.id,s=this._all_models.get(t);if(null!=s)i.set(t,s);else if(!i.has(t))throw _.logger.warn(`Got an event for unknown model ${e.model}\"`),new Error(\"event model wasn't known\");break}}const r=new Map(this._all_models),l=new Map;for(const[e,t]of i)r.has(e)||l.set(e,t);E._initialize_references_json(o,r,l,t);for(const e of n)switch(e.kind){case\"MessageSent\":{const{msg_type:s,msg_data:o}=e;let n;if(void 0===o){if(1!=t.size)throw new Error(\"expected exactly one buffer\");{const[[,e]]=t;n=e}}else n=E._resolve_refs(o,r,l,t);this._trigger_on_message(s,n);break}case\"ModelChanged\":{const o=e.model.id,n=this._all_models.get(o);if(null==n)throw new Error(`Cannot apply patch to ${o} which is not in the document`);const i=e.attr,_=E._resolve_refs(e.new,r,l,t);n.setv({[i]:_},{setter_id:s});break}case\"ColumnDataChanged\":{const o=e.column_source.id,n=this._all_models.get(o);if(null==n)throw new Error(`Cannot stream to ${o} which is not in the document`);const i=E._resolve_refs(e.new,new Map,new Map,t);if(null!=e.cols)for(const e in n.data)e in i||(i[e]=n.data[e]);n.setv({data:i},{setter_id:s,check_eq:!1});break}case\"ColumnsStreamed\":{const t=e.column_source.id,o=this._all_models.get(t);if(null==o)throw new Error(`Cannot stream to ${t} which is not in the document`);if(!(o instanceof k.ColumnDataSource))throw new Error(\"Cannot stream to non-ColumnDataSource\");const n=e.data,i=e.rollover;o.stream(n,i,s);break}case\"ColumnsPatched\":{const t=e.column_source.id,o=this._all_models.get(t);if(null==o)throw new Error(`Cannot patch ${t} which is not in the document`);if(!(o instanceof k.ColumnDataSource))throw new Error(\"Cannot patch non-ColumnDataSource\");const n=e.patches;o.patch(n,s);break}case\"RootAdded\":{const t=e.model.id,o=i.get(t);this.add_root(o,s);break}case\"RootRemoved\":{const t=e.model.id,o=i.get(t);this.remove_root(o,s);break}case\"TitleChanged\":this.set_title(e.title,s);break;default:throw new Error(`Unknown patch event ${JSON.stringify(e)}`)}}}s.Document=E,E.__name__=\"Document\"},\n function _(e,o,s,r,t){r();const l=e(1),i=e(8),d=e(13),n=e(14);s.overrides={};const a=new Map;s.Models=e=>{const o=s.Models.get(e);if(null!=o)return o;throw new Error(`Model '${e}' does not exist. This could be due to a widget or a custom model not being registered before first usage.`)},s.Models.get=e=>{var o;return null!==(o=s.overrides[e])&&void 0!==o?o:a.get(e)},s.Models.register=(e,o)=>{s.overrides[e]=o},s.Models.unregister=e=>{delete s.overrides[e]},s.Models.register_models=(e,o=!1,s)=>{var r;if(null!=e)for(const t of(0,i.isArray)(e)?e:(0,d.values)(e))if(r=t,(0,i.isObject)(r)&&r.prototype instanceof n.HasProps){const e=t.__qualified__;o||!a.has(e)?a.set(e,t):null!=s?s(e):console.warn(`Model '${e}' was already registered`)}},s.register_models=s.Models.register_models,s.Models.registered_names=()=>[...a.keys()];class _{constructor(){this._known_models=new Map}get(e,o){var r;const t=null!==(r=s.Models.get(e))&&void 0!==r?r:this._known_models.get(e);if(null!=t)return t;if(void 0!==o)return o;throw new Error(`Model '${e}' does not exist. This could be due to a widget or a custom model not being registered before first usage.`)}register(e){const o=e.__qualified__;null==this.get(o,null)?this._known_models.set(o,e):console.warn(`Model '${o}' was already registered with this resolver`)}}s.ModelResolver=_,_.__name__=\"ModelResolver\";const g=(0,l.__importStar)(e(38));(0,s.register_models)(g);const u=(0,l.__importStar)(e(392));(0,s.register_models)(u)},\n function _(n,t,r,e,i){e();\n // (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n // Underscore may be freely distributed under the MIT license.\n const o=n(9),u=Object.prototype.toString;function c(n){return!0===n||!1===n||\"[object Boolean]\"===u.call(n)}function f(n){return\"[object Number]\"===u.call(n)}function l(n){return\"[object String]\"===u.call(n)}function s(n){return\"symbol\"==typeof n}function a(n){const t=typeof n;return\"function\"===t||\"object\"===t&&!!n}function b(n){return a(n)&&void 0!==n[Symbol.iterator]}r.isBoolean=c,r.isNumber=f,r.isInteger=function(n){return f(n)&&Number.isInteger(n)},r.isString=l,r.isSymbol=s,r.isPrimitive=function(n){return null===n||c(n)||f(n)||l(n)||s(n)},r.isFunction=function(n){return\"[object Function]\"===u.call(n)},r.isArray=function(n){return Array.isArray(n)},r.isArrayOf=function(n,t){return(0,o.every)(n,t)},r.isArrayableOf=function(n,t){for(let r=0,e=n.length;r0,\"'step' must be a positive number\"),null==t&&(t=n,n=0);const{max:r,ceil:o,abs:i}=Math,c=n<=t?e:-e,f=r(o(i(t-n)/e),0),s=new Array(f);for(let t=0;t=0?t:n.length+t]},e.zip=function(...n){if(0==n.length)return[];const t=(0,c.min)(n.map((n=>n.length))),e=n.length,r=new Array(t);for(let o=0;on.length))),r=Array(e);for(let n=0;nn[t]))},e.argmax=function(n){return(0,c.max_by)(m(n.length),(t=>n[t]))},e.sort_by=function(n,t){const e=n.map(((n,e)=>({value:n,index:e,key:t(n)})));return e.sort(((n,t)=>{const e=n.key,r=t.key;if(e!==r){if(e>r||void 0===e)return 1;if(en.value))},e.uniq=function(n){const t=new Set;for(const e of n)t.add(e);return[...t]},e.uniq_by=function(n,t){const e=[],r=[];for(const o of n){const n=t(o);l(r,n)||(r.push(n),e.push(o))}return e},e.union=function(...n){const t=new Set;for(const e of n)for(const n of e)t.add(n);return[...t]},e.intersection=function(n,...t){const e=[];n:for(const r of n)if(!l(e,r)){for(const n of t)if(!l(n,r))continue n;e.push(r)}return e},e.difference=function(n,...t){const e=a(t);return n.filter((n=>!l(e,n)))},e.remove_at=function(n,t){const e=s(n);return e.splice(t,1),e},e.remove_by=function(n,t){for(let e=0;e2*a;)n-=2*a;return n}function c(n,t){return u(n-t)}function f(){return Math.random()}function i(n){switch(n){case\"deg\":return a/180;case\"rad\":return 1;case\"grad\":return a/200;case\"turn\":return 2*a}}r.angle_norm=u,r.angle_dist=c,r.angle_between=function(n,t,r,e=!1){const o=c(t,r);if(0==o)return!1;if(o==2*a)return!0;const f=u(n),i=c(t,f)<=o&&c(f,r)<=o;return e?!i:i},r.random=f,r.randomIn=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))},r.atan2=function(n,t){return Math.atan2(t[1]-n[1],t[0]-n[0])},r.radians=function(n){return n*(a/180)},r.degrees=function(n){return n/(a/180)},r.resolve_angle=function(n,t){return-i(t)*n},r.to_radians_coeff=i,r.rnorm=function(n,t){let r,e;for(;r=f(),e=f(),e=(2*e-1)*Math.sqrt(1/Math.E*2),!(-4*r*r*Math.log(r)>=e*e););let o=e/r;return o=n+t*o,o},r.clamp=function(n,t,r){return nr?r:n},r.log=function(n,t=Math.E){return Math.log(n)/Math.log(t)},r.float32_epsilon=1.1920928955078125e-7},\n function _(r,n,e,o,s){o();class t extends Error{}e.AssertionError=t,t.__name__=\"AssertionError\",e.assert=function(r,n){if(!(!0===r||!1!==r&&r()))throw new t(null!=n?n:\"Assertion failed\")},e.unreachable=function(){throw new Error(\"unreachable code\")}},\n function _(n,t,e,r,o){r();const i=n(10);function l(n,t,e,...r){const o=n.length;t<0&&(t+=o),t<0?t=0:t>o&&(t=o),null==e||e>o-t?e=o-t:e<0&&(e=0);const i=o-e+r.length,l=new n.constructor(i);let u=0;for(;u0?0:r-1;for(;o>=0&&ot[t.length-1])return t.length;let e=0,r=t.length-1;for(;r-e!=1;){const o=e+Math.floor((r-e)/2);n>=t[o]?e=o:r=o}return e}e.is_empty=function(n){return 0==n.length},e.copy=function(n){return Array.isArray(n)?n.slice():new n.constructor(n)},e.splice=l,e.head=u,e.insert=function(n,t,e){return l(n,e,0,t)},e.append=function(n,t){return l(n,n.length,0,t)},e.prepend=function(n,t){return l(n,0,0,t)},e.indexOf=function(n,t){for(let e=0,r=n.length;ee&&(e=t);return e},e.minmax=function(n){let t,e=1/0,r=-1/0;for(let o=0,i=n.length;or&&(r=t));return[e,r]},e.minmax2=function(n,t){let e,r,o=1/0,i=-1/0,l=1/0,u=-1/0;const c=Math.min(n.length,t.length);for(let f=0;fi&&(i=e),ru&&(u=r));return[o,i,l,u]},e.min_by=function(n,t){if(0==n.length)throw new Error(\"min_by() called with an empty array\");let e=n[0],r=t(e);for(let o=1,i=n.length;or&&(e=i,r=l)}return e},e.sum=function(n){let t=0;for(let e=0,r=n.length;et[r]=n+e),0),t},e.every=function(n,t){for(let e=0,r=n.length;e(n-t)/r))}},\n function _(t,e,n,c,o){c();const s=t(9),{hasOwnProperty:r}=Object.prototype;function i(t){return Object.keys(t).length}function u(t){return 0==i(t)}n.keys=Object.keys,n.values=Object.values,n.entries=Object.entries,n.extend=Object.assign,n.clone=function(t){return Object.assign({},t)},n.merge=function(t,e){const n=Object.create(Object.prototype),c=(0,s.concat)([Object.keys(t),Object.keys(e)]);for(const o of c){const c=r.call(t,o)?t[o]:[],i=r.call(e,o)?e[o]:[];n[o]=(0,s.union)(c,i)}return n},n.size=i,n.is_empty=u,n.isEmpty=u,n.to_object=function(t){const e={};for(const[n,c]of t)e[n]=c;return e}},\n function _(e,t,s,n,r){n();const i=e(1);var o;const c=e(15),a=e(17),_=(0,i.__importStar)(e(18)),h=(0,i.__importStar)(e(21)),u=e(34),l=e(13),f=e(8),p=e(26),d=e(30),g=e(35),y=e(26),v=e(36),m=e(37),b=(0,i.__importStar)(e(21));class w extends((0,c.Signalable)()){constructor(e={}){var t,s;super(),this._subtype=void 0,this.document=null,this.destroyed=new c.Signal0(this,\"destroyed\"),this.change=new c.Signal0(this,\"change\"),this.transformchange=new c.Signal0(this,\"transformchange\"),this.exprchange=new c.Signal0(this,\"exprchange\"),this.properties={},this._watchers=new WeakMap,this._pending=!1,this._changing=!1;const n=e instanceof Map?e.get.bind(e):t=>e[t];this.id=null!==(t=n(\"id\"))&&void 0!==t?t:(0,u.uniqueId)();for(const[e,{type:t,default_value:s,options:r}]of(0,l.entries)(this._props)){let i;t instanceof _.PropertyAlias?Object.defineProperty(this.properties,e,{get:()=>this.properties[t.attr],configurable:!1,enumerable:!1}):(i=t instanceof h.Kind?new _.PrimitiveProperty(this,e,t,s,n(e),r):new t(this,e,h.Any,s,n(e),r),this.properties[e]=i)}null!==(s=n(\"__deferred__\"))&&void 0!==s&&s||(this.finalize(),this.connect_signals())}get is_syncable(){return!0}set type(e){console.warn(\"prototype.type = 'ModelName' is deprecated, use static __name__ instead\"),this.constructor.__name__=e}get type(){return this.constructor.__qualified__}static get __qualified__(){const{__module__:e,__name__:t}=this;return null!=e?`${e}.${t}`:t}static get[Symbol.toStringTag](){return this.__name__}static _fix_default(e,t){if(void 0===e||(0,f.isFunction)(e))return e;if((0,f.isPrimitive)(e))return()=>e;{const t=new m.Cloner;return()=>t.clone(e)}}static define(e){for(const[t,s]of(0,l.entries)((0,f.isFunction)(e)?e(b):e)){if(null!=this.prototype._props[t])throw new Error(`attempted to redefine property '${this.prototype.type}.${t}'`);if(null!=this.prototype[t])throw new Error(`attempted to redefine attribute '${this.prototype.type}.${t}'`);Object.defineProperty(this.prototype,t,{get(){return this.properties[t].get_value()},set(e){return this.setv({[t]:e}),this},configurable:!1,enumerable:!0});const[e,n,r={}]=s,i={type:e,default_value:this._fix_default(n,t),options:r},o=Object.assign({},this.prototype._props);o[t]=i,this.prototype._props=o}}static internal(e){const t={};for(const[s,n]of(0,l.entries)((0,f.isFunction)(e)?e(b):e)){const[e,r,i={}]=n;t[s]=[e,r,Object.assign(Object.assign({},i),{internal:!0})]}this.define(t)}static mixins(e){function t(e,t){const s={};for(const[n,r]of(0,l.entries)(t))s[e+n]=r;return s}const s={},n=[];for(const r of(0,f.isArray)(e)?e:[e])if((0,f.isArray)(r)){const[e,i]=r;(0,l.extend)(s,t(e,i)),n.push([e,i])}else{const e=r;(0,l.extend)(s,e),n.push([\"\",e])}this.define(s),this.prototype._mixins=[...this.prototype._mixins,...n]}static override(e){for(const[t,s]of(0,l.entries)(e)){const e=this._fix_default(s,t),n=this.prototype._props[t];if(null==n)throw new Error(`attempted to override nonexistent '${this.prototype.type}.${t}'`);const r=Object.assign({},this.prototype._props);r[t]=Object.assign(Object.assign({},n),{default_value:e}),this.prototype._props=r}}toString(){return`${this.type}(${this.id})`}property(e){const t=this.properties[e];if(null!=t)return t;throw new Error(`unknown property ${this.type}.${e}`)}get attributes(){const e={};for(const t of this)e[t.attr]=t.get_value();return e}[m.clone](e){const t=new Map;for(const s of this)s.dirty&&t.set(s.attr,e.clone(s.get_value()));return new this.constructor(t)}[y.equals](e,t){for(const s of this){const n=e.property(s.attr);if(!t.eq(s.get_value(),n.get_value()))return!1}return!0}[v.pretty](e){const t=e.token,s=[];for(const n of this)if(n.dirty){const r=n.get_value();s.push(`${n.attr}${t(\":\")} ${e.to_string(r)}`)}return`${this.constructor.__qualified__}${t(\"(\")}${t(\"{\")}${s.join(`${t(\",\")} `)}${t(\"}\")}${t(\")\")}`}[d.serialize](e){const t=this.ref();e.add_ref(this,t);const s=this.struct();for(const t of this)t.syncable&&(e.include_defaults||t.dirty)&&(s.attributes[t.attr]=e.to_serializable(t.get_value()));return e.add_def(this,s),t}finalize(){for(const e of this){if(!(e instanceof _.VectorSpec||e instanceof _.ScalarSpec))continue;const t=e.get_value();if(null!=t){const{transform:e,expr:s}=t;null!=e&&this.connect(e.change,(()=>this.transformchange.emit())),null!=s&&this.connect(s.change,(()=>this.exprchange.emit()))}}this.initialize()}initialize(){}connect_signals(){}disconnect_signals(){c.Signal.disconnectReceiver(this)}destroy(){this.disconnect_signals(),this.destroyed.emit()}clone(){return(new m.Cloner).clone(this)}changed_for(e){const t=this._watchers.get(e);return this._watchers.set(e,!1),null==t||t}_setv(e,t){const s=t.check_eq,n=[],r=this._changing;this._changing=!0;for(const[t,r]of e)!1!==s&&(0,p.is_equal)(t.get_value(),r)||(t.set_value(r),n.push(t));n.length>0&&(this._watchers=new WeakMap,this._pending=!0);for(const e of n)e.change.emit();if(!r){if(!t.no_change)for(;this._pending;)this._pending=!1,this.change.emit();this._pending=!1,this._changing=!1}}setv(e,t={}){const s=(0,l.entries)(e);if(0==s.length)return;if(!0===t.silent){this._watchers=new WeakMap;for(const[e,t]of s)this.properties[e].set_value(t);return}const n=new Map,r=new Map;for(const[e,t]of s){const s=this.properties[e];n.set(s,t),r.set(s,s.get_value())}this._setv(n,t);const{document:i}=this;if(null!=i){const e=[];for(const[t,s]of r)e.push([t,s,t.get_value()]);for(const[,t,s]of e)if(this._needs_invalidate(t,s)){i._invalidate_all_models();break}this._push_changes(e,t)}}getv(e){return this.property(e).get_value()}ref(){return{id:this.id}}struct(){const e={type:this.type,id:this.id,attributes:{}};return null!=this._subtype&&(e.subtype=this._subtype),e}set_subtype(e){this._subtype=e}*[Symbol.iterator](){yield*(0,l.values)(this.properties)}*syncable_properties(){for(const e of this)e.syncable&&(yield e)}serializable_attributes(){const e={};for(const t of this.syncable_properties())e[t.attr]=t.get_value();return e}static _json_record_references(e,t,s,n){const{recursive:r}=n;if((0,a.is_ref)(t)){const n=e.get_model_by_id(t.id);null==n||s.has(n)||w._value_record_references(n,s,{recursive:r})}else if((0,f.isArray)(t))for(const n of t)w._json_record_references(e,n,s,{recursive:r});else if((0,f.isPlainObject)(t))for(const n of(0,l.values)(t))w._json_record_references(e,n,s,{recursive:r})}static _value_record_references(e,t,s){const{recursive:n}=s;if(e instanceof w){if(!t.has(e)&&(t.add(e),n))for(const s of e.syncable_properties()){const e=s.get_value();w._value_record_references(e,t,{recursive:n})}}else if((0,f.isArray)(e))for(const s of e)w._value_record_references(s,t,{recursive:n});else if((0,f.isPlainObject)(e))for(const s of(0,l.values)(e))w._value_record_references(s,t,{recursive:n})}references(){const e=new Set;return w._value_record_references(this,e,{recursive:!0}),e}_doc_attached(){}_doc_detached(){}attach_document(e){if(null!=this.document&&this.document!=e)throw new Error(\"models must be owned by only a single document\");this.document=e,this._doc_attached()}detach_document(){this._doc_detached(),this.document=null}_needs_invalidate(e,t){const s=new Set;w._value_record_references(t,s,{recursive:!1});const n=new Set;w._value_record_references(e,n,{recursive:!1});for(const e of s)if(!n.has(e))return!0;for(const e of n)if(!s.has(e))return!0;return!1}_push_changes(e,t={}){if(!this.is_syncable)return;const{document:s}=this;if(null==s)return;const{setter_id:n}=t,r=[];for(const[t,i,o]of e)t.syncable&&r.push(new g.ModelChangedEvent(s,this,t.attr,i,o,n));if(0!=r.length){let e;1==r.length?[e]=r:e=new g.DocumentEventBatch(s,r,n),s._trigger_on_change(e)}}on_change(e,t){for(const s of(0,f.isArray)(e)?e:[e])this.connect(s.change,t)}}s.HasProps=w,(o=w).prototype._props={},o.prototype._mixins=[]},\n function _(n,t,e,l,s){l();const i=n(16),o=n(9);class c{constructor(n,t){this.sender=n,this.name=t}connect(n,t=null){u.has(this.sender)||u.set(this.sender,[]);const e=u.get(this.sender);if(null!=g(e,this,n,t))return!1;const l=null!=t?t:n;a.has(l)||a.set(l,[]);const s=a.get(l),i={signal:this,slot:n,context:t};return e.push(i),s.push(i),!0}disconnect(n,t=null){const e=u.get(this.sender);if(null==e||0===e.length)return!1;const l=g(e,this,n,t);if(null==l)return!1;const s=null!=t?t:n,i=a.get(s);return l.signal=null,d(e),d(i),!0}emit(n){var t;const e=null!==(t=u.get(this.sender))&&void 0!==t?t:[];for(const{signal:t,slot:l,context:s}of e)t===this&&l.call(s,n,this.sender)}}e.Signal=c,c.__name__=\"Signal\";class r extends c{emit(){super.emit(void 0)}}e.Signal0=r,r.__name__=\"Signal0\",function(n){function t(n,t){const e=u.get(n);if(null==e||0===e.length)return;const l=a.get(t);if(null!=l&&0!==l.length){for(const t of l){if(null==t.signal)return;t.signal.sender===n&&(t.signal=null)}d(e),d(l)}}function e(n){var t;const e=u.get(n);if(null!=e&&0!==e.length){for(const n of e){if(null==n.signal)return;const e=null!==(t=n.context)&&void 0!==t?t:n.slot;n.signal=null,d(a.get(e))}d(e)}}function l(n,t,e){const l=a.get(n);if(null!=l&&0!==l.length){for(const n of l){if(null==n.signal)return;if(null!=t&&n.slot!=t)continue;const l=n.signal.sender;null!=e&&e.has(l)||(n.signal=null,d(u.get(l)))}d(l)}}function s(n){const t=u.get(n);if(null!=t&&0!==t.length){for(const n of t)n.signal=null;d(t)}const e=a.get(n);if(null!=e&&0!==e.length){for(const n of e)n.signal=null;d(e)}}n.disconnect_between=t,n.disconnect_sender=e,n.disconnect_receiver=l,n.disconnect_all=s,n.disconnectBetween=t,n.disconnectSender=e,n.disconnectReceiver=l,n.disconnectAll=s}(c||(e.Signal=c={})),e.Signalable=function(){return class{connect(n,t){return n.connect(t,this)}disconnect(n,t){return n.disconnect(t,this)}}};const u=new WeakMap,a=new WeakMap;function g(n,t,e,l){return(0,o.find)(n,(n=>n.signal===t&&n.slot===e&&n.context===l))}const f=new Set;function d(n){0===f.size&&(async()=>{await(0,i.defer)(),function(){for(const n of f)(0,o.remove_by)(n,(n=>null==n.signal));f.clear()}()})(),f.add(n)}},\n function _(e,n,t,s,o){s();const r=new MessageChannel,a=new Map;r.port1.onmessage=e=>{const n=e.data,t=a.get(n);if(null!=t)try{t()}finally{a.delete(n)}};let i=1;t.defer=function(){return new Promise((e=>{const n=i++;a.set(n,e),r.port2.postMessage(n)}))},t.wait=function(e){return new Promise((n=>setTimeout(n,e)))}},\n function _(n,t,i,e,c){e();const r=n(8),s=n(13);i.is_ref=function(n){if((0,r.isPlainObject)(n)){const t=(0,s.keys)(n);return 1==t.length&&\"id\"==t[0]}return!1}},\n function _(e,t,n,r,a){r(),n.YCoordinateSeqSeqSeqSpec=n.XCoordinateSeqSeqSeqSpec=n.YCoordinateSeqSpec=n.XCoordinateSeqSpec=n.YCoordinateSpec=n.XCoordinateSpec=n.CoordinateSeqSeqSeqSpec=n.CoordinateSeqSpec=n.CoordinateSpec=n.BaseCoordinateSpec=n.NumberUnitsSpec=n.UnitsSpec=n.DataSpec=n.VectorSpec=n.TextBaselineScalar=n.TextAlignScalar=n.FontStyleScalar=n.FontSizeScalar=n.FontScalar=n.LineDashScalar=n.LineCapScalar=n.LineJoinScalar=n.ArrayScalar=n.NullStringScalar=n.StringScalar=n.NumberScalar=n.ColorScalar=n.AnyScalar=n.ScalarSpec=n.VerticalAlign=n.UpdateMode=n.TooltipAttachment=n.TickLabelOrientation=n.TextureRepetition=n.TextBaseline=n.TextAlign=n.TapBehavior=n.StepMode=n.StartEnd=n.SpatialUnits=n.Sort=n.SizingMode=n.Side=n.RoundingFunction=n.ResetPolicy=n.RenderMode=n.RenderLevel=n.RadiusDimension=n.PointPolicy=n.Place=void 0,n.TextBaselineSpec=n.TextAlignSpec=n.FontStyleSpec=n.FontSizeSpec=n.FontSpec=n.LineDashSpec=n.LineCapSpec=n.LineJoinSpec=n.MarkerSpec=n.ArraySpec=n.NullStringSpec=n.StringSpec=n.AnySpec=n.NDArraySpec=n.ColorSpec=n.ScreenSizeSpec=n.NumberSpec=n.IntSpec=n.BooleanSpec=n.NullDistanceSpec=n.DistanceSpec=n.AngleSpec=void 0;const i=e(1),s=e(15),l=e(19),o=(0,i.__importStar)(e(20)),c=e(24),_=e(9),u=e(12),d=e(10),S=e(22),p=e(27),m=e(8),h=e(28),v=e(29),y=e(33);function x(e){try{return JSON.stringify(e)}catch(t){return e.toString()}}function g(e){return(0,m.isPlainObject)(e)&&(void 0===e.value?0:1)+(void 0===e.field?0:1)+(void 0===e.expr?0:1)==1}a(\"Uniform\",y.Uniform),a(\"UniformScalar\",y.UniformScalar),a(\"UniformVector\",y.UniformVector),n.isSpec=g;class f{constructor(e,t,n,r,a,i={}){var l;let o;if(this.obj=e,this.attr=t,this.kind=n,this.default_value=r,this._dirty=!1,this.change=new s.Signal0(this.obj,\"change\"),this.internal=null!==(l=i.internal)&&void 0!==l&&l,this.convert=i.convert,this.on_update=i.on_update,void 0!==a)o=a,this._dirty=!0;else{const t=this._default_override();if(void 0!==t)o=t;else{if(void 0===r)return void(this.spec={value:null});o=r(e)}}this._update(o)}get is_value(){return void 0!==this.spec.value}get syncable(){return!this.internal}get_value(){return this.spec.value}set_value(e){this._update(e),this._dirty=!0}_default_override(){}get dirty(){return this._dirty}_update(e){var t;if(this.validate(e),null!=this.convert){const t=this.convert(e);void 0!==t&&(e=t)}this.spec={value:e},null===(t=this.on_update)||void 0===t||t.call(this,e,this.obj)}toString(){return`Prop(${this.obj}.${this.attr}, spec: ${x(this.spec)})`}normalize(e){return e}validate(e){if(!this.valid(e))throw new Error(`${this.obj}.${this.attr} given invalid value: ${x(e)}`)}valid(e){return this.kind.valid(e)}_value(e=!0){if(!this.is_value)throw new Error(\"attempted to retrieve property value for property without value specification\");let t=this.normalize([this.spec.value])[0];return null!=this.spec.transform&&e&&(t=this.spec.transform.compute(t)),t}}n.Property=f,f.__name__=\"Property\";class A{constructor(e){this.attr=e}}n.PropertyAlias=A,A.__name__=\"PropertyAlias\",n.Alias=function(e){return new A(e)};class C extends f{}n.PrimitiveProperty=C,C.__name__=\"PrimitiveProperty\";class T extends f{}n.Any=T,T.__name__=\"Any\";class L extends f{valid(e){return(0,m.isArray)(e)||(0,m.isTypedArray)(e)}}n.Array=L,L.__name__=\"Array\";class w extends f{valid(e){return(0,m.isBoolean)(e)}}n.Boolean=w,w.__name__=\"Boolean\";class P extends f{valid(e){return(0,S.is_Color)(e)}}n.Color=P,P.__name__=\"Color\";class b extends f{}n.Instance=b,b.__name__=\"Instance\";class q extends f{valid(e){return(0,m.isNumber)(e)}}n.Number=q,q.__name__=\"Number\";class N extends q{valid(e){return(0,m.isNumber)(e)&&(0|e)==e}}n.Int=N,N.__name__=\"Int\";class z extends q{}n.Angle=z,z.__name__=\"Angle\";class B extends q{valid(e){return(0,m.isNumber)(e)&&0<=e&&e<=1}}n.Percent=B,B.__name__=\"Percent\";class F extends f{valid(e){return(0,m.isString)(e)}}n.String=F,F.__name__=\"String\";class D extends f{valid(e){return null===e||(0,m.isString)(e)}}n.NullString=D,D.__name__=\"NullString\";class U extends F{}n.FontSize=U,U.__name__=\"FontSize\";class M extends F{_default_override(){return h.settings.dev?\"Bokeh\":void 0}}n.Font=M,M.__name__=\"Font\";class R extends f{valid(e){return(0,m.isString)(e)&&(0,_.includes)(this.enum_values,e)}}function k(e){return class extends R{get enum_values(){return[...e]}}}n.EnumProperty=R,R.__name__=\"EnumProperty\",n.Enum=k;class O extends R{get enum_values(){return[...o.Direction]}normalize(e){const t=new Uint8Array(e.length);for(let n=0;n=0}}n.ScreenSizeSpec=fe,fe.__name__=\"ScreenSizeSpec\";class Ae extends ne{materialize(e){return(0,S.encode_rgba)((0,S.color2rgba)(e))}v_materialize(e){if(!(0,v.is_NDArray)(e)){const t=e.length,n=new c.RGBAArray(4*t);let r=0;for(const t of e){const[e,a,i,s]=(0,S.color2rgba)(t);n[r++]=e,n[r++]=a,n[r++]=i,n[r++]=s}return new c.ColorArray(n.buffer)}if(\"uint32\"==e.dtype&&1==e.dimension)return(0,p.to_big_endian)(e);if(\"uint8\"==e.dtype&&1==e.dimension){const[t]=e.shape,n=new c.RGBAArray(4*t);let r=0;for(const t of e)n[r++]=t,n[r++]=t,n[r++]=t,n[r++]=255;return new c.ColorArray(n.buffer)}if(\"uint8\"==e.dtype&&2==e.dimension){const[t,n]=e.shape;if(4==n)return new c.ColorArray(e.buffer);if(3==n){const r=new c.RGBAArray(4*t);for(let a=0,i=0;a0){let o=r[e];return null==o&&(r[e]=o=new v(e,l)),o}throw new TypeError(\"Logger.get() expects a non-empty string name and an optional log-level\")}get level(){return this.get_level()}get_level(){return this._log_level}set_level(e){if(e instanceof i)this._log_level=e;else{if(!(0,s.isString)(e)||null==v.log_levels[e])throw new Error(\"Logger.set_level() expects a log-level object or a string name of a log-level\");this._log_level=v.log_levels[e]}const l=`[${this._name}]`;for(const[e,o]of(0,g.entries)(v.log_levels))o.level\",\"*\"),t.HTTPMethod=(0,a.Enum)(\"POST\",\"GET\"),t.HexTileOrientation=(0,a.Enum)(\"pointytop\",\"flattop\"),t.HoverMode=(0,a.Enum)(\"mouse\",\"hline\",\"vline\"),t.LatLon=(0,a.Enum)(\"lat\",\"lon\"),t.LegendClickPolicy=(0,a.Enum)(\"none\",\"hide\",\"mute\"),t.LegendLocation=t.Anchor,t.LineCap=(0,a.Enum)(\"butt\",\"round\",\"square\"),t.LineJoin=(0,a.Enum)(\"miter\",\"round\",\"bevel\"),t.LineDash=(0,a.Enum)(\"solid\",\"dashed\",\"dotted\",\"dotdash\",\"dashdot\"),t.LinePolicy=(0,a.Enum)(\"prev\",\"next\",\"nearest\",\"interp\",\"none\"),t.Location=(0,a.Enum)(\"above\",\"below\",\"left\",\"right\"),t.Logo=(0,a.Enum)(\"normal\",\"grey\"),t.MarkerType=(0,a.Enum)(\"asterisk\",\"circle\",\"circle_cross\",\"circle_dot\",\"circle_x\",\"circle_y\",\"cross\",\"dash\",\"diamond\",\"diamond_cross\",\"diamond_dot\",\"dot\",\"hex\",\"hex_dot\",\"inverted_triangle\",\"plus\",\"square\",\"square_cross\",\"square_dot\",\"square_pin\",\"square_x\",\"star\",\"star_dot\",\"triangle\",\"triangle_dot\",\"triangle_pin\",\"x\",\"y\"),t.MutedPolicy=(0,a.Enum)(\"show\",\"ignore\"),t.Orientation=(0,a.Enum)(\"vertical\",\"horizontal\"),t.OutputBackend=(0,a.Enum)(\"canvas\",\"svg\",\"webgl\"),t.PaddingUnits=(0,a.Enum)(\"percent\",\"absolute\"),t.Place=(0,a.Enum)(\"above\",\"below\",\"left\",\"right\",\"center\"),t.PointPolicy=(0,a.Enum)(\"snap_to_data\",\"follow_mouse\",\"none\"),t.RadiusDimension=(0,a.Enum)(\"x\",\"y\",\"max\",\"min\"),t.RenderLevel=(0,a.Enum)(\"image\",\"underlay\",\"glyph\",\"guide\",\"annotation\",\"overlay\"),t.RenderMode=(0,a.Enum)(\"canvas\",\"css\"),t.ResetPolicy=(0,a.Enum)(\"standard\",\"event_only\"),t.RoundingFunction=(0,a.Enum)(\"round\",\"nearest\",\"floor\",\"rounddown\",\"ceil\",\"roundup\"),t.SelectionMode=(0,a.Enum)(\"replace\",\"append\",\"intersect\",\"subtract\"),t.Side=(0,a.Enum)(\"above\",\"below\",\"left\",\"right\"),t.SizingMode=(0,a.Enum)(\"stretch_width\",\"stretch_height\",\"stretch_both\",\"scale_width\",\"scale_height\",\"scale_both\",\"fixed\"),t.Sort=(0,a.Enum)(\"ascending\",\"descending\"),t.SpatialUnits=(0,a.Enum)(\"screen\",\"data\"),t.StartEnd=(0,a.Enum)(\"start\",\"end\"),t.StepMode=(0,a.Enum)(\"after\",\"before\",\"center\"),t.TapBehavior=(0,a.Enum)(\"select\",\"inspect\"),t.TextAlign=(0,a.Enum)(\"left\",\"right\",\"center\"),t.TextBaseline=(0,a.Enum)(\"top\",\"middle\",\"bottom\",\"alphabetic\",\"hanging\",\"ideographic\"),t.TextureRepetition=(0,a.Enum)(\"repeat\",\"repeat_x\",\"repeat_y\",\"no_repeat\"),t.TickLabelOrientation=(0,a.Enum)(\"vertical\",\"horizontal\",\"parallel\",\"normal\"),t.TooltipAttachment=(0,a.Enum)(\"horizontal\",\"vertical\",\"left\",\"right\",\"above\",\"below\"),t.UpdateMode=(0,a.Enum)(\"replace\",\"append\"),t.VerticalAlign=(0,a.Enum)(\"top\",\"middle\",\"bottom\")},\n function _(e,n,t,s,r){s();const i=(0,e(1).__importStar)(e(8)),a=e(22),l=e(13),_=window.Map,{hasOwnProperty:u}=Object.prototype;class d{}t.Kind=d,d.__name__=\"Kind\",function(e){class n extends d{valid(e){return!0}}n.__name__=\"Any\",e.Any=n;class t extends d{valid(e){return!0}}t.__name__=\"Unknown\",e.Unknown=t;class s extends d{valid(e){return i.isBoolean(e)}}s.__name__=\"Boolean\",e.Boolean=s;class r extends d{constructor(e){super(),this.obj_type=e}valid(e){return!0}}r.__name__=\"Ref\",e.Ref=r;class c extends d{valid(e){return!0}}c.__name__=\"AnyRef\",e.AnyRef=c;class o extends d{valid(e){return i.isNumber(e)}}o.__name__=\"Number\",e.Number=o;class p extends o{valid(e){return super.valid(e)&&i.isInteger(e)}}p.__name__=\"Int\",e.Int=p;class y extends o{valid(e){return super.valid(e)&&0<=e&&e<=1}}y.__name__=\"Percent\",e.Percent=y;class m extends d{constructor(e){super(),this.types=e,this.types=e}valid(e){return this.types.some((n=>n.valid(e)))}}m.__name__=\"Or\",e.Or=m;class v extends d{constructor(e){super(),this.types=e,this.types=e}valid(e){if(!i.isArray(e))return!1;for(let n=0;nthis.item_type.valid(e)))}}f.__name__=\"Array\",e.Array=f;class K extends d{valid(e){return null===e}}K.__name__=\"Null\",e.Null=K;class b extends d{constructor(e){super(),this.base_type=e}valid(e){return null===e||this.base_type.valid(e)}}b.__name__=\"Nullable\",e.Nullable=b;class A extends d{constructor(e){super(),this.base_type=e}valid(e){return void 0===e||this.base_type.valid(e)}}A.__name__=\"Opt\",e.Opt=A;class x extends d{valid(e){return i.isString(e)}}x.__name__=\"String\",e.String=x;class S extends d{constructor(e){super(),this.values=new Set(e)}valid(e){return this.values.has(e)}*[Symbol.iterator](){yield*this.values}}S.__name__=\"Enum\",e.Enum=S;class N extends d{constructor(e){super(),this.item_type=e}valid(e){if(!i.isPlainObject(e))return!1;for(const n in e)if(u.call(e,n)){const t=e[n];if(!this.item_type.valid(t))return!1}return!0}}N.__name__=\"Dict\",e.Dict=N;class O extends d{constructor(e,n){super(),this.key_type=e,this.item_type=n}valid(e){if(!(e instanceof _))return!1;for(const[n,t]of e.entries())if(!this.key_type.valid(n)||!this.item_type.valid(t))return!1;return!0}}O.__name__=\"Map\",e.Map=O;class g extends d{valid(e){return(0,a.is_Color)(e)}}g.__name__=\"Color\",e.Color=g;class P extends d{valid(e){return i.isFunction(e)}}P.__name__=\"Function\",e.Function=P}(t.Kinds||(t.Kinds={})),t.Any=new t.Kinds.Any,t.Unknown=new t.Kinds.Unknown,t.Boolean=new t.Kinds.Boolean,t.Number=new t.Kinds.Number,t.Int=new t.Kinds.Int,t.String=new t.Kinds.String,t.Null=new t.Kinds.Null;t.Nullable=e=>new t.Kinds.Nullable(e);t.Opt=e=>new t.Kinds.Opt(e);t.Or=(...e)=>new t.Kinds.Or(e);t.Tuple=(...e)=>new t.Kinds.Tuple(e);t.Struct=e=>new t.Kinds.Struct(e),t.Arrayable=new t.Kinds.Arrayable;t.Array=e=>new t.Kinds.Array(e);t.Dict=e=>new t.Kinds.Dict(e);t.Map=(e,n)=>new t.Kinds.Map(e,n);t.Enum=(...e)=>new t.Kinds.Enum(e);t.Ref=e=>new t.Kinds.Ref(e);t.AnyRef=()=>new t.Kinds.AnyRef;t.Function=()=>new t.Kinds.Function,t.Percent=new t.Kinds.Percent,t.Alpha=t.Percent,t.Color=new t.Kinds.Color,t.Auto=(0,t.Enum)(\"auto\"),t.FontSize=t.String,t.Font=t.String,t.Angle=t.Number},\n function _(n,t,r,e,s){e();const u=n(23),c=n(10),l=n(8),{round:i}=Math;function o(n){return(0,c.clamp)(i(n),0,255)}function a(){return[0,0,0,0]}function f(n){return[n>>24&255,n>>16&255,n>>8&255,255&n]}function d(n,t){var r;let e,s,u,c;return null==n?[e,s,u,c]=[0,0,0,0]:(0,l.isInteger)(n)?[e,s,u,c]=f(n):(0,l.isString)(n)?[e,s,u,c]=null!==(r=_(n))&&void 0!==r?r:[0,0,0,0]:([e,s,u,c=1]=n,c=o(255*c)),255==c&&null!=t&&(c=o(255*t)),[e,s,u,c]}r.transparent=a,r.encode_rgba=function([n,t,r,e]){return n<<24|t<<16|r<<8|e},r.decode_rgba=f,r.compose_alpha=function(n,t){return 255==(255&n)?4294967040&n|o(255*t):n},r.color2rgba=d;const h={0:\"0\",1:\"1\",2:\"2\",3:\"3\",4:\"4\",5:\"5\",6:\"6\",7:\"7\",8:\"8\",9:\"9\",10:\"a\",11:\"b\",12:\"c\",13:\"d\",14:\"e\",15:\"f\"};function g(n){return h[n>>4]+h[15&n]}r.color2css=function(n,t){const[r,e,s,u]=d(n,t);return`rgba(${r}, ${e}, ${s}, ${u/255})`},r.color2hex=function(n,t){const[r,e,s,u]=d(n,t),c=`#${g(r)}${g(e)}${g(s)}`;return 255==u?c:`${c}${g(u)}`},r.color2hexrgb=function(n){const[t,r,e]=d(n);return`#${g(t)}${g(r)}${g(e)}`};const b=/^rgba?\\(\\s*([^\\s,]+?)\\s+([^\\s,]+?)\\s+([^\\s,]+?)(?:\\s*\\/\\s*([^\\s,]+?))?\\s*\\)$/,$=/^rgba?\\(\\s*([^\\s,]+?)\\s*,\\s*([^\\s,]+?)\\s*,\\s*([^\\s,]+?)(?:\\s*,\\s*([^\\s,]+?))?\\s*\\)$/,m=(()=>{const n=document.createElement(\"canvas\");n.width=1,n.height=1;const t=n.getContext(\"2d\"),r=t.createLinearGradient(0,0,1,1);return n=>{t.fillStyle=r,t.fillStyle=n;const e=t.fillStyle;return e!=r?e:null}})();function _(n){var t;if(!(n=n.trim().toLowerCase()))return null;if(\"transparent\"==n)return[0,0,0,0];if((0,u.is_named_color)(n))return f(u.named_colors[n]);if(\"#\"==n[0]){const t=Number(`0x${n.substr(1)}`);if(isNaN(t))return null;switch(n.length-1){case 3:{const n=t>>8&15,r=t>>4&15,e=t>>0&15;return[n<<4|n,r<<4|r,e<<4|e,255]}case 4:{const n=t>>12&15,r=t>>8&15,e=t>>4&15,s=t>>0&15;return[n<<4|n,r<<4|r,e<<4|e,s<<4|s]}case 6:return[t>>16&255,t>>8&255,t>>0&255,255];case 8:return[t>>24&255,t>>16&255,t>>8&255,t>>0&255]}}else if(n.startsWith(\"rgb\")){const r=null!==(t=n.match(b))&&void 0!==t?t:n.match($);if(null!=r){let[,n,t,e,s=\"1\"]=r;const u=n.endsWith(\"%\"),c=t.endsWith(\"%\"),l=e.endsWith(\"%\"),i=s.endsWith(\"%\");if(!(u&&c&&l)&&(u||c||l))return null;u&&(n=n.slice(0,-1)),c&&(t=t.slice(0,-1)),l&&(e=e.slice(0,-1)),i&&(s=s.slice(0,-1));let a=Number(n),f=Number(t),d=Number(e),h=Number(s);return isNaN(a+f+d+h)?null:(u&&(a=a/100*255),c&&(f=f/100*255),l&&(d=d/100*255),h=255*(i?h/100:h),a=o(a),f=o(f),d=o(d),h=o(h),[a,f,d,h])}}else{const t=m(n);if(null!=t)return _(t)}return null}r.css4_parse=_,r.is_Color=function(n){return!!(0,l.isInteger)(n)||(!(!(0,l.isString)(n)||null==_(n))||!(!(0,l.isArray)(n)||3!=n.length&&4!=n.length))},r.is_dark=function([n,t,r]){return 1-(.299*n+.587*t+.114*r)/255>=.6}},\n function _(e,r,l,a,i){a();l.named_colors={aliceblue:4042850303,antiquewhite:4209760255,aqua:16777215,aquamarine:2147472639,azure:4043309055,beige:4126530815,bisque:4293182719,black:255,blanchedalmond:4293643775,blue:65535,blueviolet:2318131967,brown:2771004159,burlywood:3736635391,cadetblue:1604231423,chartreuse:2147418367,chocolate:3530104575,coral:4286533887,cornflowerblue:1687547391,cornsilk:4294499583,crimson:3692313855,cyan:16777215,darkblue:35839,darkcyan:9145343,darkgoldenrod:3095792639,darkgray:2846468607,darkgreen:6553855,darkgrey:2846468607,darkkhaki:3182914559,darkmagenta:2332068863,darkolivegreen:1433087999,darkorange:4287365375,darkorchid:2570243327,darkred:2332033279,darksalmon:3918953215,darkseagreen:2411499519,darkslateblue:1211993087,darkslategray:793726975,darkslategrey:793726975,darkturquoise:13554175,darkviolet:2483082239,deeppink:4279538687,deepskyblue:12582911,dimgray:1768516095,dimgrey:1768516095,dodgerblue:512819199,firebrick:2988581631,floralwhite:4294635775,forestgreen:579543807,fuchsia:4278255615,gainsboro:3705462015,ghostwhite:4177068031,gold:4292280575,goldenrod:3668254975,gray:2155905279,green:8388863,greenyellow:2919182335,grey:2155905279,honeydew:4043305215,hotpink:4285117695,indianred:3445382399,indigo:1258324735,ivory:4294963455,khaki:4041641215,lavender:3873897215,lavenderblush:4293981695,lawngreen:2096890111,lemonchiffon:4294626815,lightblue:2916673279,lightcoral:4034953471,lightcyan:3774873599,lightgoldenrodyellow:4210742015,lightgray:3553874943,lightgreen:2431553791,lightgrey:3553874943,lightpink:4290167295,lightsalmon:4288707327,lightseagreen:548580095,lightskyblue:2278488831,lightslategray:2005441023,lightslategrey:2005441023,lightsteelblue:2965692159,lightyellow:4294959359,lime:16711935,limegreen:852308735,linen:4210091775,magenta:4278255615,maroon:2147483903,mediumaquamarine:1724754687,mediumblue:52735,mediumorchid:3126187007,mediumpurple:2473647103,mediumseagreen:1018393087,mediumslateblue:2070474495,mediumspringgreen:16423679,mediumturquoise:1221709055,mediumvioletred:3340076543,midnightblue:421097727,mintcream:4127193855,mistyrose:4293190143,moccasin:4293178879,navajowhite:4292783615,navy:33023,oldlace:4260751103,olive:2155872511,olivedrab:1804477439,orange:4289003775,orangered:4282712319,orchid:3664828159,palegoldenrod:4008225535,palegreen:2566625535,paleturquoise:2951671551,palevioletred:3681588223,papayawhip:4293907967,peachpuff:4292524543,peru:3448061951,pink:4290825215,plum:3718307327,powderblue:2967529215,purple:2147516671,rebeccapurple:1714657791,red:4278190335,rosybrown:3163525119,royalblue:1097458175,saddlebrown:2336560127,salmon:4202722047,sandybrown:4104413439,seagreen:780883967,seashell:4294307583,sienna:2689740287,silver:3233857791,skyblue:2278484991,slateblue:1784335871,slategray:1887473919,slategrey:1887473919,snow:4294638335,springgreen:16744447,steelblue:1182971135,tan:3535047935,teal:8421631,thistle:3636451583,tomato:4284696575,turquoise:1088475391,violet:4001558271,wheat:4125012991,white:4294967295,whitesmoke:4126537215,yellow:4294902015,yellowgreen:2597139199},l.is_named_color=function(e){return e in l.named_colors}},\n function _(r,t,n,a,o){a(),n.GeneratorFunction=Object.getPrototypeOf((function*(){})).constructor,n.ColorArray=Uint32Array,n.RGBAArray=Uint8ClampedArray,n.infer_type=function(r,t){return r instanceof Float64Array||r instanceof Array||t instanceof Float64Array||t instanceof Array?Float64Array:Float32Array},n.ScreenArray=Float32Array,n.to_screen=function(r){return r instanceof Float32Array?r:Float32Array.from(r)},o(\"Indices\",r(25).BitSet)},\n function _(t,s,r,e,i){var n;e();const o=t(26),a=t(11);class _{constructor(t,s=0){this.size=t,this[n]=\"BitSet\",this._count=null,this._nwords=Math.ceil(t/32),0==s||1==s?(this._array=new Uint32Array(this._nwords),1==s&&this._array.fill(4294967295)):((0,a.assert)(s.length==this._nwords,\"Initializer size mismatch\"),this._array=s)}clone(){return new _(this.size,new Uint32Array(this._array))}[(n=Symbol.toStringTag,o.equals)](t,s){if(!s.eq(this.size,t.size))return!1;const{_nwords:r}=this,e=this.size%r,i=0==e?r:r-1;for(let s=0;s>>5,r=31&t;return!!(this._array[s]>>r&1)}set(t,s=!0){this._check_bounds(t),this._count=null;const r=t>>>5,e=31&t;s?this._array[r]|=1<>>t&1&&(e+=1)}return e}*ones(){const{_array:t,_nwords:s,size:r}=this;for(let e=0,i=0;i>>t&1&&(yield e);else e+=32}}*zeros(){const{_array:t,_nwords:s,size:r}=this;for(let e=0,i=0;i>>t&1||(yield e);else e+=32}}_check_size(t){(0,a.assert)(this.size==t.size,\"Size mismatch\")}add(t){this._check_size(t);for(let s=0;s{if(a(t)&&a(e))return t[r.equals](e,this);switch(n){case\"[object Array]\":case\"[object Uint8Array]\":case\"[object Int8Array]\":case\"[object Uint16Array]\":case\"[object Int16Array]\":case\"[object Uint32Array]\":case\"[object Int32Array]\":case\"[object Float32Array]\":case\"[object Float64Array]\":return this.arrays(t,e);case\"[object Map]\":return this.maps(t,e);case\"[object Set]\":return this.sets(t,e);case\"[object Object]\":if(t.constructor==e.constructor&&(null==t.constructor||t.constructor===Object))return this.objects(t,e);case\"[object Function]\":if(t.constructor==e.constructor&&t.constructor===Function)return this.eq(`${t}`,`${e}`)}if(t instanceof Node)return this.nodes(t,e);throw Error(`can't compare objects of type ${n}`)})();return s.pop(),o.pop(),u}numbers(t,e){return Object.is(t,e)}arrays(t,e){const{length:r}=t;if(r!=e.length)return!1;for(let n=0;n{const n=navigator.userAgent;return n.includes(\"MSIE\")||n.includes(\"Trident\")||n.includes(\"Edge\")})(),e.is_mobile=\"undefined\"!=typeof window&&(\"ontouchstart\"in window||navigator.maxTouchPoints>0),e.is_little_endian=(()=>{const n=new ArrayBuffer(4),i=new Uint8Array(n);new Uint32Array(n)[1]=168496141;let e=!0;return 10==i[4]&&11==i[5]&&12==i[6]&&13==i[7]&&(e=!1),e})(),e.BYTE_ORDER=e.is_little_endian?\"little\":\"big\",e.to_big_endian=function(n){if(e.is_little_endian){const i=new Uint32Array(n.length),e=new DataView(i.buffer);let t=0;for(const i of n)e.setUint32(t,i),t+=4;return i}return n}},\n function _(e,t,r,s,_){s();class i{constructor(){this._dev=!1,this._wireframe=!1,this._force_webgl=!1}set dev(e){this._dev=e}get dev(){return this._dev}set wireframe(e){this._wireframe=e}get wireframe(){return this._wireframe}set force_webgl(e){this._force_webgl=e}get force_webgl(){return this._force_webgl}}r.Settings=i,i.__name__=\"Settings\",r.settings=new i},\n function _(e,s,t,i,r){var a,n,l,h,u,o,p,c;i();const y=e(8),_=e(11),A=e(26),q=e(30),d=e(31),z=Symbol(\"__ndarray__\");class D extends Uint8Array{constructor(e,s){super(e),this[a]=!0,this.dtype=\"uint8\",this.shape=null!=s?s:x(e)?e.shape:[this.length],this.dimension=this.shape.length,null==this[A.equals]&&(this[A.equals]=(e,s)=>D.prototype[A.equals].call(this,e,s)),null==this[q.serialize]&&(this[q.serialize]=e=>D.prototype[q.serialize].call(this,e))}[(a=z,A.equals)](e,s){return s.eq(this.shape,e.shape)&&s.arrays(this,e)}[q.serialize](e){return(0,d.encode_NDArray)(this)}}t.Uint8NDArray=D,D.__name__=\"Uint8NDArray\";class N extends Int8Array{constructor(e,s){super(e),this[n]=!0,this.dtype=\"int8\",this.shape=null!=s?s:x(e)?e.shape:[this.length],this.dimension=this.shape.length,null==this[A.equals]&&(this[A.equals]=(e,s)=>N.prototype[A.equals].call(this,e,s)),null==this[q.serialize]&&(this[q.serialize]=e=>N.prototype[q.serialize].call(this,e))}[(n=z,A.equals)](e,s){return s.eq(this.shape,e.shape)&&s.arrays(this,e)}[q.serialize](e){return(0,d.encode_NDArray)(this)}}t.Int8NDArray=N,N.__name__=\"Int8NDArray\";class f extends Uint16Array{constructor(e,s){super(e),this[l]=!0,this.dtype=\"uint16\",this.shape=null!=s?s:x(e)?e.shape:[this.length],this.dimension=this.shape.length,null==this[A.equals]&&(this[A.equals]=(e,s)=>f.prototype[A.equals].call(this,e,s)),null==this[q.serialize]&&(this[q.serialize]=e=>f.prototype[q.serialize].call(this,e))}[(l=z,A.equals)](e,s){return s.eq(this.shape,e.shape)&&s.arrays(this,e)}[q.serialize](e){return(0,d.encode_NDArray)(this)}}t.Uint16NDArray=f,f.__name__=\"Uint16NDArray\";class m extends Int16Array{constructor(e,s){super(e),this[h]=!0,this.dtype=\"int16\",this.shape=null!=s?s:x(e)?e.shape:[this.length],this.dimension=this.shape.length,null==this[A.equals]&&(this[A.equals]=(e,s)=>m.prototype[A.equals].call(this,e,s)),null==this[q.serialize]&&(this[q.serialize]=e=>m.prototype[q.serialize].call(this,e))}[(h=z,A.equals)](e,s){return s.eq(this.shape,e.shape)&&s.arrays(this,e)}[q.serialize](e){return(0,d.encode_NDArray)(this)}}t.Int16NDArray=m,m.__name__=\"Int16NDArray\";class g extends Uint32Array{constructor(e,s){super(e),this[u]=!0,this.dtype=\"uint32\",this.shape=null!=s?s:x(e)?e.shape:[this.length],this.dimension=this.shape.length,null==this[A.equals]&&(this[A.equals]=(e,s)=>g.prototype[A.equals].call(this,e,s)),null==this[q.serialize]&&(this[q.serialize]=e=>g.prototype[q.serialize].call(this,e))}[(u=z,A.equals)](e,s){return s.eq(this.shape,e.shape)&&s.arrays(this,e)}[q.serialize](e){return(0,d.encode_NDArray)(this)}}t.Uint32NDArray=g,g.__name__=\"Uint32NDArray\";class I extends Int32Array{constructor(e,s){super(e),this[o]=!0,this.dtype=\"int32\",this.shape=null!=s?s:x(e)?e.shape:[this.length],this.dimension=this.shape.length,null==this[A.equals]&&(this[A.equals]=(e,s)=>I.prototype[A.equals].call(this,e,s)),null==this[q.serialize]&&(this[q.serialize]=e=>I.prototype[q.serialize].call(this,e))}[(o=z,A.equals)](e,s){return s.eq(this.shape,e.shape)&&s.arrays(this,e)}[q.serialize](e){return(0,d.encode_NDArray)(this)}}t.Int32NDArray=I,I.__name__=\"Int32NDArray\";class U extends Float32Array{constructor(e,s){super(e),this[p]=!0,this.dtype=\"float32\",this.shape=null!=s?s:x(e)?e.shape:[this.length],this.dimension=this.shape.length,null==this[A.equals]&&(this[A.equals]=(e,s)=>U.prototype[A.equals].call(this,e,s)),null==this[q.serialize]&&(this[q.serialize]=e=>U.prototype[q.serialize].call(this,e))}[(p=z,A.equals)](e,s){return s.eq(this.shape,e.shape)&&s.arrays(this,e)}[q.serialize](e){return(0,d.encode_NDArray)(this)}}t.Float32NDArray=U,U.__name__=\"Float32NDArray\";class w extends Float64Array{constructor(e,s){super(e),this[c]=!0,this.dtype=\"float64\",this.shape=null!=s?s:x(e)?e.shape:[this.length],this.dimension=this.shape.length,null==this[A.equals]&&(this[A.equals]=(e,s)=>w.prototype[A.equals].call(this,e,s)),null==this[q.serialize]&&(this[q.serialize]=e=>w.prototype[q.serialize].call(this,e))}[(c=z,A.equals)](e,s){return s.eq(this.shape,e.shape)&&s.arrays(this,e)}[q.serialize](e){return(0,d.encode_NDArray)(this)}}function x(e){return(0,y.isObject)(e)&&void 0!==e[z]}t.Float64NDArray=w,w.__name__=\"Float64NDArray\",t.is_NDArray=x,t.ndarray=function(e,s={}){let{dtype:t}=s;null==t&&(t=e instanceof ArrayBuffer||(0,y.isArray)(e)?\"float64\":(()=>{switch(!0){case e instanceof Uint8Array:return\"uint8\";case e instanceof Int8Array:return\"int8\";case e instanceof Uint16Array:return\"uint16\";case e instanceof Int16Array:return\"int16\";case e instanceof Uint32Array:return\"uint32\";case e instanceof Int32Array:return\"int32\";case e instanceof Float32Array:return\"float32\";case e instanceof Float64Array:return\"float64\";default:(0,_.unreachable)()}})());const{shape:i}=s;switch(t){case\"uint8\":return new D(e,i);case\"int8\":return new N(e,i);case\"uint16\":return new f(e,i);case\"int16\":return new m(e,i);case\"uint32\":return new g(e,i);case\"int32\":return new I(e,i);case\"float32\":return new U(e,i);case\"float64\":return new w(e,i)}}},\n function _(e,r,t,i,s){i();const n=e(11),a=e(13),l=e(8);t.serialize=Symbol(\"serialize\");class o extends Error{}t.SerializationError=o,o.__name__=\"SerializationError\";class f{constructor(e){var r;this._references=new Map,this._definitions=new Map,this._refmap=new Map,this.include_defaults=null===(r=null==e?void 0:e.include_defaults)||void 0===r||r}get_ref(e){return this._references.get(e)}add_ref(e,r){(0,n.assert)(!this._references.has(e)),this._references.set(e,r)}add_def(e,r){const t=this.get_ref(e);(0,n.assert)(null!=t),this._definitions.set(e,r),this._refmap.set(t,r)}get objects(){return new Set(this._references.keys())}get references(){return new Set(this._references.values())}get definitions(){return new Set(this._definitions.values())}resolve_ref(e){return this._refmap.get(e)}remove_ref(e){return this._references.delete(e)}remove_def(e){return this._definitions.delete(e)}to_serializable(e){const r=this.get_ref(e);if(null!=r)return r;if(function(e){return(0,l.isObject)(e)&&void 0!==e[t.serialize]}(e))return e[t.serialize](this);if((0,l.isArray)(e)||(0,l.isTypedArray)(e)){const r=e.length,t=new Array(r);for(let i=0;i(0,s.buffer_to_base64)(_.buffer)};return Object.assign({__ndarray__:e},r)}}},\n function _(t,n,e,r,o){r(),e.buffer_to_base64=function(t){const n=new Uint8Array(t),e=Array.from(n).map((t=>String.fromCharCode(t)));return btoa(e.join(\"\"))},e.base64_to_buffer=function(t){const n=atob(t),e=n.length,r=new Uint8Array(e);for(let t=0,o=e;t\"'`])/g,(t=>{switch(t){case\"&\":return\"&\";case\"<\":return\"<\";case\">\":return\">\";case'\"':return\""\";case\"'\":return\"'\";case\"`\":return\"`\";default:return t}}))},r.unescape=function(t){return t.replace(/&(amp|lt|gt|quot|#x27|#x60);/g,((t,e)=>{switch(e){case\"amp\":return\"&\";case\"lt\":return\"<\";case\"gt\":return\">\";case\"quot\":return'\"';case\"#x27\":return\"'\";case\"#x60\":return\"`\";default:return e}}))},r.use_strict=function(t){return`'use strict';\\n${t}`},r.to_fixed=function(t,e){return t.toFixed(e).replace(/(\\.[0-9]*?)0+$/,\"$1\").replace(/\\.$/,\"\")}},\n function _(e,t,s,n,o){n();const i=e(30);class r{constructor(e){this.document=e}}s.DocumentEvent=r,r.__name__=\"DocumentEvent\";class a extends r{constructor(e,t,s){super(e),this.events=t,this.setter_id=s}}s.DocumentEventBatch=a,a.__name__=\"DocumentEventBatch\";class d extends r{}s.DocumentChangedEvent=d,d.__name__=\"DocumentChangedEvent\";class l extends d{constructor(e,t,s){super(e),this.msg_type=t,this.msg_data=s}[i.serialize](e){const t=this.msg_data,s=e.to_serializable(t);return{kind:\"MessageSent\",msg_type:this.msg_type,msg_data:s}}}s.MessageSentEvent=l,l.__name__=\"MessageSentEvent\";class _ extends d{constructor(e,t,s,n,o,i,r){super(e),this.model=t,this.attr=s,this.old=n,this.new_=o,this.setter_id=i,this.hint=r}[i.serialize](e){if(null!=this.hint)return e.to_serializable(this.hint);const t=this.new_,s=e.to_serializable(t);return this.model!=t&&e.remove_def(this.model),{kind:\"ModelChanged\",model:this.model.ref(),attr:this.attr,new:s}}}s.ModelChangedEvent=_,_.__name__=\"ModelChangedEvent\";class c extends d{constructor(e,t,s){super(e),this.column_source=t,this.patches=s}[i.serialize](e){return{kind:\"ColumnsPatched\",column_source:this.column_source,patches:this.patches}}}s.ColumnsPatchedEvent=c,c.__name__=\"ColumnsPatchedEvent\";class h extends d{constructor(e,t,s,n){super(e),this.column_source=t,this.data=s,this.rollover=n}[i.serialize](e){return{kind:\"ColumnsStreamed\",column_source:this.column_source,data:this.data,rollover:this.rollover}}}s.ColumnsStreamedEvent=h,h.__name__=\"ColumnsStreamedEvent\";class m extends d{constructor(e,t,s){super(e),this.title=t,this.setter_id=s}[i.serialize](e){return{kind:\"TitleChanged\",title:this.title}}}s.TitleChangedEvent=m,m.__name__=\"TitleChangedEvent\";class u extends d{constructor(e,t,s){super(e),this.model=t,this.setter_id=s}[i.serialize](e){return{kind:\"RootAdded\",model:e.to_serializable(this.model)}}}s.RootAddedEvent=u,u.__name__=\"RootAddedEvent\";class v extends d{constructor(e,t,s){super(e),this.model=t,this.setter_id=s}[i.serialize](e){return{kind:\"RootRemoved\",model:this.model.ref()}}}s.RootRemovedEvent=v,v.__name__=\"RootRemovedEvent\"},\n function _(t,i,r,n,s){n();const e=t(8),o=t(13);r.pretty=Symbol(\"pretty\");class c{constructor(t){this.visited=new Set,this.precision=null==t?void 0:t.precision}to_string(t){if((0,e.isObject)(t)){if(this.visited.has(t))return\"\";this.visited.add(t)}return function(t){return(0,e.isObject)(t)&&void 0!==t[r.pretty]}(t)?t[r.pretty](this):(0,e.isBoolean)(t)?this.boolean(t):(0,e.isNumber)(t)?this.number(t):(0,e.isString)(t)?this.string(t):(0,e.isArray)(t)?this.array(t):(0,e.isIterable)(t)?this.iterable(t):(0,e.isPlainObject)(t)?this.object(t):(0,e.isSymbol)(t)?this.symbol(t):`${t}`}token(t){return t}boolean(t){return`${t}`}number(t){return null!=this.precision?t.toFixed(this.precision):`${t}`}string(t){return`\"${t.replace(/'/g,\"\\\\'\")}\"`}symbol(t){return t.toString()}array(t){const i=this.token,r=[];for(const i of t)r.push(this.to_string(i));return`${i(\"[\")}${r.join(`${i(\",\")} `)}${i(\"]\")}`}iterable(t){var i;const r=this.token,n=null!==(i=Object(t)[Symbol.toStringTag])&&void 0!==i?i:\"Object\",s=this.array(t);return`${n}${r(\"(\")}${s}${r(\")\")}`}object(t){const i=this.token,r=[];for(const[n,s]of(0,o.entries)(t))r.push(`${n}${i(\":\")} ${this.to_string(s)}`);return`${i(\"{\")}${r.join(`${i(\",\")} `)}${i(\"}\")}`}}r.Printer=c,c.__name__=\"Printer\",r.to_string=function(t,i){return new c(i).to_string(t)}},\n function _(n,o,r,e,t){e();const l=n(13),i=n(8);function c(n){return(0,i.isObject)(n)&&void 0!==n[r.clone]}r.clone=Symbol(\"clone\"),r.is_Cloneable=c;class s extends Error{}r.CloningError=s,s.__name__=\"CloningError\";class a{constructor(){}clone(n){if(c(n))return n[r.clone](this);if((0,i.isArray)(n)){const o=n.length,r=new Array(o);for(let e=0;e{null!=this.layout&&(this.layout.visible=this.model.visible,this.plot_view.request_layout())}))}get needs_clip(){return null==this.layout}serializable_state(){const t=super.serializable_state();return null==this.layout?t:Object.assign(Object.assign({},t),{bbox:this.layout.bbox.box})}}i.AnnotationView=r,r.__name__=\"AnnotationView\";class a extends l.Renderer{constructor(t){super(t)}}i.Annotation=a,o=a,a.__name__=\"Annotation\",o.override({level:\"annotation\"})},\n function _(e,i,t,n,s){n();const r=e(1);var o,a;const _=e(42),l=(0,r.__importStar)(e(45)),d=e(20),h=e(53),u=e(54);class c extends h.Model{constructor(e){super(e)}}t.RendererGroup=c,o=c,c.__name__=\"RendererGroup\",o.define((({Boolean:e})=>({visible:[e,!0]})));class p extends _.View{get coordinates(){const{_coordinates:e}=this;return null!=e?e:this._coordinates=this._initialize_coordinates()}initialize(){super.initialize(),this.visuals=new l.Visuals(this),this.needs_webgl_blit=!1}connect_signals(){super.connect_signals();const{x_range_name:e,y_range_name:i}=this.model.properties;this.on_change([e,i],(()=>this._initialize_coordinates()));const{group:t}=this.model;null!=t&&this.on_change(t.properties.visible,(()=>{this.model.visible=t.visible}))}_initialize_coordinates(){const{coordinates:e}=this.model,{frame:i}=this.plot_view;if(null!=e)return e.get_transform(i);{const{x_range_name:e,y_range_name:t}=this.model,n=i.x_scales.get(e),s=i.y_scales.get(t);return new u.CoordinateTransform(n,s)}}get plot_view(){return this.parent}get plot_model(){return this.parent.model}get layer(){const{overlays:e,primary:i}=this.canvas;return\"overlay\"==this.model.level?e:i}get canvas(){return this.plot_view.canvas_view}request_render(){this.request_paint()}request_paint(){this.plot_view.request_paint(this)}request_layout(){this.plot_view.request_layout()}notify_finished(){this.plot_view.notify_finished()}notify_finished_after_paint(){this.plot_view.notify_finished_after_paint()}get needs_clip(){return!1}get has_webgl(){return!1}render(){this.model.visible&&this._render(),this._has_finished=!0}renderer_view(e){}}t.RendererView=p,p.__name__=\"RendererView\";class g extends h.Model{constructor(e){super(e)}}t.Renderer=g,a=g,g.__name__=\"Renderer\",a.define((({Boolean:e,String:i,Ref:t,Nullable:n})=>({group:[n(t(c)),null],level:[d.RenderLevel,\"image\"],visible:[e,!0],x_range_name:[i,\"default\"],y_range_name:[i,\"default\"],coordinates:[n(t(u.CoordinateMapping)),null]})))},\n function _(t,e,s,i,n){i();const o=t(1),h=t(15),r=t(43),l=t(8),_=(0,o.__importDefault)(t(44));class d{constructor(t){this.removed=new h.Signal0(this,\"removed\"),this._ready=Promise.resolve(void 0),this._slots=new WeakMap,this._idle_notified=!1;const{model:e,parent:s}=t;this.model=e,this.parent=s,this.root=null==s?this:s.root,this.removed.emit()}get ready(){return this._ready}connect(t,e){let s=this._slots.get(e);return null==s&&(s=(t,s)=>{const i=Promise.resolve(e.call(this,t,s));this._ready=this._ready.then((()=>i))},this._slots.set(e,s)),t.connect(s,this)}disconnect(t,e){return t.disconnect(e,this)}initialize(){this._has_finished=!1,this.is_root&&(this._stylesheet=r.stylesheet);for(const t of this.styles())this.stylesheet.append(t)}async lazy_initialize(){}remove(){this.disconnect_signals(),this.removed.emit()}toString(){return`${this.model.type}View(${this.model.id})`}serializable_state(){return{type:this.model.type}}get is_root(){return null==this.parent}has_finished(){return this._has_finished}get is_idle(){return this.has_finished()}connect_signals(){}disconnect_signals(){h.Signal.disconnect_receiver(this)}on_change(t,e){for(const s of(0,l.isArray)(t)?t:[t])this.connect(s.change,e)}cursor(t,e){return null}get stylesheet(){return this.is_root?this._stylesheet:this.root.stylesheet}styles(){return[_.default]}notify_finished(){this.is_root?!this._idle_notified&&this.has_finished()&&null!=this.model.document&&(this._idle_notified=!0,this.model.document.notify_idle(this.model)):this.root.notify_finished()}}s.View=d,d.__name__=\"View\"},\n function _(t,e,n,i,o){i();const s=t(8),l=t(13),r=t=>(e={},...n)=>{const i=document.createElement(t);i.classList.add(\"bk\"),(0,s.isPlainObject)(e)||(n=[e,...n],e={});for(let[t,n]of(0,l.entries)(e))if(null!=n&&(!(0,s.isBoolean)(n)||n))if(\"class\"===t&&((0,s.isString)(n)&&(n=n.split(/\\s+/)),(0,s.isArray)(n)))for(const t of n)null!=t&&i.classList.add(t);else if(\"style\"===t&&(0,s.isPlainObject)(n))for(const[t,e]of(0,l.entries)(n))i.style[t]=e;else if(\"data\"===t&&(0,s.isPlainObject)(n))for(const[t,e]of(0,l.entries)(n))i.dataset[t]=e;else i.setAttribute(t,n);function o(t){if((0,s.isString)(t))i.appendChild(document.createTextNode(t));else if(t instanceof Node)i.appendChild(t);else if(t instanceof NodeList||t instanceof HTMLCollection)for(const e of t)i.appendChild(e);else if(null!=t&&!1!==t)throw new Error(`expected a DOM element, string, false or null, got ${JSON.stringify(t)}`)}for(const t of n)if((0,s.isArray)(t))for(const e of t)o(e);else o(t);return i};function a(t){const e=t.parentNode;null!=e&&e.removeChild(t)}function c(t,...e){const n=t.firstChild;for(const i of e)t.insertBefore(i,n)}function d(t,e){var n,i,o;const s=Element.prototype;return(null!==(o=null!==(i=null!==(n=s.matches)&&void 0!==n?n:s.webkitMatchesSelector)&&void 0!==i?i:s.mozMatchesSelector)&&void 0!==o?o:s.msMatchesSelector).call(t,e)}function h(t){return parseFloat(t)||0}function f(t){const e=getComputedStyle(t);return{border:{top:h(e.borderTopWidth),bottom:h(e.borderBottomWidth),left:h(e.borderLeftWidth),right:h(e.borderRightWidth)},margin:{top:h(e.marginTop),bottom:h(e.marginBottom),left:h(e.marginLeft),right:h(e.marginRight)},padding:{top:h(e.paddingTop),bottom:h(e.paddingBottom),left:h(e.paddingLeft),right:h(e.paddingRight)}}}function u(t){const e=t.getBoundingClientRect();return{width:Math.ceil(e.width),height:Math.ceil(e.height)}}n.createElement=function(t,e,...n){return r(t)(e,...n)},n.div=r(\"div\"),n.span=r(\"span\"),n.canvas=r(\"canvas\"),n.link=r(\"link\"),n.style=r(\"style\"),n.a=r(\"a\"),n.p=r(\"p\"),n.i=r(\"i\"),n.pre=r(\"pre\"),n.button=r(\"button\"),n.label=r(\"label\"),n.input=r(\"input\"),n.select=r(\"select\"),n.option=r(\"option\"),n.optgroup=r(\"optgroup\"),n.textarea=r(\"textarea\"),n.createSVGElement=function(t,e,...n){const i=document.createElementNS(\"http://www.w3.org/2000/svg\",t);for(const[t,n]of(0,l.entries)(null!=e?e:{}))null==n||(0,s.isBoolean)(n)&&!n||i.setAttribute(t,n);function o(t){if((0,s.isString)(t))i.appendChild(document.createTextNode(t));else if(t instanceof Node)i.appendChild(t);else if(t instanceof NodeList||t instanceof HTMLCollection)for(const e of t)i.appendChild(e);else if(null!=t&&!1!==t)throw new Error(`expected a DOM element, string, false or null, got ${JSON.stringify(t)}`)}for(const t of n)if((0,s.isArray)(t))for(const e of t)o(e);else o(t);return i},n.nbsp=function(){return document.createTextNode(\"\\xa0\")},n.append=function(t,...e){for(const n of e)t.appendChild(n)},n.remove=a,n.removeElement=a,n.replaceWith=function(t,e){const n=t.parentNode;null!=n&&n.replaceChild(e,t)},n.prepend=c,n.empty=function(t,e=!1){let n;for(;n=t.firstChild;)t.removeChild(n);if(e&&t instanceof Element)for(const e of t.attributes)t.removeAttributeNode(e)},n.display=function(t){t.style.display=\"\"},n.undisplay=function(t){t.style.display=\"none\"},n.show=function(t){t.style.visibility=\"\"},n.hide=function(t){t.style.visibility=\"hidden\"},n.offset=function(t){const e=t.getBoundingClientRect();return{top:e.top+window.pageYOffset-document.documentElement.clientTop,left:e.left+window.pageXOffset-document.documentElement.clientLeft}},n.matches=d,n.parent=function(t,e){let n=t;for(;n=n.parentElement;)if(d(n,e))return n;return null},n.extents=f,n.size=u,n.scroll_size=function(t){return{width:Math.ceil(t.scrollWidth),height:Math.ceil(t.scrollHeight)}},n.outer_size=function(t){const{margin:{left:e,right:n,top:i,bottom:o}}=f(t),{width:s,height:l}=u(t);return{width:Math.ceil(s+e+n),height:Math.ceil(l+i+o)}},n.content_size=function(t){const{left:e,top:n}=t.getBoundingClientRect(),{padding:i}=f(t);let o=0,s=0;for(const l of t.children){const t=l.getBoundingClientRect();o=Math.max(o,Math.ceil(t.left-e-i.left+t.width)),s=Math.max(s,Math.ceil(t.top-n-i.top+t.height))}return{width:o,height:s}},n.position=function(t,e,n){const{style:i}=t;if(i.left=`${e.x}px`,i.top=`${e.y}px`,i.width=`${e.width}px`,i.height=`${e.height}px`,null==n)i.margin=\"\";else{const{top:t,right:e,bottom:o,left:s}=n;i.margin=`${t}px ${e}px ${o}px ${s}px`}},n.children=function(t){return Array.from(t.children)};class p{constructor(t){this.el=t,this.classList=t.classList}get values(){const t=[];for(let e=0;e{document.addEventListener(\"DOMContentLoaded\",(()=>t()),{once:!0})}))}},\n function _(o,i,t,e,r){e(),t.root=\"bk-root\",t.default=\".bk-root{position:relative;width:auto;height:auto;box-sizing:border-box;font-family:Helvetica, Arial, sans-serif;font-size:13px;}.bk-root .bk,.bk-root .bk:before,.bk-root .bk:after{box-sizing:inherit;margin:0;border:0;padding:0;background-image:none;font-family:inherit;font-size:100%;line-height:1.42857143;}.bk-root pre.bk{font-family:Courier, monospace;}\"},\n function _(e,t,r,a,c){a();const n=e(1),l=e(46);c(\"Line\",l.Line),c(\"LineScalar\",l.LineScalar),c(\"LineVector\",l.LineVector);const i=e(49);c(\"Fill\",i.Fill),c(\"FillScalar\",i.FillScalar),c(\"FillVector\",i.FillVector);const s=e(50);c(\"Text\",s.Text),c(\"TextScalar\",s.TextScalar),c(\"TextVector\",s.TextVector);const o=e(51);c(\"Hatch\",o.Hatch),c(\"HatchScalar\",o.HatchScalar),c(\"HatchVector\",o.HatchVector);const u=(0,n.__importStar)(e(48)),V=e(47);c(\"VisualProperties\",V.VisualProperties),c(\"VisualUniforms\",V.VisualUniforms);class h{constructor(e){this._visuals=[];for(const[t,r]of e.model._mixins){const a=(()=>{switch(r){case u.Line:return new l.Line(e,t);case u.LineScalar:return new l.LineScalar(e,t);case u.LineVector:return new l.LineVector(e,t);case u.Fill:return new i.Fill(e,t);case u.FillScalar:return new i.FillScalar(e,t);case u.FillVector:return new i.FillVector(e,t);case u.Text:return new s.Text(e,t);case u.TextScalar:return new s.TextScalar(e,t);case u.TextVector:return new s.TextVector(e,t);case u.Hatch:return new o.Hatch(e,t);case u.HatchScalar:return new o.HatchScalar(e,t);case u.HatchVector:return new o.HatchVector(e,t);default:throw new Error(\"unknown visual\")}})();a instanceof V.VisualProperties&&a.update(),this._visuals.push(a),Object.defineProperty(this,t+a.type,{get:()=>a,configurable:!1,enumerable:!0})}}*[Symbol.iterator](){yield*this._visuals}}r.Visuals=h,h.__name__=\"Visuals\"},\n function _(e,t,i,l,s){l();const a=e(1),n=e(47),h=(0,a.__importStar)(e(48)),o=e(22),_=e(8);function r(e){if((0,_.isArray)(e))return e;switch(e){case\"solid\":return[];case\"dashed\":return[6];case\"dotted\":return[2,4];case\"dotdash\":return[2,4,6,4];case\"dashdot\":return[6,4,2,4];default:return e.split(\" \").map(Number).filter(_.isInteger)}}i.resolve_line_dash=r;class u extends n.VisualProperties{get doit(){const e=this.line_color.get_value(),t=this.line_alpha.get_value(),i=this.line_width.get_value();return!(null==e||0==t||0==i)}apply(e){const{doit:t}=this;return t&&(this.set_value(e),e.stroke()),t}values(){return{color:this.line_color.get_value(),alpha:this.line_alpha.get_value(),width:this.line_width.get_value(),join:this.line_join.get_value(),cap:this.line_cap.get_value(),dash:this.line_dash.get_value(),offset:this.line_dash_offset.get_value()}}set_value(e){const t=this.line_color.get_value(),i=this.line_alpha.get_value();e.strokeStyle=(0,o.color2css)(t,i),e.lineWidth=this.line_width.get_value(),e.lineJoin=this.line_join.get_value(),e.lineCap=this.line_cap.get_value(),e.lineDash=r(this.line_dash.get_value()),e.lineDashOffset=this.line_dash_offset.get_value()}}i.Line=u,u.__name__=\"Line\";class c extends n.VisualUniforms{get doit(){const e=this.line_color.value,t=this.line_alpha.value,i=this.line_width.value;return!(0==e||0==t||0==i)}apply(e){const{doit:t}=this;return t&&(this.set_value(e),e.stroke()),t}values(){return{color:this.line_color.value,alpha:this.line_alpha.value,width:this.line_width.value,join:this.line_join.value,cap:this.line_cap.value,dash:this.line_dash.value,offset:this.line_dash_offset.value}}set_value(e){const t=this.line_color.value,i=this.line_alpha.value;e.strokeStyle=(0,o.color2css)(t,i),e.lineWidth=this.line_width.value,e.lineJoin=this.line_join.value,e.lineCap=this.line_cap.value,e.lineDash=r(this.line_dash.value),e.lineDashOffset=this.line_dash_offset.value}}i.LineScalar=c,c.__name__=\"LineScalar\";class d extends n.VisualUniforms{get doit(){const{line_color:e}=this;if(e.is_Scalar()&&0==e.value)return!1;const{line_alpha:t}=this;if(t.is_Scalar()&&0==t.value)return!1;const{line_width:i}=this;return!i.is_Scalar()||0!=i.value}apply(e,t){const{doit:i}=this;return i&&(this.set_vectorize(e,t),e.stroke()),i}values(e){return{color:this.line_color.get(e),alpha:this.line_alpha.get(e),width:this.line_width.get(e),join:this.line_join.get(e),cap:this.line_cap.get(e),dash:this.line_dash.get(e),offset:this.line_dash_offset.get(e)}}set_vectorize(e,t){const i=this.line_color.get(t),l=this.line_alpha.get(t),s=this.line_width.get(t),a=this.line_join.get(t),n=this.line_cap.get(t),h=this.line_dash.get(t),_=this.line_dash_offset.get(t);e.strokeStyle=(0,o.color2css)(i,l),e.lineWidth=s,e.lineJoin=a,e.lineCap=n,e.lineDash=r(h),e.lineDashOffset=_}}i.LineVector=d,d.__name__=\"LineVector\",u.prototype.type=\"line\",u.prototype.attrs=Object.keys(h.Line),c.prototype.type=\"line\",c.prototype.attrs=Object.keys(h.LineScalar),d.prototype.type=\"line\",d.prototype.attrs=Object.keys(h.LineVector)},\n function _(t,s,o,i,r){i();class e{constructor(t,s=\"\"){this.obj=t,this.prefix=s;const o=this;this._props=[];for(const i of this.attrs){const r=t.model.properties[s+i];r.change.connect((()=>this.update())),o[i]=r,this._props.push(r)}}*[Symbol.iterator](){yield*this._props}update(){}}o.VisualProperties=e,e.__name__=\"VisualProperties\";class p{constructor(t,s=\"\"){this.obj=t,this.prefix=s;for(const o of this.attrs)Object.defineProperty(this,o,{get:()=>t[s+o]})}*[Symbol.iterator](){for(const t of this.attrs)yield this.obj.model.properties[this.prefix+t]}update(){}}o.VisualUniforms=p,p.__name__=\"VisualUniforms\"},\n function _(e,l,t,a,c){a();const r=e(1),o=(0,r.__importStar)(e(18)),n=e(20),i=(0,r.__importStar)(e(21)),_=e(13);t.Line={line_color:[i.Nullable(i.Color),\"black\"],line_alpha:[i.Alpha,1],line_width:[i.Number,1],line_join:[n.LineJoin,\"bevel\"],line_cap:[n.LineCap,\"butt\"],line_dash:[i.Or(n.LineDash,i.Array(i.Number)),[]],line_dash_offset:[i.Number,0]},t.Fill={fill_color:[i.Nullable(i.Color),\"gray\"],fill_alpha:[i.Alpha,1]},t.Hatch={hatch_color:[i.Nullable(i.Color),\"black\"],hatch_alpha:[i.Alpha,1],hatch_scale:[i.Number,12],hatch_pattern:[i.Nullable(i.Or(n.HatchPatternType,i.String)),null],hatch_weight:[i.Number,1],hatch_extra:[i.Dict(i.AnyRef()),{}]},t.Text={text_color:[i.Nullable(i.Color),\"#444444\"],text_alpha:[i.Alpha,1],text_font:[o.Font,\"helvetica\"],text_font_size:[i.FontSize,\"16px\"],text_font_style:[n.FontStyle,\"normal\"],text_align:[n.TextAlign,\"left\"],text_baseline:[n.TextBaseline,\"bottom\"],text_line_height:[i.Number,1.2]},t.LineScalar={line_color:[o.ColorScalar,\"black\"],line_alpha:[o.NumberScalar,1],line_width:[o.NumberScalar,1],line_join:[o.LineJoinScalar,\"bevel\"],line_cap:[o.LineCapScalar,\"butt\"],line_dash:[o.LineDashScalar,[]],line_dash_offset:[o.NumberScalar,0]},t.FillScalar={fill_color:[o.ColorScalar,\"gray\"],fill_alpha:[o.NumberScalar,1]},t.HatchScalar={hatch_color:[o.ColorScalar,\"black\"],hatch_alpha:[o.NumberScalar,1],hatch_scale:[o.NumberScalar,12],hatch_pattern:[o.NullStringScalar,null],hatch_weight:[o.NumberScalar,1],hatch_extra:[o.AnyScalar,{}]},t.TextScalar={text_color:[o.ColorScalar,\"#444444\"],text_alpha:[o.NumberScalar,1],text_font:[o.FontScalar,\"helvetica\"],text_font_size:[o.FontSizeScalar,\"16px\"],text_font_style:[o.FontStyleScalar,\"normal\"],text_align:[o.TextAlignScalar,\"left\"],text_baseline:[o.TextBaselineScalar,\"bottom\"],text_line_height:[o.NumberScalar,1.2]},t.LineVector={line_color:[o.ColorSpec,\"black\"],line_alpha:[o.NumberSpec,1],line_width:[o.NumberSpec,1],line_join:[o.LineJoinSpec,\"bevel\"],line_cap:[o.LineCapSpec,\"butt\"],line_dash:[o.LineDashSpec,[]],line_dash_offset:[o.NumberSpec,0]},t.FillVector={fill_color:[o.ColorSpec,\"gray\"],fill_alpha:[o.NumberSpec,1]},t.HatchVector={hatch_color:[o.ColorSpec,\"black\"],hatch_alpha:[o.NumberSpec,1],hatch_scale:[o.NumberSpec,12],hatch_pattern:[o.NullStringSpec,null],hatch_weight:[o.NumberSpec,1],hatch_extra:[o.AnyScalar,{}]},t.TextVector={text_color:[o.ColorSpec,\"#444444\"],text_alpha:[o.NumberSpec,1],text_font:[o.FontSpec,\"helvetica\"],text_font_size:[o.FontSizeSpec,\"16px\"],text_font_style:[o.FontStyleSpec,\"normal\"],text_align:[o.TextAlignSpec,\"left\"],text_baseline:[o.TextBaselineSpec,\"bottom\"],text_line_height:[o.NumberSpec,1.2]},t.attrs_of=function(e,l,t,a=!1){const c={};for(const r of(0,_.keys)(t)){const t=`${l}${r}`,o=e[t];c[a?t:r]=o}return c}},\n function _(l,t,e,i,s){i();const a=l(1),o=l(47),r=(0,a.__importStar)(l(48)),_=l(22);class c extends o.VisualProperties{get doit(){const l=this.fill_color.get_value(),t=this.fill_alpha.get_value();return!(null==l||0==t)}apply(l,t){const{doit:e}=this;return e&&(this.set_value(l),l.fill(t)),e}values(){return{color:this.fill_color.get_value(),alpha:this.fill_alpha.get_value()}}set_value(l){const t=this.fill_color.get_value(),e=this.fill_alpha.get_value();l.fillStyle=(0,_.color2css)(t,e)}}e.Fill=c,c.__name__=\"Fill\";class h extends o.VisualUniforms{get doit(){const l=this.fill_color.value,t=this.fill_alpha.value;return!(0==l||0==t)}apply(l,t){const{doit:e}=this;return e&&(this.set_value(l),l.fill(t)),e}values(){return{color:this.fill_color.value,alpha:this.fill_alpha.value}}set_value(l){const t=this.fill_color.value,e=this.fill_alpha.value;l.fillStyle=(0,_.color2css)(t,e)}}e.FillScalar=h,h.__name__=\"FillScalar\";class u extends o.VisualUniforms{get doit(){const{fill_color:l}=this;if(l.is_Scalar()&&0==l.value)return!1;const{fill_alpha:t}=this;return!t.is_Scalar()||0!=t.value}apply(l,t,e){const{doit:i}=this;return i&&(this.set_vectorize(l,t),l.fill(e)),i}values(l){return{color:this.fill_color.get(l),alpha:this.fill_alpha.get(l)}}set_vectorize(l,t){const e=this.fill_color.get(t),i=this.fill_alpha.get(t);l.fillStyle=(0,_.color2css)(e,i)}}e.FillVector=u,u.__name__=\"FillVector\",c.prototype.type=\"fill\",c.prototype.attrs=Object.keys(r.Fill),h.prototype.type=\"fill\",h.prototype.attrs=Object.keys(r.FillScalar),u.prototype.type=\"fill\",u.prototype.attrs=Object.keys(r.FillVector)},\n function _(t,e,l,s,_){s();const i=t(1),a=t(47),o=(0,i.__importStar)(t(48)),n=t(22);class h extends a.VisualProperties{get doit(){const t=this.text_color.get_value(),e=this.text_alpha.get_value();return!(null==t||0==e)}values(){return{color:this.text_color.get_value(),alpha:this.text_alpha.get_value(),font:this.text_font.get_value(),font_size:this.text_font_size.get_value(),font_style:this.text_font_style.get_value(),align:this.text_align.get_value(),baseline:this.text_baseline.get_value(),line_height:this.text_line_height.get_value()}}set_value(t){const e=this.text_color.get_value(),l=this.text_alpha.get_value();t.fillStyle=(0,n.color2css)(e,l),t.font=this.font_value(),t.textAlign=this.text_align.get_value(),t.textBaseline=this.text_baseline.get_value()}font_value(){return`${this.text_font_style.get_value()} ${this.text_font_size.get_value()} ${this.text_font.get_value()}`}}l.Text=h,h.__name__=\"Text\";class x extends a.VisualUniforms{get doit(){const t=this.text_color.value,e=this.text_alpha.value;return!(0==t||0==e)}values(){return{color:this.text_color.value,alpha:this.text_alpha.value,font:this.text_font.value,font_size:this.text_font_size.value,font_style:this.text_font_style.value,align:this.text_align.value,baseline:this.text_baseline.value,line_height:this.text_line_height.value}}set_value(t){const e=this.text_color.value,l=this.text_alpha.value,s=this.font_value(),_=this.text_align.value,i=this.text_baseline.value;t.fillStyle=(0,n.color2css)(e,l),t.font=s,t.textAlign=_,t.textBaseline=i}font_value(){return`${this.text_font_style.value} ${this.text_font_size.value} ${this.text_font.value}`}}l.TextScalar=x,x.__name__=\"TextScalar\";class u extends a.VisualUniforms{values(t){return{color:this.text_color.get(t),alpha:this.text_alpha.get(t),font:this.text_font.get(t),font_size:this.text_font_size.get(t),font_style:this.text_font_style.get(t),align:this.text_align.get(t),baseline:this.text_baseline.get(t),line_height:this.text_line_height.get(t)}}get doit(){const{text_color:t}=this;if(t.is_Scalar()&&0==t.value)return!1;const{text_alpha:e}=this;return!e.is_Scalar()||0!=e.value}set_vectorize(t,e){const l=this.text_color.get(e),s=this.text_alpha.get(e),_=this.font_value(e),i=this.text_align.get(e),a=this.text_baseline.get(e);t.fillStyle=(0,n.color2css)(l,s),t.font=_,t.textAlign=i,t.textBaseline=a}font_value(t){return`${this.text_font_style.get(t)} ${this.text_font_size.get(t)} ${this.text_font.get(t)}`}}l.TextVector=u,u.__name__=\"TextVector\",h.prototype.type=\"text\",h.prototype.attrs=Object.keys(o.Text),x.prototype.type=\"text\",x.prototype.attrs=Object.keys(o.TextScalar),u.prototype.type=\"text\",u.prototype.attrs=Object.keys(o.TextVector)},\n function _(t,e,a,r,i){r();const h=t(1),s=t(47),n=t(52),c=(0,h.__importStar)(t(18)),_=(0,h.__importStar)(t(48));class l extends s.VisualProperties{constructor(){super(...arguments),this._update_iteration=0}update(){if(this._update_iteration++,this._hatch_image=null,!this.doit)return;const t=this.hatch_color.get_value(),e=this.hatch_alpha.get_value(),a=this.hatch_scale.get_value(),r=this.hatch_pattern.get_value(),i=this.hatch_weight.get_value(),h=t=>{this._hatch_image=t},s=this.hatch_extra.get_value()[r];if(null!=s){const r=s.get_pattern(t,e,a,i);if(r instanceof Promise){const{_update_iteration:t}=this;r.then((e=>{this._update_iteration==t&&(h(e),this.obj.request_render())}))}else h(r)}else{const s=this.obj.canvas.create_layer(),c=(0,n.get_pattern)(s,r,t,e,a,i);h(c)}}get doit(){const t=this.hatch_color.get_value(),e=this.hatch_alpha.get_value(),a=this.hatch_pattern.get_value();return!(null==t||0==e||\" \"==a||\"blank\"==a||null==a)}apply(t,e){const{doit:a}=this;return a&&(this.set_value(t),t.layer.undo_transform((()=>t.fill(e)))),a}set_value(t){const e=this.pattern(t);t.fillStyle=null!=e?e:\"transparent\"}pattern(t){const e=this._hatch_image;return null==e?null:t.createPattern(e,this.repetition())}repetition(){const t=this.hatch_pattern.get_value(),e=this.hatch_extra.get_value()[t];if(null==e)return\"repeat\";switch(e.repetition){case\"repeat\":return\"repeat\";case\"repeat_x\":return\"repeat-x\";case\"repeat_y\":return\"repeat-y\";case\"no_repeat\":return\"no-repeat\"}}}a.Hatch=l,l.__name__=\"Hatch\";class o extends s.VisualUniforms{constructor(){super(...arguments),this._static_doit=!1,this._update_iteration=0}_compute_static_doit(){const t=this.hatch_color.value,e=this.hatch_alpha.value,a=this.hatch_pattern.value;return!(null==t||0==e||\" \"==a||\"blank\"==a||null==a)}update(){this._update_iteration++;const t=this.hatch_color.length;if(this._hatch_image=new c.UniformScalar(null,t),this._static_doit=this._compute_static_doit(),!this._static_doit)return;const e=this.hatch_color.value,a=this.hatch_alpha.value,r=this.hatch_scale.value,i=this.hatch_pattern.value,h=this.hatch_weight.value,s=e=>{this._hatch_image=new c.UniformScalar(e,t)},_=this.hatch_extra.value[i];if(null!=_){const t=_.get_pattern(e,a,r,h);if(t instanceof Promise){const{_update_iteration:e}=this;t.then((t=>{this._update_iteration==e&&(s(t),this.obj.request_render())}))}else s(t)}else{const t=this.obj.canvas.create_layer(),c=(0,n.get_pattern)(t,i,e,a,r,h);s(c)}}get doit(){return this._static_doit}apply(t,e){const{doit:a}=this;return a&&(this.set_value(t),t.layer.undo_transform((()=>t.fill(e)))),a}set_value(t){var e;t.fillStyle=null!==(e=this.pattern(t))&&void 0!==e?e:\"transparent\"}pattern(t){const e=this._hatch_image.value;return null==e?null:t.createPattern(e,this.repetition())}repetition(){const t=this.hatch_pattern.value,e=this.hatch_extra.value[t];if(null==e)return\"repeat\";switch(e.repetition){case\"repeat\":return\"repeat\";case\"repeat_x\":return\"repeat-x\";case\"repeat_y\":return\"repeat-y\";case\"no_repeat\":return\"no-repeat\"}}}a.HatchScalar=o,o.__name__=\"HatchScalar\";class u extends s.VisualUniforms{constructor(){super(...arguments),this._static_doit=!1,this._update_iteration=0}_compute_static_doit(){const{hatch_color:t}=this;if(t.is_Scalar()&&0==t.value)return!1;const{hatch_alpha:e}=this;if(e.is_Scalar()&&0==e.value)return!1;const{hatch_pattern:a}=this;if(a.is_Scalar()){const t=a.value;if(\" \"==t||\"blank\"==t||null==t)return!1}return!0}update(){this._update_iteration++;const t=this.hatch_color.length;if(this._hatch_image=new c.UniformScalar(null,t),this._static_doit=this._compute_static_doit(),!this._static_doit)return;const e=(t,e,a,r,i,h)=>{const s=this.hatch_extra.value[t];if(null!=s){const t=s.get_pattern(e,a,r,i);if(t instanceof Promise){const{_update_iteration:e}=this;t.then((t=>{this._update_iteration==e&&(h(t),this.obj.request_render())}))}else h(t)}else{const s=this.obj.canvas.create_layer(),c=(0,n.get_pattern)(s,t,e,a,r,i);h(c)}};if(this.hatch_color.is_Scalar()&&this.hatch_alpha.is_Scalar()&&this.hatch_scale.is_Scalar()&&this.hatch_pattern.is_Scalar()&&this.hatch_weight.is_Scalar()){const a=this.hatch_color.value,r=this.hatch_alpha.value,i=this.hatch_scale.value;e(this.hatch_pattern.value,a,r,i,this.hatch_weight.value,(e=>{this._hatch_image=new c.UniformScalar(e,t)}))}else{const a=new Array(t);a.fill(null),this._hatch_image=new c.UniformVector(a);for(let r=0;r{a[r]=t}))}}}get doit(){return this._static_doit}apply(t,e,a){const{doit:r}=this;return r&&(this.set_vectorize(t,e),t.layer.undo_transform((()=>t.fill(a)))),r}set_vectorize(t,e){var a;t.fillStyle=null!==(a=this.pattern(t,e))&&void 0!==a?a:\"transparent\"}pattern(t,e){const a=this._hatch_image.get(e);return null==a?null:t.createPattern(a,this.repetition(e))}repetition(t){const e=this.hatch_pattern.get(t),a=this.hatch_extra.value[e];if(null==a)return\"repeat\";switch(a.repetition){case\"repeat\":return\"repeat\";case\"repeat_x\":return\"repeat-x\";case\"repeat_y\":return\"repeat-y\";case\"no_repeat\":return\"no-repeat\"}}}a.HatchVector=u,u.__name__=\"HatchVector\",l.prototype.type=\"hatch\",l.prototype.attrs=Object.keys(_.Hatch),o.prototype.type=\"hatch\",o.prototype.attrs=Object.keys(_.HatchScalar),u.prototype.type=\"hatch\",u.prototype.attrs=Object.keys(_.HatchVector)},\n function _(e,o,a,s,r){s();const i=e(22);function l(e,o,a){e.moveTo(0,a+.5),e.lineTo(o,a+.5),e.stroke()}function n(e,o,a){e.moveTo(a+.5,0),e.lineTo(a+.5,o),e.stroke()}function t(e,o){e.moveTo(0,o),e.lineTo(o,0),e.stroke(),e.moveTo(0,0),e.lineTo(o,o),e.stroke()}a.hatch_aliases={\" \":\"blank\",\".\":\"dot\",o:\"ring\",\"-\":\"horizontal_line\",\"|\":\"vertical_line\",\"+\":\"cross\",'\"':\"horizontal_dash\",\":\":\"vertical_dash\",\"@\":\"spiral\",\"/\":\"right_diagonal_line\",\"\\\\\":\"left_diagonal_line\",x:\"diagonal_cross\",\",\":\"right_diagonal_dash\",\"`\":\"left_diagonal_dash\",v:\"horizontal_wave\",\">\":\"vertical_wave\",\"*\":\"criss_cross\"},a.get_pattern=function(e,o,s,r,c,k){return e.resize(c,c),e.prepare(),function(e,o,s,r,c,k){var _;const T=c,v=T/2,h=v/2,d=(0,i.color2css)(s,r);switch(e.strokeStyle=d,e.fillStyle=d,e.lineCap=\"square\",e.lineWidth=k,null!==(_=a.hatch_aliases[o])&&void 0!==_?_:o){case\"blank\":break;case\"dot\":e.arc(v,v,v/2,0,2*Math.PI,!0),e.fill();break;case\"ring\":e.arc(v,v,v/2,0,2*Math.PI,!0),e.stroke();break;case\"horizontal_line\":l(e,T,v);break;case\"vertical_line\":n(e,T,v);break;case\"cross\":l(e,T,v),n(e,T,v);break;case\"horizontal_dash\":l(e,v,v);break;case\"vertical_dash\":n(e,v,v);break;case\"spiral\":{const o=T/30;e.moveTo(v,v);for(let a=0;a<360;a++){const s=.1*a,r=v+o*s*Math.cos(s),i=v+o*s*Math.sin(s);e.lineTo(r,i)}e.stroke();break}case\"right_diagonal_line\":e.moveTo(.5-h,T),e.lineTo(h+.5,0),e.stroke(),e.moveTo(h+.5,T),e.lineTo(3*h+.5,0),e.stroke(),e.moveTo(3*h+.5,T),e.lineTo(5*h+.5,0),e.stroke(),e.stroke();break;case\"left_diagonal_line\":e.moveTo(h+.5,T),e.lineTo(.5-h,0),e.stroke(),e.moveTo(3*h+.5,T),e.lineTo(h+.5,0),e.stroke(),e.moveTo(5*h+.5,T),e.lineTo(3*h+.5,0),e.stroke(),e.stroke();break;case\"diagonal_cross\":t(e,T);break;case\"right_diagonal_dash\":e.moveTo(h+.5,3*h+.5),e.lineTo(3*h+.5,h+.5),e.stroke();break;case\"left_diagonal_dash\":e.moveTo(h+.5,h+.5),e.lineTo(3*h+.5,3*h+.5),e.stroke();break;case\"horizontal_wave\":e.moveTo(0,h),e.lineTo(v,3*h),e.lineTo(T,h),e.stroke();break;case\"vertical_wave\":e.moveTo(h,0),e.lineTo(3*h,v),e.lineTo(h,T),e.stroke();break;case\"criss_cross\":t(e,T),l(e,T,v),n(e,T,v)}}(e.ctx,o,s,r,c,k),e.canvas}},\n function _(e,t,s,n,c){var a;n();const i=e(14),r=e(8),l=e(13),o=e(26),_=e(19);class h extends i.HasProps{constructor(e){super(e)}get is_syncable(){return this.syncable}[o.equals](e,t){return t.eq(this.id,e.id)&&super[o.equals](e,t)}initialize(){super.initialize(),this._js_callbacks=new Map}connect_signals(){super.connect_signals(),this._update_property_callbacks(),this.connect(this.properties.js_property_callbacks.change,(()=>this._update_property_callbacks())),this.connect(this.properties.js_event_callbacks.change,(()=>this._update_event_callbacks())),this.connect(this.properties.subscribed_events.change,(()=>this._update_event_callbacks()))}_process_event(e){var t;for(const s of null!==(t=this.js_event_callbacks[e.event_name])&&void 0!==t?t:[])s.execute(e);null!=this.document&&this.subscribed_events.some((t=>t==e.event_name))&&this.document.event_manager.send_event(e)}trigger_event(e){null!=this.document&&(e.origin=this,this.document.event_manager.trigger(e))}_update_event_callbacks(){null!=this.document?this.document.event_manager.subscribed_models.add(this):_.logger.warn(\"WARNING: Document not defined for updating event callbacks\")}_update_property_callbacks(){const e=e=>{const[t,s=null]=e.split(\":\");return null!=s?this.properties[s][t]:this[t]};for(const[t,s]of this._js_callbacks){const n=e(t);for(const e of s)this.disconnect(n,e)}this._js_callbacks.clear();for(const[t,s]of(0,l.entries)(this.js_property_callbacks)){const n=s.map((e=>()=>e.execute(this)));this._js_callbacks.set(t,n);const c=e(t);for(const e of n)this.connect(c,e)}}_doc_attached(){(0,l.isEmpty)(this.js_event_callbacks)&&0==this.subscribed_events.length||this._update_event_callbacks()}_doc_detached(){this.document.event_manager.subscribed_models.delete(this)}select(e){if((0,r.isString)(e))return[...this.references()].filter((t=>t instanceof h&&t.name===e));if(e.prototype instanceof i.HasProps)return[...this.references()].filter((t=>t instanceof e));throw new Error(\"invalid selector\")}select_one(e){const t=this.select(e);switch(t.length){case 0:return null;case 1:return t[0];default:throw new Error(\"found more than one object matching given selector\")}}}s.Model=h,a=h,h.__name__=\"Model\",a.define((({Any:e,Unknown:t,Boolean:s,String:n,Array:c,Dict:a,Nullable:i})=>({tags:[c(t),[]],name:[i(n),null],js_property_callbacks:[a(c(e)),{}],js_event_callbacks:[a(c(e)),{}],subscribed_events:[c(n),[]],syncable:[s,!0]})))},\n function _(e,t,s,a,r){var c,n;a();const _=e(12),o=e(53),i=e(55),l=e(59),u=e(61),g=e(62),h=e(57),p=e(63),m=e(67);class x{constructor(e,t){this.x_scale=e,this.y_scale=t,this.x_source=this.x_scale.source_range,this.y_source=this.y_scale.source_range,this.ranges=[this.x_source,this.y_source],this.scales=[this.x_scale,this.y_scale]}map_to_screen(e,t){return[this.x_scale.v_compute(e),this.y_scale.v_compute(t)]}map_from_screen(e,t){return[this.x_scale.v_invert(e),this.y_scale.v_invert(t)]}}s.CoordinateTransform=x,x.__name__=\"CoordinateTransform\";class y extends o.Model{constructor(e){super(e)}get x_ranges(){return new Map([[\"default\",this.x_source]])}get y_ranges(){return new Map([[\"default\",this.y_source]])}_get_scale(e,t,s){if(e instanceof m.FactorRange!=t instanceof g.CategoricalScale)throw new Error(`Range ${e.type} is incompatible is Scale ${t.type}`);t instanceof u.LogScale&&e instanceof p.DataRange1d&&(e.scale_hint=\"log\");const a=t.clone();return a.setv({source_range:e,target_range:s}),a}get_transform(e){const{x_source:t,x_scale:s,x_target:a}=this,r=this._get_scale(t,s,a),{y_source:c,y_scale:n,y_target:_}=this,o=this._get_scale(c,n,_),i=new v({source_scale:r,source_range:r.source_range,target_scale:e.x_scale,target_range:e.x_target}),l=new v({source_scale:o,source_range:o.source_range,target_scale:e.y_scale,target_range:e.y_target});return new x(i,l)}}s.CoordinateMapping=y,c=y,y.__name__=\"CoordinateMapping\",c.define((({Ref:e})=>({x_source:[e(h.Range),()=>new p.DataRange1d],y_source:[e(h.Range),()=>new p.DataRange1d],x_scale:[e(i.Scale),()=>new l.LinearScale],y_scale:[e(i.Scale),()=>new l.LinearScale],x_target:[e(h.Range)],y_target:[e(h.Range)]})));class v extends i.Scale{constructor(e){super(e)}get s_compute(){const e=this.source_scale.s_compute,t=this.target_scale.s_compute;return s=>t(e(s))}get s_invert(){const e=this.source_scale.s_invert,t=this.target_scale.s_invert;return s=>e(t(s))}compute(e){return this.s_compute(e)}v_compute(e){const{s_compute:t}=this;return(0,_.map)(e,t)}invert(e){return this.s_invert(e)}v_invert(e){const{s_invert:t}=this;return(0,_.map)(e,t)}}s.CompositeScale=v,n=v,v.__name__=\"CompositeScale\",n.internal((({Ref:e})=>({source_scale:[e(i.Scale)],target_scale:[e(i.Scale)]})))},\n function _(e,t,r,n,s){var _;n();const a=e(56),c=e(57),o=e(58),i=e(24);class u extends a.Transform{constructor(e){super(e)}compute(e){return this.s_compute(e)}v_compute(e){const t=new i.ScreenArray(e.length),{s_compute:r}=this;for(let n=0;n({source_range:[e(c.Range)],target_range:[e(o.Range1d)]})))},\n function _(n,s,o,r,c){r();const e=n(53);class t extends e.Model{constructor(n){super(n)}}o.Transform=t,t.__name__=\"Transform\"},\n function _(e,t,n,i,s){var r;i();const a=e(53);class l extends a.Model{constructor(e){super(e),this.have_updated_interactively=!1}get is_reversed(){return this.start>this.end}get is_valid(){return isFinite(this.min)&&isFinite(this.max)}get span(){return Math.abs(this.end-this.start)}}n.Range=l,r=l,l.__name__=\"Range\",r.define((({Number:e,Tuple:t,Or:n,Auto:i,Nullable:s})=>({bounds:[s(n(t(s(e),s(e)),i)),null],min_interval:[s(e),null],max_interval:[s(e),null]}))),r.internal((({Array:e,AnyRef:t})=>({plots:[e(t()),[]]})))},\n function _(t,e,s,n,r){var a;n();const i=t(57);class _ extends i.Range{constructor(t){super(t)}_set_auto_bounds(){if(\"auto\"==this.bounds){const t=Math.min(this._reset_start,this._reset_end),e=Math.max(this._reset_start,this._reset_end);this.setv({bounds:[t,e]},{silent:!0})}}initialize(){super.initialize(),this._set_auto_bounds()}get min(){return Math.min(this.start,this.end)}get max(){return Math.max(this.start,this.end)}reset(){this._set_auto_bounds();const{_reset_start:t,_reset_end:e}=this;this.start!=t||this.end!=e?this.setv({start:t,end:e}):this.change.emit()}map(t){return new _({start:t(this.start),end:t(this.end)})}widen(t){let{start:e,end:s}=this;return this.is_reversed?(e+=t,s-=t):(e-=t,s+=t),new _({start:e,end:s})}}s.Range1d=_,a=_,_.__name__=\"Range1d\",a.define((({Number:t,Nullable:e})=>({start:[t,0],end:[t,1],reset_start:[e(t),null,{on_update(t,e){e._reset_start=null!=t?t:e.start}}],reset_end:[e(t),null,{on_update(t,e){e._reset_end=null!=t?t:e.end}}]})))},\n function _(t,e,n,r,s){r();const a=t(60);class _ extends a.ContinuousScale{constructor(t){super(t)}get s_compute(){const[t,e]=this._linear_compute_state();return n=>t*n+e}get s_invert(){const[t,e]=this._linear_compute_state();return n=>(n-e)/t}_linear_compute_state(){const t=this.source_range.start,e=this.source_range.end,n=this.target_range.start,r=(this.target_range.end-n)/(e-t);return[r,-r*t+n]}}n.LinearScale=_,_.__name__=\"LinearScale\"},\n function _(n,c,o,s,e){s();const t=n(55);class u extends t.Scale{constructor(n){super(n)}}o.ContinuousScale=u,u.__name__=\"ContinuousScale\"},\n function _(t,e,a,o,s){o();const r=t(60);class n extends r.ContinuousScale{constructor(t){super(t)}get s_compute(){const[t,e,a,o]=this._compute_state();return s=>{if(0==a)return 0;{const r=(Math.log(s)-o)/a;return isFinite(r)?r*t+e:NaN}}}get s_invert(){const[t,e,a,o]=this._compute_state();return s=>{const r=(s-e)/t;return Math.exp(a*r+o)}}_get_safe_factor(t,e){let a=t<0?0:t,o=e<0?0:e;if(a==o)if(0==a)[a,o]=[1,10];else{const t=Math.log(a)/Math.log(10);a=10**Math.floor(t),o=Math.ceil(t)!=Math.floor(t)?10**Math.ceil(t):10**(Math.ceil(t)+1)}return[a,o]}_compute_state(){const t=this.source_range.start,e=this.source_range.end,a=this.target_range.start,o=this.target_range.end-a,[s,r]=this._get_safe_factor(t,e);let n,c;0==s?(n=Math.log(r),c=0):(n=Math.log(r)-Math.log(s),c=Math.log(s));return[o,a,n,c]}}a.LogScale=n,n.__name__=\"LogScale\"},\n function _(t,e,c,a,s){a();const n=t(55),r=t(59),{_linear_compute_state:o}=r.LinearScale.prototype;class l extends n.Scale{constructor(t){super(t)}get s_compute(){const[t,e]=o.call(this),c=this.source_range;return a=>t*c.synthetic(a)+e}get s_invert(){const[t,e]=o.call(this);return c=>(c-e)/t}}c.CategoricalScale=l,l.__name__=\"CategoricalScale\"},\n function _(t,i,n,e,a){e();const s=t(1);var l;const _=t(64),o=t(20),r=t(9),h=t(19),d=(0,s.__importStar)(t(65)),u=t(66);class g extends _.DataRange{constructor(t){super(t),this.have_updated_interactively=!1}initialize(){super.initialize(),this._initial_start=this.start,this._initial_end=this.end,this._initial_range_padding=this.range_padding,this._initial_range_padding_units=this.range_padding_units,this._initial_follow=this.follow,this._initial_follow_interval=this.follow_interval,this._initial_default_span=this.default_span,this._plot_bounds=new Map}get min(){return Math.min(this.start,this.end)}get max(){return Math.max(this.start,this.end)}computed_renderers(){const{renderers:t,names:i}=this,n=(0,r.concat)(this.plots.map((t=>t.data_renderers)));return(0,u.compute_renderers)(0==t.length?\"auto\":t,n,i)}_compute_plot_bounds(t,i){let n=d.empty();for(const e of t){const t=i.get(e);null==t||!e.visible&&this.only_visible||(n=d.union(n,t))}return n}adjust_bounds_for_aspect(t,i){const n=d.empty();let e=t.x1-t.x0;e<=0&&(e=1);let a=t.y1-t.y0;a<=0&&(a=1);const s=.5*(t.x1+t.x0),l=.5*(t.y1+t.y0);return el&&(\"start\"==this.follow?a=e+s*l:\"end\"==this.follow&&(e=a-s*l)),[e,a]}update(t,i,n,e){if(this.have_updated_interactively)return;const a=this.computed_renderers();let s=this._compute_plot_bounds(a,t);null!=e&&(s=this.adjust_bounds_for_aspect(s,e)),this._plot_bounds.set(n,s);const[l,_]=this._compute_min_max(this._plot_bounds.entries(),i);let[o,r]=this._compute_range(l,_);null!=this._initial_start&&(\"log\"==this.scale_hint?this._initial_start>0&&(o=this._initial_start):o=this._initial_start),null!=this._initial_end&&(\"log\"==this.scale_hint?this._initial_end>0&&(r=this._initial_end):r=this._initial_end);let h=!1;\"auto\"==this.bounds&&(this.setv({bounds:[o,r]},{silent:!0}),h=!0);const[d,u]=[this.start,this.end];if(o!=d||r!=u){const t={};o!=d&&(t.start=o),r!=u&&(t.end=r),this.setv(t),h=!1}h&&this.change.emit()}reset(){this.have_updated_interactively=!1,this.setv({range_padding:this._initial_range_padding,range_padding_units:this._initial_range_padding_units,follow:this._initial_follow,follow_interval:this._initial_follow_interval,default_span:this._initial_default_span},{silent:!0}),this.change.emit()}}n.DataRange1d=g,l=g,g.__name__=\"DataRange1d\",l.define((({Boolean:t,Number:i,Nullable:n})=>({start:[i],end:[i],range_padding:[i,.1],range_padding_units:[o.PaddingUnits,\"percent\"],flipped:[t,!1],follow:[n(o.StartEnd),null],follow_interval:[n(i),null],default_span:[i,2],only_visible:[t,!1]}))),l.internal((({Enum:t})=>({scale_hint:[t(\"log\",\"auto\"),\"auto\"]})))},\n function _(e,n,a,r,s){var t;r();const c=e(57);class _ extends c.Range{constructor(e){super(e)}}a.DataRange=_,t=_,_.__name__=\"DataRange\",t.define((({String:e,Array:n,AnyRef:a})=>({names:[n(e),[]],renderers:[n(a()),[]]})))},\n function _(t,i,e,h,r){h();const s=t(24),n=t(26),{min:x,max:y}=Math;e.empty=function(){return{x0:1/0,y0:1/0,x1:-1/0,y1:-1/0}},e.positive_x=function(){return{x0:Number.MIN_VALUE,y0:-1/0,x1:1/0,y1:1/0}},e.positive_y=function(){return{x0:-1/0,y0:Number.MIN_VALUE,x1:1/0,y1:1/0}},e.union=function(t,i){return{x0:x(t.x0,i.x0),x1:y(t.x1,i.x1),y0:x(t.y0,i.y0),y1:y(t.y1,i.y1)}};class o{constructor(t){if(null==t)this.x0=0,this.y0=0,this.x1=0,this.y1=0;else if(\"x0\"in t){const{x0:i,y0:e,x1:h,y1:r}=t;if(!(i<=h&&e<=r))throw new Error(`invalid bbox {x0: ${i}, y0: ${e}, x1: ${h}, y1: ${r}}`);this.x0=i,this.y0=e,this.x1=h,this.y1=r}else if(\"x\"in t){const{x:i,y:e,width:h,height:r}=t;if(!(h>=0&&r>=0))throw new Error(`invalid bbox {x: ${i}, y: ${e}, width: ${h}, height: ${r}}`);this.x0=i,this.y0=e,this.x1=i+h,this.y1=e+r}else{let i,e,h,r;if(\"width\"in t)if(\"left\"in t)i=t.left,e=i+t.width;else if(\"right\"in t)e=t.right,i=e-t.width;else{const h=t.width/2;i=t.hcenter-h,e=t.hcenter+h}else i=t.left,e=t.right;if(\"height\"in t)if(\"top\"in t)h=t.top,r=h+t.height;else if(\"bottom\"in t)r=t.bottom,h=r-t.height;else{const i=t.height/2;h=t.vcenter-i,r=t.vcenter+i}else h=t.top,r=t.bottom;if(!(i<=e&&h<=r))throw new Error(`invalid bbox {left: ${i}, top: ${h}, right: ${e}, bottom: ${r}}`);this.x0=i,this.y0=h,this.x1=e,this.y1=r}}static from_rect({left:t,right:i,top:e,bottom:h}){return new o({x0:Math.min(t,i),y0:Math.min(e,h),x1:Math.max(t,i),y1:Math.max(e,h)})}equals(t){return this.x0==t.x0&&this.y0==t.y0&&this.x1==t.x1&&this.y1==t.y1}[n.equals](t,i){return i.eq(this.x0,t.x0)&&i.eq(this.y0,t.y0)&&i.eq(this.x1,t.x1)&&i.eq(this.y1,t.y1)}toString(){return`BBox({left: ${this.left}, top: ${this.top}, width: ${this.width}, height: ${this.height}})`}get left(){return this.x0}get top(){return this.y0}get right(){return this.x1}get bottom(){return this.y1}get p0(){return[this.x0,this.y0]}get p1(){return[this.x1,this.y1]}get x(){return this.x0}get y(){return this.y0}get width(){return this.x1-this.x0}get height(){return this.y1-this.y0}get size(){return{width:this.width,height:this.height}}get rect(){const{x0:t,y0:i,x1:e,y1:h}=this;return{p0:{x:t,y:i},p1:{x:e,y:i},p2:{x:e,y:h},p3:{x:t,y:h}}}get box(){const{x:t,y:i,width:e,height:h}=this;return{x:t,y:i,width:e,height:h}}get h_range(){return{start:this.x0,end:this.x1}}get v_range(){return{start:this.y0,end:this.y1}}get ranges(){return[this.h_range,this.v_range]}get aspect(){return this.width/this.height}get hcenter(){return(this.left+this.right)/2}get vcenter(){return(this.top+this.bottom)/2}get area(){return this.width*this.height}relative(){const{width:t,height:i}=this;return new o({x:0,y:0,width:t,height:i})}translate(t,i){const{x:e,y:h,width:r,height:s}=this;return new o({x:t+e,y:i+h,width:r,height:s})}relativize(t,i){return[t-this.x,i-this.y]}contains(t,i){return this.x0<=t&&t<=this.x1&&this.y0<=i&&i<=this.y1}clip(t,i){return tthis.x1&&(t=this.x1),ithis.y1&&(i=this.y1),[t,i]}grow_by(t){return new o({left:this.left-t,right:this.right+t,top:this.top-t,bottom:this.bottom+t})}shrink_by(t){return new o({left:this.left+t,right:this.right-t,top:this.top+t,bottom:this.bottom-t})}union(t){return new o({x0:x(this.x0,t.x0),y0:x(this.y0,t.y0),x1:y(this.x1,t.x1),y1:y(this.y1,t.y1)})}intersection(t){return this.intersects(t)?new o({x0:y(this.x0,t.x0),y0:y(this.y0,t.y0),x1:x(this.x1,t.x1),y1:x(this.y1,t.y1)}):null}intersects(t){return!(t.x1this.x1||t.y1this.y1)}get xview(){return{compute:t=>this.left+t,v_compute:t=>{const i=new s.ScreenArray(t.length),e=this.left;for(let h=0;hthis.bottom-t,v_compute:t=>{const i=new s.ScreenArray(t.length),e=this.bottom;for(let h=0;h0&&(r=r.filter((n=>(0,l.includes)(t,n.name)))),r}},\n function _(t,n,e,i,s){var r;i();const a=t(57),o=t(20),g=t(21),p=t(24),c=t(9),l=t(8),u=t(11);function h(t,n,e=0){const i=new Map;for(let s=0;sa.get(t).value)));r.set(t,{value:l/s,mapping:a}),o+=s+n+p}return[r,(a.size-1)*n+g]}function _(t,n,e,i,s=0){var r;const a=new Map,o=new Map;for(const[n,e,i]of t){const t=null!==(r=o.get(n))&&void 0!==r?r:[];o.set(n,[...t,[e,i]])}let g=s,p=0;for(const[t,s]of o){const r=s.length,[o,l]=d(s,e,i,g);p+=l;const u=(0,c.sum)(s.map((([t])=>o.get(t).value)));a.set(t,{value:u/r,mapping:o}),g+=r+n+l}return[a,(o.size-1)*n+p]}e.Factor=(0,g.Or)(g.String,(0,g.Tuple)(g.String,g.String),(0,g.Tuple)(g.String,g.String,g.String)),e.FactorSeq=(0,g.Or)((0,g.Array)(g.String),(0,g.Array)((0,g.Tuple)(g.String,g.String)),(0,g.Array)((0,g.Tuple)(g.String,g.String,g.String))),e.map_one_level=h,e.map_two_levels=d,e.map_three_levels=_;class f extends a.Range{constructor(t){super(t)}get min(){return this.start}get max(){return this.end}initialize(){super.initialize(),this._init(!0)}connect_signals(){super.connect_signals(),this.connect(this.properties.factors.change,(()=>this.reset())),this.connect(this.properties.factor_padding.change,(()=>this.reset())),this.connect(this.properties.group_padding.change,(()=>this.reset())),this.connect(this.properties.subgroup_padding.change,(()=>this.reset())),this.connect(this.properties.range_padding.change,(()=>this.reset())),this.connect(this.properties.range_padding_units.change,(()=>this.reset()))}reset(){this._init(!1),this.change.emit()}_lookup(t){switch(t.length){case 1:{const[n]=t,e=this._mapping.get(n);return null!=e?e.value:NaN}case 2:{const[n,e]=t,i=this._mapping.get(n);if(null!=i){const t=i.mapping.get(e);if(null!=t)return t.value}return NaN}case 3:{const[n,e,i]=t,s=this._mapping.get(n);if(null!=s){const t=s.mapping.get(e);if(null!=t){const n=t.mapping.get(i);if(null!=n)return n.value}}return NaN}default:(0,u.unreachable)()}}synthetic(t){if((0,l.isNumber)(t))return t;if((0,l.isString)(t))return this._lookup([t]);let n=0;const e=t[t.length-1];return(0,l.isNumber)(e)&&(n=e,t=t.slice(0,-1)),this._lookup(t)+n}v_synthetic(t){const n=t.length,e=new p.ScreenArray(n);for(let i=0;i{if((0,c.every)(this.factors,l.isString)){const t=this.factors,[n,e]=h(t,this.factor_padding);return{levels:1,mapping:n,tops:null,mids:null,inside_padding:e}}if((0,c.every)(this.factors,(t=>(0,l.isArray)(t)&&2==t.length&&(0,l.isString)(t[0])&&(0,l.isString)(t[1])))){const t=this.factors,[n,e]=d(t,this.group_padding,this.factor_padding),i=[...n.keys()];return{levels:2,mapping:n,tops:i,mids:null,inside_padding:e}}if((0,c.every)(this.factors,(t=>(0,l.isArray)(t)&&3==t.length&&(0,l.isString)(t[0])&&(0,l.isString)(t[1])&&(0,l.isString)(t[2])))){const t=this.factors,[n,e]=_(t,this.group_padding,this.subgroup_padding,this.factor_padding),i=[...n.keys()],s=[];for(const[t,e]of n)for(const n of e.mapping.keys())s.push([t,n]);return{levels:3,mapping:n,tops:i,mids:s,inside_padding:e}}(0,u.unreachable)()})();this._mapping=e,this.tops=i,this.mids=s;let a=0,o=this.factors.length+r;if(\"percent\"==this.range_padding_units){const t=(o-a)*this.range_padding/2;a-=t,o+=t}else a-=this.range_padding,o+=this.range_padding;this.setv({start:a,end:o,levels:n},{silent:t}),\"auto\"==this.bounds&&this.setv({bounds:[a,o]},{silent:!0})}}e.FactorRange=f,r=f,f.__name__=\"FactorRange\",r.define((({Number:t})=>({factors:[e.FactorSeq,[]],factor_padding:[t,0],subgroup_padding:[t,.8],group_padding:[t,1.4],range_padding:[t,0],range_padding_units:[o.PaddingUnits,\"percent\"],start:[t],end:[t]}))),r.internal((({Number:t,String:n,Array:e,Tuple:i,Nullable:s})=>({levels:[t],mids:[s(e(i(n,n))),null],tops:[s(e(n)),null]})))},\n function _(t,e,s,a,i){a();const n=t(1);var _;const r=t(69),o=t(112),l=t(48),d=t(20),h=t(24),c=t(113),u=(0,n.__importStar)(t(18)),v=t(10);class p extends r.DataAnnotationView{async lazy_initialize(){await super.lazy_initialize();const{start:t,end:e}=this.model;null!=t&&(this.start=await(0,c.build_view)(t,{parent:this})),null!=e&&(this.end=await(0,c.build_view)(e,{parent:this}))}set_data(t){var e,s;super.set_data(t),null===(e=this.start)||void 0===e||e.set_data(t),null===(s=this.end)||void 0===s||s.set_data(t)}remove(){var t,e;null===(t=this.start)||void 0===t||t.remove(),null===(e=this.end)||void 0===e||e.remove(),super.remove()}map_data(){const{frame:t}=this.plot_view;\"data\"==this.model.start_units?(this._sx_start=this.coordinates.x_scale.v_compute(this._x_start),this._sy_start=this.coordinates.y_scale.v_compute(this._y_start)):(this._sx_start=t.bbox.xview.v_compute(this._x_start),this._sy_start=t.bbox.yview.v_compute(this._y_start)),\"data\"==this.model.end_units?(this._sx_end=this.coordinates.x_scale.v_compute(this._x_end),this._sy_end=this.coordinates.y_scale.v_compute(this._y_end)):(this._sx_end=t.bbox.xview.v_compute(this._x_end),this._sy_end=t.bbox.yview.v_compute(this._y_end));const{_sx_start:e,_sy_start:s,_sx_end:a,_sy_end:i}=this,n=e.length,_=this._angles=new h.ScreenArray(n);for(let t=0;t({x_start:[u.XCoordinateSpec,{field:\"x_start\"}],y_start:[u.YCoordinateSpec,{field:\"y_start\"}],start_units:[d.SpatialUnits,\"data\"],start:[e(t(o.ArrowHead)),null],x_end:[u.XCoordinateSpec,{field:\"x_end\"}],y_end:[u.YCoordinateSpec,{field:\"y_end\"}],end_units:[d.SpatialUnits,\"data\"],end:[e(t(o.ArrowHead)),()=>new o.OpenHead]})))},\n function _(t,e,n,s,a){s();const o=t(1);var i;const c=t(40),r=t(70),_=t(75),l=t(78),h=(0,o.__importStar)(t(18));class d extends c.AnnotationView{constructor(){super(...arguments),this._initial_set_data=!1}connect_signals(){super.connect_signals();const t=()=>{this.set_data(this.model.source),this._rerender()};this.connect(this.model.change,t),this.connect(this.model.source.streaming,t),this.connect(this.model.source.patching,t),this.connect(this.model.source.change,t)}_rerender(){this.request_render()}set_data(t){const e=this;for(const n of this.model)if(n instanceof h.VectorSpec||n instanceof h.ScalarSpec)if(n instanceof h.BaseCoordinateSpec){const s=n.array(t);e[`_${n.attr}`]=s}else{const s=n.uniform(t);e[`${n.attr}`]=s}this.plot_model.use_map&&(null!=e._x&&l.inplace.project_xy(e._x,e._y),null!=e._xs&&l.inplace.project_xsys(e._xs,e._ys));for(const t of this.visuals)t.update()}_render(){this._initial_set_data||(this.set_data(this.model.source),this._initial_set_data=!0),this.map_data(),this.paint(this.layer.ctx)}}n.DataAnnotationView=d,d.__name__=\"DataAnnotationView\";class u extends c.Annotation{constructor(t){super(t)}}n.DataAnnotation=u,i=u,u.__name__=\"DataAnnotation\",i.define((({Ref:t})=>({source:[t(r.ColumnarDataSource),()=>new _.ColumnDataSource]})))},\n function _(t,e,n,s,a){var i;s();const r=t(71),l=t(15),c=t(19),o=t(73),h=t(8),u=t(9),g=t(13),d=t(72),_=t(74),m=t(29);class w extends r.DataSource{constructor(t){super(t),this.selection_manager=new o.SelectionManager(this)}get_array(t){let e=this.data[t];return null==e?this.data[t]=e=[]:(0,h.isArray)(e)||(this.data[t]=e=Array.from(e)),e}initialize(){super.initialize(),this._select=new l.Signal0(this,\"select\"),this.inspect=new l.Signal(this,\"inspect\"),this.streaming=new l.Signal0(this,\"streaming\"),this.patching=new l.Signal(this,\"patching\")}get_column(t){const e=this.data[t];return null!=e?e:null}columns(){return(0,g.keys)(this.data)}get_length(t=!0){const e=(0,u.uniq)((0,g.values)(this.data).map((t=>(0,m.is_NDArray)(t)?t.shape[0]:t.length)));switch(e.length){case 0:return null;case 1:return e[0];default:{const n=\"data source has columns of inconsistent lengths\";if(t)return c.logger.warn(n),e.sort()[0];throw new Error(n)}}}get length(){var t;return null!==(t=this.get_length())&&void 0!==t?t:0}clear(){const t={};for(const e of this.columns())t[e]=new this.data[e].constructor(0);this.data=t}}n.ColumnarDataSource=w,i=w,w.__name__=\"ColumnarDataSource\",i.define((({Ref:t})=>({selection_policy:[t(_.SelectionPolicy),()=>new _.UnionRenderers]}))),i.internal((({AnyRef:t})=>({inspected:[t(),()=>new d.Selection]})))},\n function _(e,c,n,t,o){var a;t();const s=e(53),r=e(72);class l extends s.Model{constructor(e){super(e)}}n.DataSource=l,a=l,l.__name__=\"DataSource\",a.define((({Ref:e})=>({selected:[e(r.Selection),()=>new r.Selection]})))},\n function _(i,e,s,t,n){var l;t();const c=i(53),d=i(9),h=i(13);class _ extends c.Model{constructor(i){super(i)}get_view(){return this.view}get selected_glyph(){return this.selected_glyphs.length>0?this.selected_glyphs[0]:null}add_to_selected_glyphs(i){this.selected_glyphs.push(i)}update(i,e=!0,s=\"replace\"){switch(s){case\"replace\":this.indices=i.indices,this.line_indices=i.line_indices,this.multiline_indices=i.multiline_indices,this.image_indices=i.image_indices,this.view=i.view,this.selected_glyphs=i.selected_glyphs;break;case\"append\":this.update_through_union(i);break;case\"intersect\":this.update_through_intersection(i);break;case\"subtract\":this.update_through_subtraction(i)}}clear(){this.indices=[],this.line_indices=[],this.multiline_indices={},this.image_indices=[],this.view=null,this.selected_glyphs=[]}map(i){return new _(Object.assign(Object.assign({},this.attributes),{indices:this.indices.map(i),multiline_indices:(0,h.to_object)((0,h.entries)(this.multiline_indices).map((([e,s])=>[i(Number(e)),s]))),image_indices:this.image_indices.map((e=>Object.assign(Object.assign({},e),{index:i(e.index)})))}))}is_empty(){return 0==this.indices.length&&0==this.line_indices.length&&0==this.image_indices.length}update_through_union(i){this.indices=(0,d.union)(this.indices,i.indices),this.selected_glyphs=(0,d.union)(i.selected_glyphs,this.selected_glyphs),this.line_indices=(0,d.union)(i.line_indices,this.line_indices),this.view=i.view,this.multiline_indices=(0,h.merge)(i.multiline_indices,this.multiline_indices)}update_through_intersection(i){this.indices=(0,d.intersection)(this.indices,i.indices),this.selected_glyphs=(0,d.union)(i.selected_glyphs,this.selected_glyphs),this.line_indices=(0,d.union)(i.line_indices,this.line_indices),this.view=i.view,this.multiline_indices=(0,h.merge)(i.multiline_indices,this.multiline_indices)}update_through_subtraction(i){this.indices=(0,d.difference)(this.indices,i.indices),this.selected_glyphs=(0,d.union)(i.selected_glyphs,this.selected_glyphs),this.line_indices=(0,d.union)(i.line_indices,this.line_indices),this.view=i.view,this.multiline_indices=(0,h.merge)(i.multiline_indices,this.multiline_indices)}}s.Selection=_,l=_,_.__name__=\"Selection\",l.define((({Int:i,Array:e,Dict:s})=>({indices:[e(i),[]],line_indices:[e(i),[]],multiline_indices:[s(e(i)),{}]}))),l.internal((({Int:i,Array:e,AnyRef:s,Struct:t,Nullable:n})=>({selected_glyphs:[e(s()),[]],view:[n(s()),null],image_indices:[e(t({index:i,dim1:i,dim2:i,flat_index:i})),[]]})))},\n function _(e,t,o,s,c){s();const n=e(72);function i(e){return\"GlyphRenderer\"==e.model.type}function l(e){return\"GraphRenderer\"==e.model.type}class r{constructor(e){this.source=e,this.inspectors=new Map}select(e,t,o,s=\"replace\"){const c=[],n=[];for(const t of e)i(t)?c.push(t):l(t)&&n.push(t);let r=!1;for(const e of n){const c=e.model.selection_policy.hit_test(t,e);r=r||e.model.selection_policy.do_selection(c,e.model,o,s)}if(c.length>0){const e=this.source.selection_policy.hit_test(t,c);r=r||this.source.selection_policy.do_selection(e,this.source,o,s)}return r}inspect(e,t){let o=!1;if(i(e)){const s=e.hit_test(t);if(null!=s){o=!s.is_empty();const c=this.get_or_create_inspector(e.model);c.update(s,!0,\"replace\"),this.source.setv({inspected:c},{silent:!0}),this.source.inspect.emit([e.model,{geometry:t}])}}else if(l(e)){const s=e.model.inspection_policy.hit_test(t,e);o=o||e.model.inspection_policy.do_inspection(s,t,e,!1,\"replace\")}return o}clear(e){this.source.selected.clear(),null!=e&&this.get_or_create_inspector(e.model).clear()}get_or_create_inspector(e){let t=this.inspectors.get(e);return null==t&&(t=new n.Selection,this.inspectors.set(e,t)),t}}o.SelectionManager=r,r.__name__=\"SelectionManager\"},\n function _(e,t,n,s,o){s();const r=e(53);class c extends r.Model{do_selection(e,t,n,s){return null!=e&&(t.selected.update(e,n,s),t._select.emit(),!t.selected.is_empty())}}n.SelectionPolicy=c,c.__name__=\"SelectionPolicy\";class l extends c{hit_test(e,t){const n=[];for(const s of t){const t=s.hit_test(e);null!=t&&n.push(t)}if(n.length>0){const e=n[0];for(const t of n)e.update_through_intersection(t);return e}return null}}n.IntersectRenderers=l,l.__name__=\"IntersectRenderers\";class _ extends c{hit_test(e,t){const n=[];for(const s of t){const t=s.hit_test(e);null!=t&&n.push(t)}if(n.length>0){const e=n[0];for(const t of n)e.update_through_union(t);return e}return null}}n.UnionRenderers=_,_.__name__=\"UnionRenderers\"},\n function _(t,n,e,s,o){s();const r=t(1);var l;const c=t(70),i=t(8),a=t(13),u=(0,r.__importStar)(t(76)),h=t(77),d=t(35);function f(t,n,e){if((0,i.isArray)(t)){const s=t.concat(n);return null!=e&&s.length>e?s.slice(-e):s}if((0,i.isTypedArray)(t)){const s=t.length+n.length;if(null!=e&&s>e){const o=s-e,r=t.length;let l;t.length({data:[t(n),{}]})))},\n function _(t,n,o,e,c){e(),o.concat=function(t,...n){let o=t.length;for(const t of n)o+=t.length;const e=new t.constructor(o);e.set(t,0);let c=t.length;for(const t of n)e.set(t,c),c+=t.length;return e}},\n function _(n,o,t,e,f){function c(...n){const o=new Set;for(const t of n)for(const n of t)o.add(n);return o}e(),t.union=c,t.intersection=function(n,...o){const t=new Set;n:for(const e of n){for(const n of o)if(!n.has(e))continue n;t.add(e)}return t},t.difference=function(n,...o){const t=new Set(n);for(const n of c(...o))t.delete(n);return t}},\n function _(n,t,e,o,r){o();const c=n(1),l=(0,c.__importDefault)(n(79)),i=(0,c.__importDefault)(n(80)),u=n(24),a=new i.default(\"GOOGLE\"),s=new i.default(\"WGS84\"),f=(0,l.default)(s,a);e.wgs84_mercator={compute:(n,t)=>isFinite(n)&&isFinite(t)?f.forward([n,t]):[NaN,NaN],invert:(n,t)=>isFinite(n)&&isFinite(t)?f.inverse([n,t]):[NaN,NaN]};const _={lon:[-20026376.39,20026376.39],lat:[-20048966.1,20048966.1]},p={lon:[-180,180],lat:[-85.06,85.06]},{min:g,max:h}=Math;function m(n,t){const o=g(n.length,t.length),r=(0,u.infer_type)(n,t),c=new r(o),l=new r(o);return e.inplace.project_xy(n,t,c,l),[c,l]}e.clip_mercator=function(n,t,e){const[o,r]=_[e];return[h(n,o),g(t,r)]},e.in_bounds=function(n,t){const[e,o]=p[t];return e2?void 0!==e.name&&\"geocent\"===e.name||void 0!==n.name&&\"geocent\"===n.name?\"number\"==typeof o.z?[o.x,o.y,o.z].concat(t.splice(3)):[o.x,o.y,t[2]].concat(t.splice(3)):[o.x,o.y].concat(t.splice(2)):[o.x,o.y]):(a=(0,c.default)(e,n,t,r),2===(i=Object.keys(t)).length||i.forEach((function(r){if(void 0!==e.name&&\"geocent\"===e.name||void 0!==n.name&&\"geocent\"===n.name){if(\"x\"===r||\"y\"===r||\"z\"===r)return}else if(\"x\"===r||\"y\"===r)return;a[r]=t[r]})),a)}function l(e){return e instanceof i.default?e:e.oProj?e.oProj:(0,i.default)(e)}t.default=function(e,n,t){e=l(e);var r,o=!1;return void 0===n?(n=e,e=u,o=!0):(void 0!==n.x||Array.isArray(n))&&(t=n,n=e,e=u,o=!0),n=l(n),t?f(e,n,t):(r={forward:function(t,r){return f(e,n,t,r)},inverse:function(t,r){return f(n,e,t,r)}},o&&(r.oProj=n),r)}},\n function _(t,e,a,s,i){s();const l=t(1),u=(0,l.__importDefault)(t(81)),r=(0,l.__importDefault)(t(92)),d=(0,l.__importDefault)(t(93)),o=t(101),f=(0,l.__importDefault)(t(103)),p=(0,l.__importDefault)(t(104)),m=(0,l.__importDefault)(t(88)),n=t(105);function h(t,e){if(!(this instanceof h))return new h(t);e=e||function(t){if(t)throw t};var a=(0,u.default)(t);if(\"object\"==typeof a){var s=h.projections.get(a.projName);if(s){if(a.datumCode&&\"none\"!==a.datumCode){var i=(0,m.default)(f.default,a.datumCode);i&&(a.datum_params=a.datum_params||(i.towgs84?i.towgs84.split(\",\"):null),a.ellps=i.ellipse,a.datumName=i.datumName?i.datumName:a.datumCode)}a.k0=a.k0||1,a.axis=a.axis||\"enu\",a.ellps=a.ellps||\"wgs84\",a.lat1=a.lat1||a.lat0;var l=(0,o.sphere)(a.a,a.b,a.rf,a.ellps,a.sphere),d=(0,o.eccentricity)(l.a,l.b,l.rf,a.R_A),_=(0,n.getNadgrids)(a.nadgrids),c=a.datum||(0,p.default)(a.datumCode,a.datum_params,l.a,l.b,d.es,d.ep2,_);(0,r.default)(this,a),(0,r.default)(this,s),this.a=l.a,this.b=l.b,this.rf=l.rf,this.sphere=l.sphere,this.es=d.es,this.e=d.e,this.ep2=d.ep2,this.datum=c,this.init(),e(null,this)}else e(t)}else e(t)}h.projections=d.default,h.projections.start(),a.default=h},\n function _(t,r,n,u,e){u();const f=t(1),i=(0,f.__importDefault)(t(82)),a=(0,f.__importDefault)(t(89)),o=(0,f.__importDefault)(t(84)),l=(0,f.__importDefault)(t(88));var C=[\"PROJECTEDCRS\",\"PROJCRS\",\"GEOGCS\",\"GEOCCS\",\"PROJCS\",\"LOCAL_CS\",\"GEODCRS\",\"GEODETICCRS\",\"GEODETICDATUM\",\"ENGCRS\",\"ENGINEERINGCRS\"];var d=[\"3857\",\"900913\",\"3785\",\"102113\"];n.default=function(t){if(!function(t){return\"string\"==typeof t}(t))return t;if(function(t){return t in i.default}(t))return i.default[t];if(function(t){return C.some((function(r){return t.indexOf(r)>-1}))}(t)){var r=(0,a.default)(t);if(function(t){var r=(0,l.default)(t,\"authority\");if(r){var n=(0,l.default)(r,\"epsg\");return n&&d.indexOf(n)>-1}}(r))return i.default[\"EPSG:3857\"];var n=function(t){var r=(0,l.default)(t,\"extension\");if(r)return(0,l.default)(r,\"proj4\")}(r);return n?(0,o.default)(n):r}return function(t){return\"+\"===t[0]}(t)?(0,o.default)(t):void 0}},\n function _(t,r,i,e,n){e();const f=t(1),a=(0,f.__importDefault)(t(83)),l=(0,f.__importDefault)(t(84)),u=(0,f.__importDefault)(t(89));function o(t){var r=this;if(2===arguments.length){var i=arguments[1];\"string\"==typeof i?\"+\"===i.charAt(0)?o[t]=(0,l.default)(arguments[1]):o[t]=(0,u.default)(arguments[1]):o[t]=i}else if(1===arguments.length){if(Array.isArray(t))return t.map((function(t){Array.isArray(t)?o.apply(r,t):o(t)}));if(\"string\"==typeof t){if(t in o)return o[t]}else\"EPSG\"in t?o[\"EPSG:\"+t.EPSG]=t:\"ESRI\"in t?o[\"ESRI:\"+t.ESRI]=t:\"IAU2000\"in t?o[\"IAU2000:\"+t.IAU2000]=t:console.log(t);return}}(0,a.default)(o),i.default=o},\n function _(t,l,G,S,e){S(),G.default=function(t){t(\"EPSG:4326\",\"+title=WGS 84 (long/lat) +proj=longlat +ellps=WGS84 +datum=WGS84 +units=degrees\"),t(\"EPSG:4269\",\"+title=NAD83 (long/lat) +proj=longlat +a=6378137.0 +b=6356752.31414036 +ellps=GRS80 +datum=NAD83 +units=degrees\"),t(\"EPSG:3857\",\"+title=WGS 84 / Pseudo-Mercator +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs\"),t.WGS84=t[\"EPSG:4326\"],t[\"EPSG:3785\"]=t[\"EPSG:3857\"],t.GOOGLE=t[\"EPSG:3857\"],t[\"EPSG:900913\"]=t[\"EPSG:3857\"],t[\"EPSG:102113\"]=t[\"EPSG:3857\"]}},\n function _(t,n,o,a,u){a();const e=t(1),r=t(85),i=(0,e.__importDefault)(t(86)),f=(0,e.__importDefault)(t(87)),l=(0,e.__importDefault)(t(88));o.default=function(t){var n,o,a,u={},e=t.split(\"+\").map((function(t){return t.trim()})).filter((function(t){return t})).reduce((function(t,n){var o=n.split(\"=\");return o.push(!0),t[o[0].toLowerCase()]=o[1],t}),{}),c={proj:\"projName\",datum:\"datumCode\",rf:function(t){u.rf=parseFloat(t)},lat_0:function(t){u.lat0=t*r.D2R},lat_1:function(t){u.lat1=t*r.D2R},lat_2:function(t){u.lat2=t*r.D2R},lat_ts:function(t){u.lat_ts=t*r.D2R},lon_0:function(t){u.long0=t*r.D2R},lon_1:function(t){u.long1=t*r.D2R},lon_2:function(t){u.long2=t*r.D2R},alpha:function(t){u.alpha=parseFloat(t)*r.D2R},gamma:function(t){u.rectified_grid_angle=parseFloat(t)},lonc:function(t){u.longc=t*r.D2R},x_0:function(t){u.x0=parseFloat(t)},y_0:function(t){u.y0=parseFloat(t)},k_0:function(t){u.k0=parseFloat(t)},k:function(t){u.k0=parseFloat(t)},a:function(t){u.a=parseFloat(t)},b:function(t){u.b=parseFloat(t)},r_a:function(){u.R_A=!0},zone:function(t){u.zone=parseInt(t,10)},south:function(){u.utmSouth=!0},towgs84:function(t){u.datum_params=t.split(\",\").map((function(t){return parseFloat(t)}))},to_meter:function(t){u.to_meter=parseFloat(t)},units:function(t){u.units=t;var n=(0,l.default)(f.default,t);n&&(u.to_meter=n.to_meter)},from_greenwich:function(t){u.from_greenwich=t*r.D2R},pm:function(t){var n=(0,l.default)(i.default,t);u.from_greenwich=(n||parseFloat(t))*r.D2R},nadgrids:function(t){\"@null\"===t?u.datumCode=\"none\":u.nadgrids=t},axis:function(t){var n=\"ewnsud\";3===t.length&&-1!==n.indexOf(t.substr(0,1))&&-1!==n.indexOf(t.substr(1,1))&&-1!==n.indexOf(t.substr(2,1))&&(u.axis=t)},approx:function(){u.approx=!0}};for(n in e)o=e[n],n in c?\"function\"==typeof(a=c[n])?a(o):u[a]=o:u[n]=o;return\"string\"==typeof u.datumCode&&\"WGS84\"!==u.datumCode&&(u.datumCode=u.datumCode.toLowerCase()),u}},\n function _(S,_,P,R,I){R(),P.PJD_3PARAM=1,P.PJD_7PARAM=2,P.PJD_GRIDSHIFT=3,P.PJD_WGS84=4,P.PJD_NODATUM=5,P.SRS_WGS84_SEMIMAJOR=6378137,P.SRS_WGS84_SEMIMINOR=6356752.314,P.SRS_WGS84_ESQUARED=.0066943799901413165,P.SEC_TO_RAD=484813681109536e-20,P.HALF_PI=Math.PI/2,P.SIXTH=.16666666666666666,P.RA4=.04722222222222222,P.RA6=.022156084656084655,P.EPSLN=1e-10,P.D2R=.017453292519943295,P.R2D=57.29577951308232,P.FORTPI=Math.PI/4,P.TWO_PI=2*Math.PI,P.SPI=3.14159265359},\n function _(o,r,a,e,s){e();var n={};a.default=n,n.greenwich=0,n.lisbon=-9.131906111111,n.paris=2.337229166667,n.bogota=-74.080916666667,n.madrid=-3.687938888889,n.rome=12.452333333333,n.bern=7.439583333333,n.jakarta=106.807719444444,n.ferro=-17.666666666667,n.brussels=4.367975,n.stockholm=18.058277777778,n.athens=23.7163375,n.oslo=10.722916666667},\n function _(t,e,f,o,u){o(),f.default={ft:{to_meter:.3048},\"us-ft\":{to_meter:1200/3937}}},\n function _(e,r,t,a,n){a();var o=/[\\s_\\-\\/\\(\\)]/g;t.default=function(e,r){if(e[r])return e[r];for(var t,a=Object.keys(e),n=r.toLowerCase().replace(o,\"\"),f=-1;++f0?90:-90),e.lat_ts=e.lat1)}(n),n}},\n function _(t,e,r,i,s){i(),r.default=function(t){return new d(t).output()};var h=/\\s/,o=/[A-Za-z]/,n=/[A-Za-z84]/,a=/[,\\]]/,u=/[\\d\\.E\\-\\+]/;function d(t){if(\"string\"!=typeof t)throw new Error(\"not a string\");this.text=t.trim(),this.level=0,this.place=0,this.root=null,this.stack=[],this.currentObject=null,this.state=1}d.prototype.readCharicter=function(){var t=this.text[this.place++];if(4!==this.state)for(;h.test(t);){if(this.place>=this.text.length)return;t=this.text[this.place++]}switch(this.state){case 1:return this.neutral(t);case 2:return this.keyword(t);case 4:return this.quoted(t);case 5:return this.afterquote(t);case 3:return this.number(t);case-1:return}},d.prototype.afterquote=function(t){if('\"'===t)return this.word+='\"',void(this.state=4);if(a.test(t))return this.word=this.word.trim(),void this.afterItem(t);throw new Error(\"havn't handled \\\"\"+t+'\" in afterquote yet, index '+this.place)},d.prototype.afterItem=function(t){return\",\"===t?(null!==this.word&&this.currentObject.push(this.word),this.word=null,void(this.state=1)):\"]\"===t?(this.level--,null!==this.word&&(this.currentObject.push(this.word),this.word=null),this.state=1,this.currentObject=this.stack.pop(),void(this.currentObject||(this.state=-1))):void 0},d.prototype.number=function(t){if(!u.test(t)){if(a.test(t))return this.word=parseFloat(this.word),void this.afterItem(t);throw new Error(\"havn't handled \\\"\"+t+'\" in number yet, index '+this.place)}this.word+=t},d.prototype.quoted=function(t){'\"'!==t?this.word+=t:this.state=5},d.prototype.keyword=function(t){if(n.test(t))this.word+=t;else{if(\"[\"===t){var e=[];return e.push(this.word),this.level++,null===this.root?this.root=e:this.currentObject.push(e),this.stack.push(this.currentObject),this.currentObject=e,void(this.state=1)}if(!a.test(t))throw new Error(\"havn't handled \\\"\"+t+'\" in keyword yet, index '+this.place);this.afterItem(t)}},d.prototype.neutral=function(t){if(o.test(t))return this.word=t,void(this.state=2);if('\"'===t)return this.word=\"\",void(this.state=4);if(u.test(t))return this.word=t,void(this.state=3);if(!a.test(t))throw new Error(\"havn't handled \\\"\"+t+'\" in neutral yet, index '+this.place);this.afterItem(t)},d.prototype.output=function(){for(;this.place90&&a*o.R2D<-90&&h*o.R2D>180&&h*o.R2D<-180)return null;if(Math.abs(Math.abs(a)-o.HALF_PI)<=o.EPSLN)return null;if(this.sphere)i=this.x0+this.a*this.k0*(0,n.default)(h-this.long0),s=this.y0+this.a*this.k0*Math.log(Math.tan(o.FORTPI+.5*a));else{var e=Math.sin(a),r=(0,l.default)(this.e,a,e);i=this.x0+this.a*this.k0*(0,n.default)(h-this.long0),s=this.y0-this.a*this.k0*Math.log(r)}return t.x=i,t.y=s,t}function M(t){var i,s,h=t.x-this.x0,a=t.y-this.y0;if(this.sphere)s=o.HALF_PI-2*Math.atan(Math.exp(-a/(this.a*this.k0)));else{var e=Math.exp(-a/(this.a*this.k0));if(-9999===(s=(0,u.default)(this.e,e)))return null}return i=(0,n.default)(this.long0+h/(this.a*this.k0)),t.x=i,t.y=s,t}s.init=f,s.forward=_,s.inverse=M,s.names=[\"Mercator\",\"Popular Visualisation Pseudo Mercator\",\"Mercator_1SP\",\"Mercator_Auxiliary_Sphere\",\"merc\"],s.default={init:f,forward:_,inverse:M,names:s.names}},\n function _(t,n,r,u,a){u(),r.default=function(t,n,r){var u=t*n;return r/Math.sqrt(1-u*u)}},\n function _(t,n,u,a,f){a();const e=t(1),o=t(85),_=(0,e.__importDefault)(t(97));u.default=function(t){return Math.abs(t)<=o.SPI?t:t-(0,_.default)(t)*o.TWO_PI}},\n function _(n,t,u,f,c){f(),u.default=function(n){return n<0?-1:1}},\n function _(t,n,a,o,u){o();const c=t(85);a.default=function(t,n,a){var o=t*a,u=.5*t;return o=Math.pow((1-o)/(1+o),u),Math.tan(.5*(c.HALF_PI-n))/o}},\n function _(t,a,n,r,f){r();const h=t(85);n.default=function(t,a){for(var n,r,f=.5*t,o=h.HALF_PI-2*Math.atan(a),u=0;u<=15;u++)if(n=t*Math.sin(o),o+=r=h.HALF_PI-2*Math.atan(a*Math.pow((1-n)/(1+n),f))-o,Math.abs(r)<=1e-10)return o;return-9999}},\n function _(n,i,e,t,r){function a(){}function f(n){return n}t(),e.init=a,e.forward=f,e.inverse=f,e.names=[\"longlat\",\"identity\"],e.default={init:a,forward:f,inverse:f,names:e.names}},\n function _(t,r,e,a,n){a();const f=t(1),i=t(85),u=(0,f.__importStar)(t(102)),c=(0,f.__importDefault)(t(88));e.eccentricity=function(t,r,e,a){var n=t*t,f=r*r,u=(n-f)/n,c=0;return a?(n=(t*=1-u*(i.SIXTH+u*(i.RA4+u*i.RA6)))*t,u=0):c=Math.sqrt(u),{es:u,e:c,ep2:(n-f)/f}},e.sphere=function(t,r,e,a,n){if(!t){var f=(0,c.default)(u.default,a);f||(f=u.WGS84),t=f.a,r=f.b,e=f.rf}return e&&!r&&(r=(1-1/e)*t),(0===e||Math.abs(t-r)3&&(0===s.datum_params[3]&&0===s.datum_params[4]&&0===s.datum_params[5]&&0===s.datum_params[6]||(s.datum_type=d.PJD_7PARAM,s.datum_params[3]*=d.SEC_TO_RAD,s.datum_params[4]*=d.SEC_TO_RAD,s.datum_params[5]*=d.SEC_TO_RAD,s.datum_params[6]=s.datum_params[6]/1e6+1))),r&&(s.datum_type=d.PJD_GRIDSHIFT,s.grids=r),s.a=_,s.b=t,s.es=u,s.ep2=p,s}},\n function _(t,e,n,r,i){r();var u={};function l(t){if(0===t.length)return null;var e=\"@\"===t[0];return e&&(t=t.slice(1)),\"null\"===t?{name:\"null\",mandatory:!e,grid:null,isNull:!0}:{name:t,mandatory:!e,grid:u[t]||null,isNull:!1}}function o(t){return t/3600*Math.PI/180}function a(t,e,n){return String.fromCharCode.apply(null,new Uint8Array(t.buffer.slice(e,n)))}function d(t){return t.map((function(t){return[o(t.longitudeShift),o(t.latitudeShift)]}))}function g(t,e,n){return{name:a(t,e+8,e+16).trim(),parent:a(t,e+24,e+24+8).trim(),lowerLatitude:t.getFloat64(e+72,n),upperLatitude:t.getFloat64(e+88,n),lowerLongitude:t.getFloat64(e+104,n),upperLongitude:t.getFloat64(e+120,n),latitudeInterval:t.getFloat64(e+136,n),longitudeInterval:t.getFloat64(e+152,n),gridNodeCount:t.getInt32(e+168,n)}}function s(t,e,n,r){for(var i=e+176,u=[],l=0;l1&&console.log(\"Only single NTv2 subgrids are currently supported, subsequent sub grids are ignored\");var l=function(t,e,n){for(var r=176,i=[],u=0;ua.y||f>a.x||N1e-12&&Math.abs(n.y)>1e-12);if(d<0)return console.log(\"Inverse grid shift iterator failed to converge.\"),a;a.x=(0,u.default)(l.x+t.ll[0]),a.y=l.y+t.ll[1]}else isNaN(l.x)||(a.x=r.x+l.x,a.y=r.y+l.y);return a}function f(r,e){var t,a={x:r.x/e.del[0],y:r.y/e.del[1]},i=Math.floor(a.x),l=Math.floor(a.y),n=a.x-1*i,o=a.y-1*l,u={x:Number.NaN,y:Number.NaN};if(i<0||i>=e.lim[0])return u;if(l<0||l>=e.lim[1])return u;t=l*e.lim[0]+i;var d=e.cvs[t][0],s=e.cvs[t][1];t++;var y=e.cvs[t][0],f=e.cvs[t][1];t+=e.lim[0];var x=e.cvs[t][0],m=e.cvs[t][1];t--;var N=e.cvs[t][0],c=e.cvs[t][1],_=n*o,g=n*(1-o),v=(1-n)*(1-o),S=(1-n)*o;return u.x=v*d+g*y+S*N+_*x,u.y=v*s+g*f+S*c+_*m,u}t.default=function(r,e,t){if((0,o.compareDatums)(r,e))return t;if(r.datum_type===n.PJD_NODATUM||e.datum_type===n.PJD_NODATUM)return t;var a=r.a,i=r.es;if(r.datum_type===n.PJD_GRIDSHIFT){if(0!==s(r,!1,t))return;a=n.SRS_WGS84_SEMIMAJOR,i=n.SRS_WGS84_ESQUARED}var l=e.a,u=e.b,y=e.es;if(e.datum_type===n.PJD_GRIDSHIFT&&(l=n.SRS_WGS84_SEMIMAJOR,u=n.SRS_WGS84_SEMIMINOR,y=n.SRS_WGS84_ESQUARED),i===y&&a===l&&!d(r.datum_type)&&!d(e.datum_type))return t;if(t=(0,o.geodeticToGeocentric)(t,i,a),d(r.datum_type)&&(t=(0,o.geocentricToWgs84)(t,r.datum_type,r.datum_params)),d(e.datum_type)&&(t=(0,o.geocentricFromWgs84)(t,e.datum_type,e.datum_params)),t=(0,o.geocentricToGeodetic)(t,y,l,u),e.datum_type===n.PJD_GRIDSHIFT&&0!==s(e,!0,t))return;return t},t.applyGridShift=s},\n function _(a,t,r,m,s){m();const u=a(85);r.compareDatums=function(a,t){return a.datum_type===t.datum_type&&(!(a.a!==t.a||Math.abs(a.es-t.es)>5e-11)&&(a.datum_type===u.PJD_3PARAM?a.datum_params[0]===t.datum_params[0]&&a.datum_params[1]===t.datum_params[1]&&a.datum_params[2]===t.datum_params[2]:a.datum_type!==u.PJD_7PARAM||a.datum_params[0]===t.datum_params[0]&&a.datum_params[1]===t.datum_params[1]&&a.datum_params[2]===t.datum_params[2]&&a.datum_params[3]===t.datum_params[3]&&a.datum_params[4]===t.datum_params[4]&&a.datum_params[5]===t.datum_params[5]&&a.datum_params[6]===t.datum_params[6]))},r.geodeticToGeocentric=function(a,t,r){var m,s,_,e,n=a.x,d=a.y,i=a.z?a.z:0;if(d<-u.HALF_PI&&d>-1.001*u.HALF_PI)d=-u.HALF_PI;else if(d>u.HALF_PI&&d<1.001*u.HALF_PI)d=u.HALF_PI;else{if(d<-u.HALF_PI)return{x:-1/0,y:-1/0,z:a.z};if(d>u.HALF_PI)return{x:1/0,y:1/0,z:a.z}}return n>Math.PI&&(n-=2*Math.PI),s=Math.sin(d),e=Math.cos(d),_=s*s,{x:((m=r/Math.sqrt(1-t*_))+i)*e*Math.cos(n),y:(m+i)*e*Math.sin(n),z:(m*(1-t)+i)*s}},r.geocentricToGeodetic=function(a,t,r,m){var s,_,e,n,d,i,p,P,y,z,M,o,A,c,x,h=1e-12,f=a.x,I=a.y,F=a.z?a.z:0;if(s=Math.sqrt(f*f+I*I),_=Math.sqrt(f*f+I*I+F*F),s/r1e-24&&A<30);return{x:c,y:Math.atan(M/Math.abs(z)),z:x}},r.geocentricToWgs84=function(a,t,r){if(t===u.PJD_3PARAM)return{x:a.x+r[0],y:a.y+r[1],z:a.z+r[2]};if(t===u.PJD_7PARAM){var m=r[0],s=r[1],_=r[2],e=r[3],n=r[4],d=r[5],i=r[6];return{x:i*(a.x-d*a.y+n*a.z)+m,y:i*(d*a.x+a.y-e*a.z)+s,z:i*(-n*a.x+e*a.y+a.z)+_}}},r.geocentricFromWgs84=function(a,t,r){if(t===u.PJD_3PARAM)return{x:a.x-r[0],y:a.y-r[1],z:a.z-r[2]};if(t===u.PJD_7PARAM){var m=r[0],s=r[1],_=r[2],e=r[3],n=r[4],d=r[5],i=r[6],p=(a.x-m)/i,P=(a.y-s)/i,y=(a.z-_)/i;return{x:p+d*P-n*y,y:-d*p+P+e*y,z:n*p-e*P+y}}}},\n function _(e,a,i,r,s){r(),i.default=function(e,a,i){var r,s,n,c=i.x,d=i.y,f=i.z||0,u={};for(n=0;n<3;n++)if(!a||2!==n||void 0!==i.z)switch(0===n?(r=c,s=-1!==\"ew\".indexOf(e.axis[n])?\"x\":\"y\"):1===n?(r=d,s=-1!==\"ns\".indexOf(e.axis[n])?\"y\":\"x\"):(r=f,s=\"z\"),e.axis[n]){case\"e\":u[s]=r;break;case\"w\":u[s]=-r;break;case\"n\":u[s]=r;break;case\"s\":u[s]=-r;break;case\"u\":void 0!==i[s]&&(u.z=r);break;case\"d\":void 0!==i[s]&&(u.z=-r);break;default:return null}return u}},\n function _(n,t,e,u,f){u(),e.default=function(n){var t={x:n[0],y:n[1]};return n.length>2&&(t.z=n[2]),n.length>3&&(t.m=n[3]),t}},\n function _(e,i,n,t,r){function o(e){if(\"function\"==typeof Number.isFinite){if(Number.isFinite(e))return;throw new TypeError(\"coordinates must be finite numbers\")}if(\"number\"!=typeof e||e!=e||!isFinite(e))throw new TypeError(\"coordinates must be finite numbers\")}t(),n.default=function(e){o(e.x),o(e.y)}},\n function _(e,i,s,t,o){t();const n=e(1);var l,a,r,_,c;const d=e(53),v=e(42),u=(0,n.__importStar)(e(45)),h=e(48),m=(0,n.__importStar)(e(18));class T extends v.View{initialize(){super.initialize(),this.visuals=new u.Visuals(this)}request_render(){this.parent.request_render()}get canvas(){return this.parent.canvas}set_data(e){const i=this;for(const s of this.model){if(!(s instanceof m.VectorSpec||s instanceof m.ScalarSpec))continue;const t=s.uniform(e);i[`${s.attr}`]=t}}}s.ArrowHeadView=T,T.__name__=\"ArrowHeadView\";class p extends d.Model{constructor(e){super(e)}}s.ArrowHead=p,l=p,p.__name__=\"ArrowHead\",l.define((()=>({size:[m.NumberSpec,25]})));class V extends T{clip(e,i){this.visuals.line.set_vectorize(e,i);const s=this.size.get(i);e.moveTo(.5*s,s),e.lineTo(.5*s,-2),e.lineTo(-.5*s,-2),e.lineTo(-.5*s,s),e.lineTo(0,0),e.lineTo(.5*s,s)}render(e,i){if(this.visuals.line.doit){this.visuals.line.set_vectorize(e,i);const s=this.size.get(i);e.beginPath(),e.moveTo(.5*s,s),e.lineTo(0,0),e.lineTo(-.5*s,s),e.stroke()}}}s.OpenHeadView=V,V.__name__=\"OpenHeadView\";class f extends p{constructor(e){super(e)}}s.OpenHead=f,a=f,f.__name__=\"OpenHead\",a.prototype.default_view=V,a.mixins(h.LineVector);class w extends T{clip(e,i){this.visuals.line.set_vectorize(e,i);const s=this.size.get(i);e.moveTo(.5*s,s),e.lineTo(.5*s,-2),e.lineTo(-.5*s,-2),e.lineTo(-.5*s,s),e.lineTo(.5*s,s)}render(e,i){this.visuals.fill.doit&&(this.visuals.fill.set_vectorize(e,i),this._normal(e,i),e.fill()),this.visuals.line.doit&&(this.visuals.line.set_vectorize(e,i),this._normal(e,i),e.stroke())}_normal(e,i){const s=this.size.get(i);e.beginPath(),e.moveTo(.5*s,s),e.lineTo(0,0),e.lineTo(-.5*s,s),e.closePath()}}s.NormalHeadView=w,w.__name__=\"NormalHeadView\";class H extends p{constructor(e){super(e)}}s.NormalHead=H,r=H,H.__name__=\"NormalHead\",r.prototype.default_view=w,r.mixins([h.LineVector,h.FillVector]),r.override({fill_color:\"black\"});class z extends T{clip(e,i){this.visuals.line.set_vectorize(e,i);const s=this.size.get(i);e.moveTo(.5*s,s),e.lineTo(.5*s,-2),e.lineTo(-.5*s,-2),e.lineTo(-.5*s,s),e.lineTo(0,.5*s),e.lineTo(.5*s,s)}render(e,i){this.visuals.fill.doit&&(this.visuals.fill.set_vectorize(e,i),this._vee(e,i),e.fill()),this.visuals.line.doit&&(this.visuals.line.set_vectorize(e,i),this._vee(e,i),e.stroke())}_vee(e,i){const s=this.size.get(i);e.beginPath(),e.moveTo(.5*s,s),e.lineTo(0,0),e.lineTo(-.5*s,s),e.lineTo(0,.5*s),e.closePath()}}s.VeeHeadView=z,z.__name__=\"VeeHeadView\";class x extends p{constructor(e){super(e)}}s.VeeHead=x,_=x,x.__name__=\"VeeHead\",_.prototype.default_view=z,_.mixins([h.LineVector,h.FillVector]),_.override({fill_color:\"black\"});class g extends T{render(e,i){if(this.visuals.line.doit){this.visuals.line.set_vectorize(e,i);const s=this.size.get(i);e.beginPath(),e.moveTo(.5*s,0),e.lineTo(-.5*s,0),e.stroke()}}clip(e,i){}}s.TeeHeadView=g,g.__name__=\"TeeHeadView\";class b extends p{constructor(e){super(e)}}s.TeeHead=b,c=b,b.__name__=\"TeeHead\",c.prototype.default_view=g,c.mixins(h.LineVector)},\n function _(n,e,t,i,o){i();const s=n(9);async function c(n,e,t){const i=new n(Object.assign(Object.assign({},t),{model:e}));return i.initialize(),await i.lazy_initialize(),i}t.build_view=async function(n,e={parent:null},t=(n=>n.default_view)){const i=await c(t(n),n,e);return i.connect_signals(),i},t.build_views=async function(n,e,t={parent:null},i=(n=>n.default_view)){const o=(0,s.difference)([...n.keys()],e);for(const e of o)n.get(e).remove(),n.delete(e);const a=[],f=e.filter((e=>!n.has(e)));for(const e of f){const o=await c(i(e),e,t);n.set(e,o),a.push(o)}for(const n of a)n.connect_signals();return a},t.remove_views=function(n){for(const[e,t]of n)t.remove(),n.delete(e)}},\n function _(e,s,_,i,l){i();const t=e(1);var o;const r=e(115),p=(0,t.__importStar)(e(48));class h extends r.UpperLowerView{paint(e){e.beginPath(),e.moveTo(this._lower_sx[0],this._lower_sy[0]);for(let s=0,_=this._lower_sx.length;s<_;s++)e.lineTo(this._lower_sx[s],this._lower_sy[s]);for(let s=this._upper_sx.length-1;s>=0;s--)e.lineTo(this._upper_sx[s],this._upper_sy[s]);e.closePath(),this.visuals.fill.apply(e),e.beginPath(),e.moveTo(this._lower_sx[0],this._lower_sy[0]);for(let s=0,_=this._lower_sx.length;s<_;s++)e.lineTo(this._lower_sx[s],this._lower_sy[s]);this.visuals.line.apply(e),e.beginPath(),e.moveTo(this._upper_sx[0],this._upper_sy[0]);for(let s=0,_=this._upper_sx.length;s<_;s++)e.lineTo(this._upper_sx[s],this._upper_sy[s]);this.visuals.line.apply(e)}}_.BandView=h,h.__name__=\"BandView\";class n extends r.UpperLower{constructor(e){super(e)}}_.Band=n,o=n,n.__name__=\"Band\",o.prototype.default_view=h,o.mixins([p.Line,p.Fill]),o.override({fill_color:\"#fff9ba\",fill_alpha:.4,line_color:\"#cccccc\",line_alpha:.3})},\n function _(e,t,i,s,o){s();const r=e(1);var n;const p=e(69),a=e(20),_=(0,r.__importStar)(e(18));class h extends p.DataAnnotationView{map_data(){const{frame:e}=this.plot_view,t=this.model.dimension,i=this.coordinates.x_scale,s=this.coordinates.y_scale,o=\"height\"==t?s:i,r=\"height\"==t?i:s,n=\"height\"==t?e.bbox.yview:e.bbox.xview,p=\"height\"==t?e.bbox.xview:e.bbox.yview;let a,_,h;a=\"data\"==this.model.properties.lower.units?o.v_compute(this._lower):n.v_compute(this._lower),_=\"data\"==this.model.properties.upper.units?o.v_compute(this._upper):n.v_compute(this._upper),h=\"data\"==this.model.properties.base.units?r.v_compute(this._base):p.v_compute(this._base);const[d,c]=\"height\"==t?[1,0]:[0,1],u=[a,h],l=[_,h];this._lower_sx=u[d],this._lower_sy=u[c],this._upper_sx=l[d],this._upper_sy=l[c]}}i.UpperLowerView=h,h.__name__=\"UpperLowerView\";class d extends _.CoordinateSpec{get dimension(){return\"width\"==this.obj.dimension?\"x\":\"y\"}get units(){var e;return null!==(e=this.spec.units)&&void 0!==e?e:\"data\"}}i.XOrYCoordinateSpec=d,d.__name__=\"XOrYCoordinateSpec\";class c extends p.DataAnnotation{constructor(e){super(e)}}i.UpperLower=c,n=c,c.__name__=\"UpperLower\",n.define((()=>({dimension:[a.Dimension,\"height\"],lower:[d,{field:\"lower\"}],upper:[d,{field:\"upper\"}],base:[d,{field:\"base\"}]})))},\n function _(t,o,i,n,e){n();const s=t(1);var l;const r=t(40),a=(0,s.__importStar)(t(48)),c=t(20),h=t(65);i.EDGE_TOLERANCE=2.5;class b extends r.AnnotationView{constructor(){super(...arguments),this.bbox=new h.BBox}connect_signals(){super.connect_signals(),this.connect(this.model.change,(()=>this.request_render()))}_render(){const{left:t,right:o,top:i,bottom:n}=this.model;if(null==t&&null==o&&null==i&&null==n)return;const{frame:e}=this.plot_view,s=this.coordinates.x_scale,l=this.coordinates.y_scale,r=(t,o,i,n,e)=>{let s;return s=null!=t?this.model.screen?t:\"data\"==o?i.compute(t):n.compute(t):e,s};this.bbox=h.BBox.from_rect({left:r(t,this.model.left_units,s,e.bbox.xview,e.bbox.left),right:r(o,this.model.right_units,s,e.bbox.xview,e.bbox.right),top:r(i,this.model.top_units,l,e.bbox.yview,e.bbox.top),bottom:r(n,this.model.bottom_units,l,e.bbox.yview,e.bbox.bottom)}),this._paint_box()}_paint_box(){const{ctx:t}=this.layer;t.save();const{left:o,top:i,width:n,height:e}=this.bbox;t.beginPath(),t.rect(o,i,n,e),this.visuals.fill.apply(t),this.visuals.hatch.apply(t),this.visuals.line.apply(t),t.restore()}interactive_bbox(){const t=this.model.line_width+i.EDGE_TOLERANCE;return this.bbox.grow_by(t)}interactive_hit(t,o){if(null==this.model.in_cursor)return!1;return this.interactive_bbox().contains(t,o)}cursor(t,o){const{left:i,right:n,bottom:e,top:s}=this.bbox;return Math.abs(t-i)<3||Math.abs(t-n)<3?this.model.ew_cursor:Math.abs(o-e)<3||Math.abs(o-s)<3?this.model.ns_cursor:this.bbox.contains(t,o)?this.model.in_cursor:null}}i.BoxAnnotationView=b,b.__name__=\"BoxAnnotationView\";class u extends r.Annotation{constructor(t){super(t)}update({left:t,right:o,top:i,bottom:n}){this.setv({left:t,right:o,top:i,bottom:n,screen:!0})}}i.BoxAnnotation=u,l=u,u.__name__=\"BoxAnnotation\",l.prototype.default_view=b,l.mixins([a.Line,a.Fill,a.Hatch]),l.define((({Number:t,Nullable:o})=>({top:[o(t),null],top_units:[c.SpatialUnits,\"data\"],bottom:[o(t),null],bottom_units:[c.SpatialUnits,\"data\"],left:[o(t),null],left_units:[c.SpatialUnits,\"data\"],right:[o(t),null],right_units:[c.SpatialUnits,\"data\"],render_mode:[c.RenderMode,\"canvas\"]}))),l.internal((({Boolean:t,String:o,Nullable:i})=>({screen:[t,!1],ew_cursor:[i(o),null],ns_cursor:[i(o),null],in_cursor:[i(o),null]}))),l.override({fill_color:\"#fff9ba\",fill_alpha:.4,line_color:\"#cccccc\",line_alpha:.3})},\n function _(t,e,i,o,n){o();const a=t(1);var r;const s=t(40),l=t(118),_=t(126),c=t(127),h=t(130),u=t(168),p=t(131),m=t(192),g=t(132),d=t(173),f=t(172),w=t(196),b=t(204),v=t(206),x=t(133),y=t(20),k=(0,a.__importStar)(t(48)),z=t(9),j=t(207),C=t(208),L=t(211),B=t(123),S=t(11),M=t(113),T=t(65),A=t(8);class O extends s.AnnotationView{get orientation(){return this._orientation}initialize(){super.initialize();const{ticker:t,formatter:e,color_mapper:i}=this.model;this._ticker=\"auto\"!=t?t:(()=>{switch(!0){case i instanceof w.LogColorMapper:return new u.LogTicker;case i instanceof w.ScanningColorMapper:return new u.BinnedTicker({mapper:i});case i instanceof w.CategoricalColorMapper:return new u.CategoricalTicker;default:return new u.BasicTicker}})(),this._formatter=\"auto\"!=e?e:(()=>{switch(!0){case this._ticker instanceof u.LogTicker:return new m.LogTickFormatter;case i instanceof w.CategoricalColorMapper:return new m.CategoricalTickFormatter;default:return new m.BasicTickFormatter}})(),this._major_range=(()=>{if(i instanceof w.CategoricalColorMapper){const{factors:t}=i;return new v.FactorRange({factors:t})}if(i instanceof f.ContinuousColorMapper){const{min:t,max:e}=i.metrics;return new v.Range1d({start:t,end:e})}(0,S.unreachable)()})(),this._major_scale=(()=>{if(i instanceof w.LinearColorMapper)return new b.LinearScale;if(i instanceof w.LogColorMapper)return new b.LogScale;if(i instanceof w.ScanningColorMapper){const{binning:t}=i.metrics;return new b.LinearInterpolationScale({binning:t})}if(i instanceof w.CategoricalColorMapper)return new b.CategoricalScale;(0,S.unreachable)()})(),this._minor_range=new v.Range1d({start:0,end:1}),this._minor_scale=new b.LinearScale;const o=k.attrs_of(this.model,\"major_label_\",k.Text,!0),n=k.attrs_of(this.model,\"major_tick_\",k.Line,!0),a=k.attrs_of(this.model,\"minor_tick_\",k.Line,!0),r=k.attrs_of(this.model,\"title_\",k.Text),s=i instanceof w.CategoricalColorMapper?c.CategoricalAxis:i instanceof w.LogColorMapper?c.LogAxis:c.LinearAxis;this._axis=new s(Object.assign(Object.assign(Object.assign({ticker:this._ticker,formatter:this._formatter,major_tick_in:this.model.major_tick_in,major_tick_out:this.model.major_tick_out,minor_tick_in:this.model.minor_tick_in,minor_tick_out:this.model.minor_tick_out,major_label_standoff:this.model.label_standoff,major_label_overrides:this.model.major_label_overrides,major_label_policy:this.model.major_label_policy,axis_line_color:null},o),n),a));const{title:_}=this.model;_&&(this._title=new l.Title(Object.assign({text:_,standoff:this.model.title_standoff},r)))}async lazy_initialize(){await super.lazy_initialize();const t=this,e={get parent(){return t.parent},get root(){return t.root},get frame(){return t._frame},get canvas_view(){return t.parent.canvas_view},request_layout(){t.parent.request_layout()}};this._axis_view=await(0,M.build_view)(this._axis,{parent:e}),null!=this._title&&(this._title_view=await(0,M.build_view)(this._title,{parent:e}))}remove(){var t;null===(t=this._title_view)||void 0===t||t.remove(),this._axis_view.remove(),super.remove()}connect_signals(){super.connect_signals(),this.connect(this._ticker.change,(()=>this.request_render())),this.connect(this._formatter.change,(()=>this.request_render())),this.connect(this.model.color_mapper.metrics_change,(()=>{const t=this._major_range,e=this._major_scale,{color_mapper:i}=this.model;if(i instanceof f.ContinuousColorMapper&&t instanceof v.Range1d){const{min:e,max:o}=i.metrics;t.setv({start:e,end:o})}if(i instanceof w.ScanningColorMapper&&e instanceof b.LinearInterpolationScale){const{binning:t}=i.metrics;e.binning=t}this._set_canvas_image(),this.plot_view.request_layout()}))}_set_canvas_image(){const{orientation:t}=this,e=(()=>{const{palette:e}=this.model.color_mapper;return\"vertical\"==t?(0,z.reversed)(e):e})(),[i,o]=\"vertical\"==t?[1,e.length]:[e.length,1],n=this._image=document.createElement(\"canvas\");n.width=i,n.height=o;const a=n.getContext(\"2d\"),r=a.getImageData(0,0,i,o),s=new w.LinearColorMapper({palette:e}).rgba_mapper.v_compute((0,z.range)(0,e.length));r.data.set(s),a.putImageData(r,0,0)}update_layout(){const{location:t,width:e,height:i,padding:o,margin:n}=this.model,[a,r]=(()=>{if(!(0,A.isString)(t))return[\"end\",\"start\"];switch(t){case\"top_left\":return[\"start\",\"start\"];case\"top\":case\"top_center\":return[\"start\",\"center\"];case\"top_right\":return[\"start\",\"end\"];case\"bottom_left\":return[\"end\",\"start\"];case\"bottom\":case\"bottom_center\":return[\"end\",\"center\"];case\"bottom_right\":return[\"end\",\"end\"];case\"left\":case\"center_left\":return[\"center\",\"start\"];case\"center\":case\"center_center\":return[\"center\",\"center\"];case\"right\":case\"center_right\":return[\"center\",\"end\"]}})(),s=this._orientation=(()=>{const{orientation:t}=this.model;return\"auto\"==t?null!=this.panel?this.panel.is_horizontal?\"horizontal\":\"vertical\":\"start\"==r||\"end\"==r||\"center\"==r&&\"center\"==a?\"vertical\":\"horizontal\":t})(),l=new C.NodeLayout,c=new C.VStack,h=new C.VStack,u=new C.HStack,p=new C.HStack;l.absolute=!0,c.absolute=!0,h.absolute=!0,u.absolute=!0,p.absolute=!0;const[m,g,d,f]=(()=>\"horizontal\"==s?[this._major_scale,this._minor_scale,this._major_range,this._minor_range]:[this._minor_scale,this._major_scale,this._minor_range,this._major_range])();this._frame=new _.CartesianFrame(m,g,d,f),l.on_resize((t=>this._frame.set_geometry(t)));const w=new L.BorderLayout;this._inner_layout=w,w.absolute=!0,w.center_panel=l,w.top_panel=c,w.bottom_panel=h,w.left_panel=u,w.right_panel=p;const b={left:o,right:o,top:o,bottom:o},v=(()=>{if(null==this.panel){if((0,A.isString)(t))return{left:n,right:n,top:n,bottom:n};{const[e,i]=t;return{left:e,right:n,top:n,bottom:i}}}if(!(0,A.isString)(t)){const[e,i]=t;return w.fixup_geometry=(t,o)=>{const n=t,a=this.layout.bbox,{width:r,height:s}=t;if(t=new T.BBox({left:a.left+e,bottom:a.bottom-i,width:r,height:s}),null!=o){const e=t.left-n.left,i=t.top-n.top,{left:a,top:r,width:s,height:l}=o;o=new T.BBox({left:a+e,top:r+i,width:s,height:l})}return[t,o]},{left:e,right:0,top:0,bottom:i}}w.fixup_geometry=(t,e)=>{const i=t;if(\"horizontal\"==s){const{top:e,width:i,height:o}=t;if(\"end\"==r){const{right:n}=this.layout.bbox;t=new T.BBox({right:n,top:e,width:i,height:o})}else if(\"center\"==r){const{hcenter:n}=this.layout.bbox;t=new T.BBox({hcenter:Math.round(n),top:e,width:i,height:o})}}else{const{left:e,width:i,height:o}=t;if(\"end\"==a){const{bottom:n}=this.layout.bbox;t=new T.BBox({left:e,bottom:n,width:i,height:o})}else if(\"center\"==a){const{vcenter:n}=this.layout.bbox;t=new T.BBox({left:e,vcenter:Math.round(n),width:i,height:o})}}if(null!=e){const o=t.left-i.left,n=t.top-i.top,{left:a,top:r,width:s,height:l}=e;e=new T.BBox({left:a+o,top:r+n,width:s,height:l})}return[t,e]}})();let x,y,k,z;if(w.padding=b,null!=this.panel?(x=\"max\",y=void 0,k=void 0,z=void 0):\"auto\"==(\"horizontal\"==s?e:i)?(x=\"fixed\",y=25*this.model.color_mapper.palette.length,k={percent:.3},z={percent:.8}):(x=\"fit\",y=void 0),\"horizontal\"==s){const t=\"auto\"==e?void 0:e,o=\"auto\"==i?25:i;w.set_sizing({width_policy:x,height_policy:\"min\",width:y,min_width:k,max_width:z,halign:r,valign:a,margin:v}),w.center_panel.set_sizing({width_policy:\"auto\"==e?\"fit\":\"fixed\",height_policy:\"fixed\",width:t,height:o})}else{const t=\"auto\"==e?25:e,o=\"auto\"==i?void 0:i;w.set_sizing({width_policy:\"min\",height_policy:x,height:y,min_height:k,max_height:z,halign:r,valign:a,margin:v}),w.center_panel.set_sizing({width_policy:\"fixed\",height_policy:\"auto\"==i?\"fit\":\"fixed\",width:t,height:o})}c.set_sizing({width_policy:\"fit\",height_policy:\"min\"}),h.set_sizing({width_policy:\"fit\",height_policy:\"min\"}),u.set_sizing({width_policy:\"min\",height_policy:\"fit\"}),p.set_sizing({width_policy:\"min\",height_policy:\"fit\"});const{_title_view:S}=this;null!=S&&(\"horizontal\"==s?(S.panel=new B.Panel(\"above\"),S.update_layout(),c.children.push(S.layout)):(S.panel=new B.Panel(\"left\"),S.update_layout(),u.children.push(S.layout)));const{panel:M}=this,O=null!=M&&s==M.orientation?M.side:\"horizontal\"==s?\"below\":\"right\",R=(()=>{switch(O){case\"above\":return c;case\"below\":return h;case\"left\":return u;case\"right\":return p}})(),{_axis_view:F}=this;if(F.panel=new B.Panel(O),F.update_layout(),R.children.push(F.layout),null!=this.panel){const t=new j.Grid([{layout:w,row:0,col:0}]);t.absolute=!0,\"horizontal\"==s?t.set_sizing({width_policy:\"max\",height_policy:\"min\"}):t.set_sizing({width_policy:\"min\",height_policy:\"max\"}),this.layout=t}else this.layout=this._inner_layout;const{visible:I}=this.model;this.layout.sizing.visible=I,this._set_canvas_image()}_render(){var t;const{ctx:e}=this.layer;e.save(),this._paint_bbox(e,this._inner_layout.bbox),this._paint_image(e,this._inner_layout.center_panel.bbox),null===(t=this._title_view)||void 0===t||t.render(),this._axis_view.render(),e.restore()}_paint_bbox(t,e){const{x:i,y:o}=e;let{width:n,height:a}=e;i+n>=this.parent.canvas_view.bbox.width&&(n-=1),o+a>=this.parent.canvas_view.bbox.height&&(a-=1),t.save(),this.visuals.background_fill.doit&&(this.visuals.background_fill.set_value(t),t.fillRect(i,o,n,a)),this.visuals.border_line.doit&&(this.visuals.border_line.set_value(t),t.strokeRect(i,o,n,a)),t.restore()}_paint_image(t,e){const{x:i,y:o,width:n,height:a}=e;t.save(),t.setImageSmoothingEnabled(!1),t.globalAlpha=this.model.scale_alpha,t.drawImage(this._image,i,o,n,a),this.visuals.bar_line.doit&&(this.visuals.bar_line.set_value(t),t.strokeRect(i,o,n,a)),t.restore()}serializable_state(){const t=super.serializable_state(),{children:e=[]}=t,i=(0,a.__rest)(t,[\"children\"]);return null!=this._title_view&&e.push(this._title_view.serializable_state()),e.push(this._axis_view.serializable_state()),Object.assign(Object.assign({},i),{children:e})}}i.ColorBarView=O,O.__name__=\"ColorBarView\";class R extends s.Annotation{constructor(t){super(t)}}i.ColorBar=R,r=R,R.__name__=\"ColorBar\",r.prototype.default_view=O,r.mixins([[\"major_label_\",k.Text],[\"title_\",k.Text],[\"major_tick_\",k.Line],[\"minor_tick_\",k.Line],[\"border_\",k.Line],[\"bar_\",k.Line],[\"background_\",k.Fill]]),r.define((({Alpha:t,Number:e,String:i,Tuple:o,Dict:n,Or:a,Ref:r,Auto:s,Nullable:l})=>({location:[a(y.Anchor,o(e,e)),\"top_right\"],orientation:[a(y.Orientation,s),\"auto\"],title:[l(i),null],title_standoff:[e,2],width:[a(e,s),\"auto\"],height:[a(e,s),\"auto\"],scale_alpha:[t,1],ticker:[a(r(h.Ticker),s),\"auto\"],formatter:[a(r(p.TickFormatter),s),\"auto\"],major_label_overrides:[n(a(i,r(x.BaseText))),{}],major_label_policy:[r(g.LabelingPolicy),()=>new g.NoOverlap],color_mapper:[r(d.ColorMapper)],label_standoff:[e,5],margin:[e,30],padding:[e,10],major_tick_in:[e,5],major_tick_out:[e,0],minor_tick_in:[e,0],minor_tick_out:[e,0]}))),r.override({background_fill_color:\"#ffffff\",background_fill_alpha:.95,bar_line_color:null,border_line_color:null,major_label_text_font_size:\"11px\",major_tick_line_color:\"#ffffff\",minor_tick_line_color:null,title_text_font_size:\"13px\",title_text_font_style:\"italic\"})},\n function _(t,e,i,s,l){s();const o=t(1);var a;const n=t(119),r=t(20),c=t(120),h=(0,o.__importStar)(t(48));class _ extends n.TextAnnotationView{_get_location(){const t=this.model.offset,e=this.model.standoff/2;let i,s;const{bbox:l}=this.layout;switch(this.panel.side){case\"above\":case\"below\":switch(this.model.vertical_align){case\"top\":s=l.top+e;break;case\"middle\":s=l.vcenter;break;case\"bottom\":s=l.bottom-e}switch(this.model.align){case\"left\":i=l.left+t;break;case\"center\":i=l.hcenter;break;case\"right\":i=l.right-t}break;case\"left\":switch(this.model.vertical_align){case\"top\":i=l.left+e;break;case\"middle\":i=l.hcenter;break;case\"bottom\":i=l.right-e}switch(this.model.align){case\"left\":s=l.bottom-t;break;case\"center\":s=l.vcenter;break;case\"right\":s=l.top+t}break;case\"right\":switch(this.model.vertical_align){case\"top\":i=l.right-e;break;case\"middle\":i=l.hcenter;break;case\"bottom\":i=l.left+e}switch(this.model.align){case\"left\":s=l.top+t;break;case\"center\":s=l.vcenter;break;case\"right\":s=l.bottom-t}}return[i,s]}_render(){const{text:t}=this.model;if(null==t||0==t.length)return;this.model.text_baseline=this.model.vertical_align,this.model.text_align=this.model.align;const[e,i]=this._get_location(),s=this.panel.get_label_angle_heuristic(\"parallel\");(\"canvas\"==this.model.render_mode?this._canvas_text.bind(this):this._css_text.bind(this))(this.layer.ctx,t,e,i,s)}_get_size(){const{text:t}=this.model,e=new c.TextBox({text:t});e.visuals=this.visuals.text.values();const{width:i,height:s}=e.size();return{width:i,height:0==s?0:2+s+this.model.standoff}}}i.TitleView=_,_.__name__=\"TitleView\";class d extends n.TextAnnotation{constructor(t){super(t)}}i.Title=d,a=d,d.__name__=\"Title\",a.prototype.default_view=_,a.mixins([h.Text,[\"border_\",h.Line],[\"background_\",h.Fill]]),a.define((({Number:t,String:e})=>({text:[e,\"\"],vertical_align:[r.VerticalAlign,\"bottom\"],align:[r.TextAlign,\"left\"],offset:[t,0],standoff:[t,10]}))),a.prototype._props.text_align.options.internal=!0,a.prototype._props.text_baseline.options.internal=!0,a.override({text_font_size:\"13px\",text_font_style:\"bold\",text_line_height:1,background_fill_color:null,border_line_color:null})},\n function _(e,t,s,i,l){var n;i();const o=e(40),a=e(43),r=e(20),d=e(120),u=e(123),c=e(11);class h extends o.AnnotationView{update_layout(){const{panel:e}=this;this.layout=null!=e?new u.SideLayout(e,(()=>this.get_size()),!0):void 0}initialize(){super.initialize(),\"css\"==this.model.render_mode&&(this.el=(0,a.div)(),this.plot_view.canvas_view.add_overlay(this.el))}remove(){null!=this.el&&(0,a.remove)(this.el),super.remove()}connect_signals(){super.connect_signals(),\"css\"==this.model.render_mode?this.connect(this.model.change,(()=>this.render())):this.connect(this.model.change,(()=>this.request_render()))}render(){this.model.visible||\"css\"!=this.model.render_mode||(0,a.undisplay)(this.el),super.render()}_canvas_text(e,t,s,i,l){const n=new d.TextBox({text:t});n.angle=l,n.position={sx:s,sy:i},n.visuals=this.visuals.text.values();const{background_fill:o,border_line:a}=this.visuals;if(o.doit||a.doit){const{p0:t,p1:s,p2:i,p3:l}=n.rect();e.beginPath(),e.moveTo(t.x,t.y),e.lineTo(s.x,s.y),e.lineTo(i.x,i.y),e.lineTo(l.x,l.y),e.closePath(),this.visuals.background_fill.apply(e),this.visuals.border_line.apply(e)}this.visuals.text.doit&&n.paint(e)}_css_text(e,t,s,i,l){const{el:n}=this;(0,c.assert)(null!=n),(0,a.undisplay)(n),n.textContent=t,this.visuals.text.set_value(e),n.style.position=\"absolute\",n.style.left=`${s}px`,n.style.top=`${i}px`,n.style.color=e.fillStyle,n.style.font=e.font,n.style.lineHeight=\"normal\",n.style.whiteSpace=\"pre\";const[o,r]=(()=>{switch(this.visuals.text.text_align.get_value()){case\"left\":return[\"left\",\"0%\"];case\"center\":return[\"center\",\"-50%\"];case\"right\":return[\"right\",\"-100%\"]}})(),[d,u]=(()=>{switch(this.visuals.text.text_baseline.get_value()){case\"top\":return[\"top\",\"0%\"];case\"middle\":return[\"center\",\"-50%\"];case\"bottom\":return[\"bottom\",\"-100%\"];default:return[\"center\",\"-50%\"]}})();let h=`translate(${r}, ${u})`;l&&(h+=`rotate(${l}rad)`),n.style.transformOrigin=`${o} ${d}`,n.style.transform=h,this.layout,this.visuals.background_fill.doit&&(this.visuals.background_fill.set_value(e),n.style.backgroundColor=e.fillStyle),this.visuals.border_line.doit&&(this.visuals.border_line.set_value(e),n.style.borderStyle=e.lineDash.length<2?\"solid\":\"dashed\",n.style.borderWidth=`${e.lineWidth}px`,n.style.borderColor=e.strokeStyle),(0,a.display)(n)}}s.TextAnnotationView=h,h.__name__=\"TextAnnotationView\";class _ extends o.Annotation{constructor(e){super(e)}}s.TextAnnotation=_,n=_,_.__name__=\"TextAnnotation\",n.define((()=>({render_mode:[r.RenderMode,\"canvas\"]})))},\n function _(t,e,s,i,n){i();const h=t(65),o=t(121),r=t(9),a=t(8),c=t(122),_=t(22);s.text_width=(()=>{const t=document.createElement(\"canvas\").getContext(\"2d\");let e=\"\";return(s,i)=>(i!=e&&(e=i,t.font=i),t.measureText(s).width)})();class l{constructor(){this._position={sx:0,sy:0},this.font_size_scale=1,this.align=\"left\",this._base_font_size=13,this._x_anchor=\"left\",this._y_anchor=\"center\"}set base_font_size(t){null!=t&&(this._base_font_size=t)}get base_font_size(){return this._base_font_size}set position(t){this._position=t}get position(){return this._position}infer_text_height(){return\"ascent_descent\"}bbox(){const{p0:t,p1:e,p2:s,p3:i}=this.rect(),n=Math.min(t.x,e.x,s.x,i.x),o=Math.min(t.y,e.y,s.y,i.y),r=Math.max(t.x,e.x,s.x,i.x),a=Math.max(t.y,e.y,s.y,i.y);return new h.BBox({left:n,right:r,top:o,bottom:a})}size(){const{width:t,height:e}=this._size(),{angle:s}=this;if(s){const i=Math.cos(Math.abs(s)),n=Math.sin(Math.abs(s));return{width:Math.abs(t*i+e*n),height:Math.abs(t*n+e*i)}}return{width:t,height:e}}rect(){const t=this._rect(),{angle:e}=this;if(e){const{sx:s,sy:i}=this.position,n=new c.AffineTransform;return n.translate(s,i),n.rotate(e),n.translate(-s,-i),n.apply_rect(t)}return t}paint_rect(t){const{p0:e,p1:s,p2:i,p3:n}=this.rect();t.save(),t.strokeStyle=\"red\",t.lineWidth=1,t.beginPath();const{round:h}=Math;t.moveTo(h(e.x),h(e.y)),t.lineTo(h(s.x),h(s.y)),t.lineTo(h(i.x),h(i.y)),t.lineTo(h(n.x),h(n.y)),t.closePath(),t.stroke(),t.restore()}paint_bbox(t){const{x:e,y:s,width:i,height:n}=this.bbox();t.save(),t.strokeStyle=\"blue\",t.lineWidth=1,t.beginPath();const{round:h}=Math;t.moveTo(h(e),h(s)),t.lineTo(h(e),h(s+n)),t.lineTo(h(e+i),h(s+n)),t.lineTo(h(e+i),h(s)),t.closePath(),t.stroke(),t.restore()}}s.GraphicsBox=l,l.__name__=\"GraphicsBox\";class x extends l{constructor({text:t}){super(),this.text=t}set visuals(t){const e=t.color,s=t.alpha,i=t.font_style;let n=t.font_size;const h=t.font,{font_size_scale:r,base_font_size:a}=this,c=(0,o.parse_css_font_size)(n);if(null!=c){let{value:t,unit:e}=c;t*=r,\"em\"==e&&a&&(t*=a,e=\"px\"),n=`${t}${e}`}const l=`${i} ${n} ${h}`;this.font=l,this.color=(0,_.color2css)(e,s),this.line_height=t.line_height;const x=t.align;this._x_anchor=x;const u=t.baseline;this._y_anchor=(()=>{switch(u){case\"top\":return\"top\";case\"middle\":return\"center\";case\"bottom\":return\"bottom\";default:return\"baseline\"}})()}infer_text_height(){if(this.text.includes(\"\\n\"))return\"ascent_descent\";{function t(t){for(const e of new Set(t))if(!(\"0\"<=e&&e<=\"9\"))switch(e){case\",\":case\".\":case\"+\":case\"-\":case\"\\u2212\":case\"e\":continue;default:return!1}return!0}return t(this.text)?\"cap\":\"ascent_descent\"}}_text_line(t){var e;const s=null!==(e=this.text_height_metric)&&void 0!==e?e:this.infer_text_height(),i=(()=>{switch(s){case\"x\":case\"x_descent\":return t.x_height;case\"cap\":case\"cap_descent\":return t.cap_height;case\"ascent\":case\"ascent_descent\":return t.ascent}})(),n=(()=>{switch(s){case\"x\":case\"cap\":case\"ascent\":return 0;case\"x_descent\":case\"cap_descent\":case\"ascent_descent\":return t.descent}})();return{height:i+n,ascent:i,descent:n}}get nlines(){return this.text.split(\"\\n\").length}_size(){var t,e;const{font:i}=this,n=(0,o.font_metrics)(i),h=(this.line_height-1)*n.height,a=\"\"==this.text,c=this.text.split(\"\\n\"),_=c.length,l=c.map((t=>(0,s.text_width)(t,i))),x=this._text_line(n).height*_,u=\"%\"==(null===(t=this.width)||void 0===t?void 0:t.unit)?this.width.value:1,p=\"%\"==(null===(e=this.height)||void 0===e?void 0:e.unit)?this.height.value:1;return{width:(0,r.max)(l)*u,height:a?0:(x+h*(_-1))*p,metrics:n}}_computed_position(t,e,s){const{width:i,height:n}=t,{sx:h,sy:o,x_anchor:r=this._x_anchor,y_anchor:c=this._y_anchor}=this.position;return{x:h-(()=>{if((0,a.isNumber)(r))return r*i;switch(r){case\"left\":return 0;case\"center\":return.5*i;case\"right\":return i}})(),y:o-(()=>{var t;if((0,a.isNumber)(c))return c*n;switch(c){case\"top\":return 0;case\"center\":return.5*n;case\"bottom\":return n;case\"baseline\":if(1!=s)return.5*n;switch(null!==(t=this.text_height_metric)&&void 0!==t?t:this.infer_text_height()){case\"x\":case\"x_descent\":return e.x_height;case\"cap\":case\"cap_descent\":return e.cap_height;case\"ascent\":case\"ascent_descent\":return e.ascent}}})()}}_rect(){const{width:t,height:e,metrics:s}=this._size(),i=this.text.split(\"\\n\").length,{x:n,y:o}=this._computed_position({width:t,height:e},s,i);return new h.BBox({x:n,y:o,width:t,height:e}).rect}paint(t){var e,i;const{font:n}=this,h=(0,o.font_metrics)(n),a=(this.line_height-1)*h.height,c=this.text.split(\"\\n\"),_=c.length,l=c.map((t=>(0,s.text_width)(t,n))),x=this._text_line(h),u=x.height*_,p=\"%\"==(null===(e=this.width)||void 0===e?void 0:e.unit)?this.width.value:1,f=\"%\"==(null===(i=this.height)||void 0===i?void 0:i.unit)?this.height.value:1,g=(0,r.max)(l)*p,d=(u+a*(_-1))*f;t.save(),t.fillStyle=this.color,t.font=this.font,t.textAlign=\"left\",t.textBaseline=\"alphabetic\";const{sx:b,sy:m}=this.position,{align:y}=this,{angle:w}=this;w&&(t.translate(b,m),t.rotate(w),t.translate(-b,-m));let{x:v,y:z}=this._computed_position({width:g,height:d},h,_);if(\"justify\"==y)for(let e=0;e<_;e++){let i=v;const h=c[e].split(\" \"),o=h.length,_=h.map((t=>(0,s.text_width)(t,n))),l=(g-(0,r.sum)(_))/(o-1);for(let e=0;e{switch(y){case\"left\":return 0;case\"center\":return.5*(g-l[e]);case\"right\":return g-l[e]}})();t.fillStyle=this.color,t.fillText(c[e],s,z+x.ascent),z+=x.height+a}t.restore()}}s.TextBox=x,x.__name__=\"TextBox\";class u extends l{constructor(t,e){super(),this.base=t,this.expo=e}get children(){return[this.base,this.expo]}set base_font_size(t){super.base_font_size=t,this.base.base_font_size=t,this.expo.base_font_size=t}set position(t){this._position=t;const e=this.base.size(),s=this.expo.size(),i=this._shift_scale()*e.height,n=Math.max(e.height,i+s.height);this.base.position={sx:0,x_anchor:\"left\",sy:n,y_anchor:\"bottom\"},this.expo.position={sx:e.width,x_anchor:\"left\",sy:i,y_anchor:\"bottom\"}}get position(){return this._position}set visuals(t){this.expo.font_size_scale=.7,this.base.visuals=t,this.expo.visuals=t}_shift_scale(){if(this.base instanceof x&&1==this.base.nlines){const{x_height:t,cap_height:e}=(0,o.font_metrics)(this.base.font);return t/e}return 2/3}infer_text_height(){return this.base.infer_text_height()}_rect(){const t=this.base.bbox(),e=this.expo.bbox(),s=t.union(e),{x:i,y:n}=this._computed_position();return s.translate(i,n).rect}_size(){const t=this.base.size(),e=this.expo.size();return{width:t.width+e.width,height:Math.max(t.height,this._shift_scale()*t.height+e.height)}}paint(t){t.save();const{angle:e}=this;if(e){const{sx:s,sy:i}=this.position;t.translate(s,i),t.rotate(e),t.translate(-s,-i)}const{x:s,y:i}=this._computed_position();t.translate(s,i),this.base.paint(t),this.expo.paint(t),t.restore()}paint_bbox(t){super.paint_bbox(t);const{x:e,y:s}=this._computed_position();t.save(),t.translate(e,s);for(const e of this.children)e.paint_bbox(t);t.restore()}_computed_position(){const{width:t,height:e}=this._size(),{sx:s,sy:i,x_anchor:n=this._x_anchor,y_anchor:h=this._y_anchor}=this.position;return{x:s-(()=>{if((0,a.isNumber)(n))return n*t;switch(n){case\"left\":return 0;case\"center\":return.5*t;case\"right\":return t}})(),y:i-(()=>{if((0,a.isNumber)(h))return h*e;switch(h){case\"top\":return 0;case\"center\":return.5*e;case\"bottom\":return e;case\"baseline\":return.5*e}})()}}}s.BaseExpo=u,u.__name__=\"BaseExpo\";class p{constructor(t){this.items=t}set base_font_size(t){for(const e of this.items)e.base_font_size=t}get length(){return this.items.length}set visuals(t){for(const e of this.items)e.visuals=t;const e={x:0,cap:1,ascent:2,x_descent:3,cap_descent:4,ascent_descent:5},s=(0,r.max_by)(this.items.map((t=>t.infer_text_height())),(t=>e[t]));for(const t of this.items)t.text_height_metric=s}set angle(t){for(const e of this.items)e.angle=t}max_size(){let t=0,e=0;for(const s of this.items){const i=s.size();t=Math.max(t,i.width),e=Math.max(e,i.height)}return{width:t,height:e}}}s.GraphicsBoxes=p,p.__name__=\"GraphicsBoxes\"},\n function _(t,e,n,r,l){r();const a=t(11),c=(()=>{try{return\"undefined\"!=typeof OffscreenCanvas&&null!=new OffscreenCanvas(0,0).getContext(\"2d\")}catch(t){return!1}})()?(t,e)=>new OffscreenCanvas(t,e):(t,e)=>{const n=document.createElement(\"canvas\");return n.width=t,n.height=e,n},o=(()=>{const t=c(0,0).getContext(\"2d\");return e=>{t.font=e;const n=t.measureText(\"M\"),r=t.measureText(\"x\"),l=t.measureText(\"\\xc5\\u015ag|\"),c=l.fontBoundingBoxAscent,o=l.fontBoundingBoxDescent;if(null!=c&&null!=o)return{height:c+o,ascent:c,descent:o,cap_height:n.actualBoundingBoxAscent,x_height:r.actualBoundingBoxAscent};const s=l.actualBoundingBoxAscent,u=l.actualBoundingBoxDescent;if(null!=s&&null!=u)return{height:s+u,ascent:s,descent:u,cap_height:n.actualBoundingBoxAscent,x_height:r.actualBoundingBoxAscent};(0,a.unreachable)()}})(),s=(()=>{const t=c(0,0).getContext(\"2d\");return(e,n)=>{t.font=n;const r=t.measureText(e),l=r.actualBoundingBoxAscent,c=r.actualBoundingBoxDescent;if(null!=l&&null!=c)return{width:r.width,height:l+c,ascent:l,descent:c};(0,a.unreachable)()}})(),u=(()=>{const t=document.createElement(\"canvas\"),e=t.getContext(\"2d\");let n=-1,r=-1;return(l,a=1)=>{e.font=l;const{width:c}=e.measureText(\"M\"),o=c*a,s=Math.ceil(o),u=Math.ceil(2*o),i=Math.ceil(1.5*o);n{let e=0;for(let n=0;n<=i;n++)for(let r=0;r{let e=t.length-4;for(let n=u;n>=i;n--)for(let r=0;r{const t=document.createElement(\"canvas\"),e=t.getContext(\"2d\");let n=-1,r=-1;return(l,a,c=1)=>{e.font=a;const{width:o}=e.measureText(\"M\"),s=o*c,u=Math.ceil(s),i=Math.ceil(2*s),f=Math.ceil(1.5*s);(n{let e=0;for(let n=0;n<=f;n++)for(let r=0;r{let e=t.length-4;for(let n=i;n>=f;n--)for(let r=0;r{try{return o(\"normal 10px sans-serif\"),o}catch(t){return u}})(),h=(()=>{try{return s(\"A\",\"normal 10px sans-serif\"),s}catch(t){return i}})(),g=new Map;function d(t){let e=g.get(t);return null==e&&(e={font:f(t),glyphs:new Map},g.set(t,e)),e.font}n.font_metrics=d,n.glyph_metrics=function(t,e){let n=g.get(e);null==n&&(d(e),n=g.get(e));let r=n.glyphs.get(t);return null==r&&(r=h(t,e),n.glyphs.set(t,r)),r},n.parse_css_font_size=function(t){const e=t.match(/^\\s*(\\d+(\\.\\d+)?)(\\w+)\\s*$/);if(null!=e){const[,t,,n]=e,r=Number(t);if(isFinite(r))return{value:r,unit:n}}return null}},\n function _(t,s,r,n,i){n();const{sin:e,cos:a}=Math;class h{constructor(t=1,s=0,r=0,n=1,i=0,e=0){this.a=t,this.b=s,this.c=r,this.d=n,this.e=i,this.f=e}toString(){const{a:t,b:s,c:r,d:n,e:i,f:e}=this;return`matrix(${t}, ${s}, ${r}, ${n}, ${i}, ${e})`}static from_DOMMatrix(t){const{a:s,b:r,c:n,d:i,e,f:a}=t;return new h(s,r,n,i,e,a)}to_DOMMatrix(){const{a:t,b:s,c:r,d:n,e:i,f:e}=this;return new DOMMatrix([t,s,r,n,i,e])}clone(){const{a:t,b:s,c:r,d:n,e:i,f:e}=this;return new h(t,s,r,n,i,e)}get is_identity(){const{a:t,b:s,c:r,d:n,e:i,f:e}=this;return 1==t&&0==s&&0==r&&1==n&&0==i&&0==e}apply_point(t){const[s,r]=this.apply(t.x,t.y);return{x:s,y:r}}apply_rect(t){return{p0:this.apply_point(t.p0),p1:this.apply_point(t.p1),p2:this.apply_point(t.p2),p3:this.apply_point(t.p3)}}apply(t,s){const{a:r,b:n,c:i,d:e,e:a,f:h}=this;return[r*t+i*s+a,n*t+e*s+h]}iv_apply(t,s){const{a:r,b:n,c:i,d:e,e:a,f:h}=this,c=t.length;for(let o=0;o{const h={max:4,fit:3,min:2,fixed:1};return h[i]>h[t]};if(\"fixed\"!=n&&\"fixed\"!=s)if(n==s){const n=t,s=_(t/e),r=_(h*e),g=h;Math.abs(i.width-n)+Math.abs(i.height-s)<=Math.abs(i.width-r)+Math.abs(i.height-g)?(t=n,h=s):(t=r,h=g)}else r(n,s)?h=_(t/e):t=_(h*e);else\"fixed\"==n?h=_(t/e):\"fixed\"==s&&(t=_(h*e))}return{width:t,height:h}}measure(i){if(!this.sizing.visible)return{width:0,height:0};const t=i=>\"fixed\"==this.sizing.width_policy&&null!=this.sizing.width?this.sizing.width:i,h=i=>\"fixed\"==this.sizing.height_policy&&null!=this.sizing.height?this.sizing.height:i,e=new s.Sizeable(i).shrink_by(this.sizing.margin).map(t,h),n=this._measure(e),r=this.clip_size(n,e),g=t(r.width),l=h(r.height),a=this.apply_aspect(e,{width:g,height:l});return Object.assign(Object.assign({},n),a)}compute(i={}){const t=this.measure({width:null!=i.width&&this.is_width_expanding()?i.width:1/0,height:null!=i.height&&this.is_height_expanding()?i.height:1/0}),{width:h,height:e}=t,n=new r.BBox({left:0,top:0,width:h,height:e});let s;if(null!=t.inner){const{left:i,top:n,right:g,bottom:l}=t.inner;s=new r.BBox({left:i,top:n,right:h-g,bottom:e-l})}this.set_geometry(n,s)}get xview(){return this.bbox.xview}get yview(){return this.bbox.yview}clip_size(i,t){function h(i,t,h,e){return null==h?h=0:(0,g.isNumber)(h)||(h=Math.round(h.percent*t)),null==e?e=1/0:(0,g.isNumber)(e)||(e=Math.round(e.percent*t)),a(h,l(i,e))}return{width:h(i.width,t.width,this.sizing.min_width,this.sizing.max_width),height:h(i.height,t.height,this.sizing.min_height,this.sizing.max_height)}}has_size_changed(){const{_dirty:i}=this;return this._dirty=!1,i}}h.Layoutable=o,o.__name__=\"Layoutable\";class d extends o{_measure(i){const{width_policy:t,height_policy:h}=this.sizing;return{width:(()=>{const{width:h}=this.sizing;if(i.width==1/0)return null!=h?h:0;switch(t){case\"fixed\":return null!=h?h:0;case\"min\":return null!=h?l(i.width,h):0;case\"fit\":return null!=h?l(i.width,h):i.width;case\"max\":return null!=h?a(i.width,h):i.width}})(),height:(()=>{const{height:t}=this.sizing;if(i.height==1/0)return null!=t?t:0;switch(h){case\"fixed\":return null!=t?t:0;case\"min\":return null!=t?l(i.height,t):0;case\"fit\":return null!=t?l(i.height,t):i.height;case\"max\":return null!=t?a(i.height,t):i.height}})()}}}h.LayoutItem=d,d.__name__=\"LayoutItem\";class u extends o{_measure(i){const t=this._content_size(),h=i.bounded_to(this.sizing.size).bounded_to(t);return{width:(()=>{switch(this.sizing.width_policy){case\"fixed\":return null!=this.sizing.width?this.sizing.width:t.width;case\"min\":return t.width;case\"fit\":return h.width;case\"max\":return Math.max(t.width,h.width)}})(),height:(()=>{switch(this.sizing.height_policy){case\"fixed\":return null!=this.sizing.height?this.sizing.height:t.height;case\"min\":return t.height;case\"fit\":return h.height;case\"max\":return Math.max(t.height,h.height)}})()}}}h.ContentLayoutable=u,u.__name__=\"ContentLayoutable\"},\n function _(e,t,s,a,_){a();const r=e(62),n=e(61),g=e(58),i=e(63),c=e(67),h=e(65),l=e(13),o=e(11);class x{constructor(e,t,s,a,_={},r={},n={},g={}){this.in_x_scale=e,this.in_y_scale=t,this.x_range=s,this.y_range=a,this.extra_x_ranges=_,this.extra_y_ranges=r,this.extra_x_scales=n,this.extra_y_scales=g,this._bbox=new h.BBox,(0,o.assert)(null==e.source_range&&null==e.target_range),(0,o.assert)(null==t.source_range&&null==t.target_range),this._configure_scales()}get bbox(){return this._bbox}_get_ranges(e,t){return new Map((0,l.entries)(Object.assign(Object.assign({},t),{default:e})))}_get_scales(e,t,s,a){var _;const g=new Map((0,l.entries)(Object.assign(Object.assign({},t),{default:e}))),h=new Map;for(const[t,l]of s){if(l instanceof c.FactorRange!=e instanceof r.CategoricalScale)throw new Error(`Range ${l.type} is incompatible is Scale ${e.type}`);e instanceof n.LogScale&&l instanceof i.DataRange1d&&(l.scale_hint=\"log\");const s=(null!==(_=g.get(t))&&void 0!==_?_:e).clone();s.setv({source_range:l,target_range:a}),h.set(t,s)}return h}_configure_frame_ranges(){const{bbox:e}=this;this._x_target=new g.Range1d({start:e.left,end:e.right}),this._y_target=new g.Range1d({start:e.bottom,end:e.top})}_configure_scales(){this._configure_frame_ranges(),this._x_ranges=this._get_ranges(this.x_range,this.extra_x_ranges),this._y_ranges=this._get_ranges(this.y_range,this.extra_y_ranges),this._x_scales=this._get_scales(this.in_x_scale,this.extra_x_scales,this._x_ranges,this._x_target),this._y_scales=this._get_scales(this.in_y_scale,this.extra_y_scales,this._y_ranges,this._y_target)}_update_scales(){this._configure_frame_ranges();for(const[,e]of this._x_scales)e.target_range=this._x_target;for(const[,e]of this._y_scales)e.target_range=this._y_target}set_geometry(e){this._bbox=e,this._update_scales()}get x_target(){return this._x_target}get y_target(){return this._y_target}get x_ranges(){return this._x_ranges}get y_ranges(){return this._y_ranges}get x_scales(){return this._x_scales}get y_scales(){return this._y_scales}get x_scale(){return this._x_scales.get(\"default\")}get y_scale(){return this._y_scales.get(\"default\")}get xscales(){return(0,l.to_object)(this.x_scales)}get yscales(){return(0,l.to_object)(this.y_scales)}}s.CartesianFrame=x,x.__name__=\"CartesianFrame\"},\n function _(i,s,x,A,o){A(),o(\"Axis\",i(128).Axis),o(\"CategoricalAxis\",i(140).CategoricalAxis),o(\"ContinuousAxis\",i(143).ContinuousAxis),o(\"DatetimeAxis\",i(144).DatetimeAxis),o(\"LinearAxis\",i(145).LinearAxis),o(\"LogAxis\",i(162).LogAxis),o(\"MercatorAxis\",i(165).MercatorAxis)},\n function _(t,e,i,s,a){s();const o=t(1);var l;const n=t(129),_=t(130),r=t(131),h=t(132),c=(0,o.__importStar)(t(48)),b=t(20),u=t(24),m=t(123),d=t(9),x=t(13),f=t(8),g=t(120),p=t(67),v=t(133),w=t(113),j=t(11),k=t(8),y=t(134),{abs:z}=Math;class M extends n.GuideRendererView{constructor(){super(...arguments),this._axis_label_view=null,this._major_label_views=new Map}async lazy_initialize(){await super.lazy_initialize(),await this._init_axis_label(),await this._init_major_labels()}async _init_axis_label(){const{axis_label:t}=this.model;if(null!=t){const e=(0,k.isString)(t)?(0,y.parse_delimited_string)(t):t;this._axis_label_view=await(0,w.build_view)(e,{parent:this})}else this._axis_label_view=null}async _init_major_labels(){const{major_label_overrides:t}=this.model;for(const[e,i]of(0,x.entries)(t)){const t=(0,k.isString)(i)?(0,y.parse_delimited_string)(i):i;this._major_label_views.set(e,await(0,w.build_view)(t,{parent:this}))}}update_layout(){this.layout=new m.SideLayout(this.panel,(()=>this.get_size()),!0),this.layout.on_resize((()=>this._coordinates=void 0))}get_size(){const{visible:t,fixed_location:e}=this.model;if(t&&null==e&&this.is_renderable){const{extents:t}=this;return{width:0,height:Math.round(t.tick+t.tick_label+t.axis_label)}}return{width:0,height:0}}get is_renderable(){const[t,e]=this.ranges;return t.is_valid&&e.is_valid}_render(){var t;if(!this.is_renderable)return;const{tick_coords:e,extents:i}=this,s=this.layer.ctx;s.save(),this._draw_rule(s,i),this._draw_major_ticks(s,i,e),this._draw_minor_ticks(s,i,e),this._draw_major_labels(s,i,e),this._draw_axis_label(s,i,e),null===(t=this._paint)||void 0===t||t.call(this,s,i,e),s.restore()}connect_signals(){super.connect_signals();const{axis_label:t,major_label_overrides:e}=this.model.properties;this.on_change(t,(async()=>{var t;null===(t=this._axis_label_view)||void 0===t||t.remove(),await this._init_axis_label()})),this.on_change(e,(async()=>{for(const t of this._major_label_views.values())t.remove();await this._init_major_labels()})),this.connect(this.model.change,(()=>this.plot_view.request_layout()))}get needs_clip(){return null!=this.model.fixed_location}_draw_rule(t,e){if(!this.visuals.axis_line.doit)return;const[i,s]=this.rule_coords,[a,o]=this.coordinates.map_to_screen(i,s),[l,n]=this.normals,[_,r]=this.offsets;this.visuals.axis_line.set_value(t),t.beginPath();for(let e=0;e0?s+i+3:0}_draw_axis_label(t,e,i){if(null==this._axis_label_view||null!=this.model.fixed_location)return;const[s,a]=(()=>{const{bbox:t}=this.layout;switch(this.panel.side){case\"above\":return[t.hcenter,t.bottom];case\"below\":return[t.hcenter,t.top];case\"left\":return[t.right,t.vcenter];case\"right\":return[t.left,t.vcenter]}})(),[o,l]=this.normals,n=e.tick+e.tick_label+this.model.axis_label_standoff,{vertical_align:_,align:r}=this.panel.get_label_text_heuristics(\"parallel\"),h={sx:s+o*n,sy:a+l*n,x_anchor:r,y_anchor:_},c=this._axis_label_view.graphics();c.visuals=this.visuals.axis_label_text.values(),c.angle=this.panel.get_label_angle_heuristic(\"parallel\"),this.plot_view.base_font_size&&(c.base_font_size=this.plot_view.base_font_size),c.position=h,c.align=r,c.paint(t)}_draw_ticks(t,e,i,s,a){if(!a.doit)return;const[o,l]=e,[n,_]=this.coordinates.map_to_screen(o,l),[r,h]=this.normals,[c,b]=this.offsets,[u,m]=[r*(c-i),h*(b-i)],[d,x]=[r*(c+s),h*(b+s)];a.set_value(t),t.beginPath();for(let e=0;et.bbox())),M=(()=>{const[t]=this.ranges;return t.is_reversed?0==this.dimension?(t,e)=>z[t].left-z[e].right:(t,e)=>z[e].top-z[t].bottom:0==this.dimension?(t,e)=>z[e].left-z[t].right:(t,e)=>z[t].top-z[e].bottom})(),{major_label_policy:O}=this.model,T=O.filter(k,z,M),A=[...T.ones()];if(0!=A.length){const t=this.parent.canvas_view.bbox,e=e=>{const i=z[e];if(i.left<0){const t=-i.left,{position:s}=y[e];y[e].position=Object.assign(Object.assign({},s),{sx:s.sx+t})}else if(i.right>t.width){const s=i.right-t.width,{position:a}=y[e];y[e].position=Object.assign(Object.assign({},a),{sx:a.sx-s})}},i=e=>{const i=z[e];if(i.top<0){const t=-i.top,{position:s}=y[e];y[e].position=Object.assign(Object.assign({},s),{sy:s.sy+t})}else if(i.bottom>t.height){const s=i.bottom-t.height,{position:a}=y[e];y[e].position=Object.assign(Object.assign({},a),{sy:a.sy-s})}},s=A[0],a=A[A.length-1];0==this.dimension?(e(s),e(a)):(i(s),i(a))}for(const e of T){y[e].paint(t)}}_tick_extent(){return this.model.major_tick_out}_tick_label_extents(){const t=this.tick_coords.major,e=this.compute_labels(t[this.dimension]),i=this.model.major_label_orientation,s=this.model.major_label_standoff,a=this.visuals.major_label_text;return[this._oriented_labels_extent(e,i,s,a)]}get extents(){const t=this._tick_label_extents();return{tick:this._tick_extent(),tick_labels:t,tick_label:(0,d.sum)(t),axis_label:this._axis_label_extent()}}_oriented_labels_extent(t,e,i,s){if(0==t.length||!s.doit)return 0;const a=this.panel.get_label_angle_heuristic(e);t.visuals=s.values(),t.angle=a,t.base_font_size=this.plot_view.base_font_size;const o=t.max_size(),l=0==this.dimension?o.height:o.width;return l>0?i+l+3:0}get normals(){return this.panel.normals}get dimension(){return this.panel.dimension}compute_labels(t){const e=this.model.formatter.format_graphics(t,this),{_major_label_views:i}=this,s=new Set;for(let a=0;az(l-n)?(t=r(_(a,o),l),s=_(r(a,o),n)):(t=_(a,o),s=r(a,o)),[t,s]}}get rule_coords(){const t=this.dimension,e=(t+1)%2,[i]=this.ranges,[s,a]=this.computed_bounds,o=[new Array(2),new Array(2)];return o[t][0]=Math.max(s,i.min),o[t][1]=Math.min(a,i.max),o[t][0]>o[t][1]&&(o[t][0]=o[t][1]=NaN),o[e][0]=this.loc,o[e][1]=this.loc,o}get tick_coords(){const t=this.dimension,e=(t+1)%2,[i]=this.ranges,[s,a]=this.computed_bounds,o=this.model.ticker.get_ticks(s,a,i,this.loc),l=o.major,n=o.minor,_=[[],[]],r=[[],[]],[h,c]=[i.min,i.max];for(let i=0;ic||(_[t].push(l[i]),_[e].push(this.loc));for(let i=0;ic||(r[t].push(n[i]),r[e].push(this.loc));return{major:_,minor:r}}get loc(){const{fixed_location:t}=this.model;if(null!=t){if((0,f.isNumber)(t))return t;const[,e]=this.ranges;if(e instanceof p.FactorRange)return e.synthetic(t);(0,j.unreachable)()}const[,e]=this.ranges;switch(this.panel.side){case\"left\":case\"below\":return e.start;case\"right\":case\"above\":return e.end}}serializable_state(){return Object.assign(Object.assign({},super.serializable_state()),{bbox:this.layout.bbox.box})}remove(){var t;null===(t=this._axis_label_view)||void 0===t||t.remove();for(const t of this._major_label_views.values())t.remove();super.remove()}has_finished(){if(!super.has_finished())return!1;if(null!=this._axis_label_view&&!this._axis_label_view.has_finished())return!1;for(const t of this._major_label_views.values())if(!t.has_finished())return!1;return!0}}i.AxisView=M,M.__name__=\"AxisView\";class O extends n.GuideRenderer{constructor(t){super(t)}}i.Axis=O,l=O,O.__name__=\"Axis\",l.prototype.default_view=M,l.mixins([[\"axis_\",c.Line],[\"major_tick_\",c.Line],[\"minor_tick_\",c.Line],[\"major_label_\",c.Text],[\"axis_label_\",c.Text]]),l.define((({Any:t,Int:e,Number:i,String:s,Ref:a,Dict:o,Tuple:l,Or:n,Nullable:c,Auto:u})=>({bounds:[n(l(i,i),u),\"auto\"],ticker:[a(_.Ticker)],formatter:[a(r.TickFormatter)],axis_label:[c(n(s,a(v.BaseText))),null],axis_label_standoff:[e,5],major_label_standoff:[e,5],major_label_orientation:[n(b.TickLabelOrientation,i),\"horizontal\"],major_label_overrides:[o(n(s,a(v.BaseText))),{}],major_label_policy:[a(h.LabelingPolicy),()=>new h.AllLabels],major_tick_in:[i,2],major_tick_out:[i,6],minor_tick_in:[i,0],minor_tick_out:[i,4],fixed_location:[c(n(i,t)),null]}))),l.override({axis_line_color:\"black\",major_tick_line_color:\"black\",minor_tick_line_color:\"black\",major_label_text_font_size:\"11px\",major_label_text_align:\"center\",major_label_text_baseline:\"alphabetic\",axis_label_text_font_size:\"13px\",axis_label_text_font_style:\"italic\"})},\n function _(e,r,d,n,i){var s;n();const _=e(41);class u extends _.RendererView{}d.GuideRendererView=u,u.__name__=\"GuideRendererView\";class c extends _.Renderer{constructor(e){super(e)}}d.GuideRenderer=c,s=c,c.__name__=\"GuideRenderer\",s.override({level:\"guide\"})},\n function _(c,e,n,s,o){s();const r=c(53);class t extends r.Model{constructor(c){super(c)}}n.Ticker=t,t.__name__=\"Ticker\"},\n function _(t,o,r,e,c){e();const n=t(53),a=t(120);class m extends n.Model{constructor(t){super(t)}format_graphics(t,o){return this.doFormat(t,o).map((t=>new a.TextBox({text:t})))}compute(t,o){return this.doFormat([t],null!=o?o:{loc:0})[0]}v_compute(t,o){return this.doFormat(t,null!=o?o:{loc:0})}}r.TickFormatter=m,m.__name__=\"TickFormatter\"},\n function _(e,n,s,t,i){var c,r;t();const l=e(53),o=e(13),a=e(34),u=e(8),d=e(24);class _ extends l.Model{constructor(e){super(e)}}s.LabelingPolicy=_,_.__name__=\"LabelingPolicy\";class f extends _{constructor(e){super(e)}filter(e,n,s){return e}}s.AllLabels=f,f.__name__=\"AllLabels\";class m extends _{constructor(e){super(e)}filter(e,n,s){const{min_distance:t}=this;let i=null;for(const n of e)null!=i&&s(i,n)({min_distance:[e,5]})));class b extends _{constructor(e){super(e)}get names(){return(0,o.keys)(this.args)}get values(){return(0,o.values)(this.args)}get func(){const e=(0,a.use_strict)(this.code);return new d.GeneratorFunction(\"indices\",\"bboxes\",\"distance\",...this.names,e)}filter(e,n,s){const t=Object.create(null),i=this.func.call(t,e,n,s,...this.values);let c=i.next();if(c.done&&void 0!==c.value){const{value:n}=c;return n instanceof d.Indices?n:void 0===n?e:(0,u.isIterable)(n)?d.Indices.from_indices(e.size,n):d.Indices.all_unset(e.size)}{const n=[];do{n.push(c.value),c=i.next()}while(!c.done);return d.Indices.from_indices(e.size,n)}}}s.CustomLabelingPolicy=b,r=b,b.__name__=\"CustomLabelingPolicy\",r.define((({Unknown:e,String:n,Dict:s})=>({args:[s(e),{}],code:[n,\"\"]})))},\n function _(e,s,t,n,a){var _;n();const x=e(53),c=e(42);class i extends c.View{}t.BaseTextView=i,i.__name__=\"BaseTextView\";class o extends x.Model{constructor(e){super(e)}}t.BaseText=o,_=o,o.__name__=\"BaseText\",_.define((({String:e})=>({text:[e]})))},\n function _(n,e,t,i,r){i();const s=n(135),l=n(139),d=[{start:\"$$\",end:\"$$\",inline:!1},{start:\"\\\\[\",end:\"\\\\]\",inline:!1},{start:\"\\\\(\",end:\"\\\\)\",inline:!0}];t.parse_delimited_string=function(n){for(const e of d){const t=n.indexOf(e.start),i=t+e.start.length;if(0==t){const t=n.indexOf(e.end,i),r=t;if(t==n.length-e.end.length)return new s.TeX({text:n.slice(i,r),inline:e.inline});break}}return new l.PlainText({text:n})}},\n function _(t,e,s,i,n){var o,r,a;i();const h=t(8),_=t(136),l=t(22),c=t(120),d=t(121),u=t(122),g=t(65),p=t(133),x=t(137);class m extends p.BaseTextView{constructor(){super(...arguments),this._position={sx:0,sy:0},this.align=\"left\",this._x_anchor=\"left\",this._y_anchor=\"center\",this._base_font_size=13,this.font_size_scale=1,this.svg_image=null}graphics(){return this}infer_text_height(){return\"ascent_descent\"}set base_font_size(t){null!=t&&(this._base_font_size=t)}get base_font_size(){return this._base_font_size}get has_image_loaded(){return null!=this.svg_image}_rect(){const{width:t,height:e}=this._size(),{x:s,y:i}=this._computed_position();return new g.BBox({x:s,y:i,width:t,height:e}).rect}set position(t){this._position=t}get position(){return this._position}get text(){return this.model.text}get provider(){return x.default_provider}async lazy_initialize(){await super.lazy_initialize(),\"not_started\"==this.provider.status&&await this.provider.fetch(),\"not_started\"!=this.provider.status&&\"loading\"!=this.provider.status||this.provider.ready.connect((()=>this.load_image())),\"loaded\"==this.provider.status&&await this.load_image()}connect_signals(){super.connect_signals(),this.on_change(this.model.properties.text,(()=>this.load_image()))}set visuals(t){const e=t.color,s=t.alpha,i=t.font_style;let n=t.font_size;const o=t.font,{font_size_scale:r,_base_font_size:a}=this,h=(0,d.parse_css_font_size)(n);if(null!=h){let{value:t,unit:e}=h;t*=r,\"em\"==e&&a&&(t*=a,e=\"px\"),n=`${t}${e}`}const _=`${i} ${n} ${o}`;this.font=_,this.color=(0,l.color2css)(e,s)}_computed_position(){const{width:t,height:e}=this._size(),{sx:s,sy:i,x_anchor:n=this._x_anchor,y_anchor:o=this._y_anchor}=this.position;return{x:s-(()=>{if((0,h.isNumber)(n))return n*t;switch(n){case\"left\":return 0;case\"center\":return.5*t;case\"right\":return t}})(),y:i-(()=>{if((0,h.isNumber)(o))return o*e;switch(o){case\"top\":return 0;case\"center\":return.5*e;case\"bottom\":return e;case\"baseline\":return.5*e}})()}}size(){const{width:t,height:e}=this._size(),{angle:s}=this;if(s){const i=Math.cos(Math.abs(s)),n=Math.sin(Math.abs(s));return{width:Math.abs(t*i+e*n),height:Math.abs(t*n+e*i)}}return{width:t,height:e}}get_text_dimensions(){return{width:(0,c.text_width)(this.model.text,this.font),height:(0,d.font_metrics)(this.font).height}}get_image_dimensions(){var t,e,s,i;const n=parseFloat(null!==(e=null===(t=this.svg_element.getAttribute(\"height\"))||void 0===t?void 0:t.replace(/([A-z])/g,\"\"))&&void 0!==e?e:\"0\"),o=parseFloat(null!==(i=null===(s=this.svg_element.getAttribute(\"width\"))||void 0===s?void 0:s.replace(/([A-z])/g,\"\"))&&void 0!==i?i:\"0\");return{width:(0,d.font_metrics)(this.font).x_height*o,height:(0,d.font_metrics)(this.font).x_height*n}}_size(){return this.has_image_loaded?this.get_image_dimensions():this.get_text_dimensions()}bbox(){const{p0:t,p1:e,p2:s,p3:i}=this.rect(),n=Math.min(t.x,e.x,s.x,i.x),o=Math.min(t.y,e.y,s.y,i.y),r=Math.max(t.x,e.x,s.x,i.x),a=Math.max(t.y,e.y,s.y,i.y);return new g.BBox({left:n,right:r,top:o,bottom:a})}rect(){const t=this._rect(),{angle:e}=this;if(e){const{sx:s,sy:i}=this.position,n=new u.AffineTransform;return n.translate(s,i),n.rotate(e),n.translate(-s,-i),n.apply_rect(t)}return t}paint_rect(t){const{p0:e,p1:s,p2:i,p3:n}=this.rect();t.save(),t.strokeStyle=\"red\",t.lineWidth=1,t.beginPath();const{round:o}=Math;t.moveTo(o(e.x),o(e.y)),t.lineTo(o(s.x),o(s.y)),t.lineTo(o(i.x),o(i.y)),t.lineTo(o(n.x),o(n.y)),t.closePath(),t.stroke(),t.restore()}paint_bbox(t){const{x:e,y:s,width:i,height:n}=this.bbox();t.save(),t.strokeStyle=\"blue\",t.lineWidth=1,t.beginPath();const{round:o}=Math;t.moveTo(o(e),o(s)),t.lineTo(o(e),o(s+n)),t.lineTo(o(e+i),o(s+n)),t.lineTo(o(e+i),o(s)),t.closePath(),t.stroke(),t.restore()}async load_image(){if(null==this.provider.MathJax)return null;const t=this._process_text(this.model.text);if(null==t)return this._has_finished=!0,null;const e=t.children[0];this.svg_element=e,e.setAttribute(\"font\",this.font),e.setAttribute(\"stroke\",this.color);const s=e.outerHTML,i=new Blob([s],{type:\"image/svg+xml\"}),n=URL.createObjectURL(i);try{this.svg_image=await(0,_.load_image)(n)}finally{URL.revokeObjectURL(n)}return this.parent.request_layout(),this.svg_image}paint(t){t.save();const{sx:e,sy:s}=this.position;this.angle&&(t.translate(e,s),t.rotate(this.angle),t.translate(-e,-s));const{x:i,y:n}=this._computed_position();if(null!=this.svg_image){const{width:e,height:s}=this.get_image_dimensions();t.drawImage(this.svg_image,i,n,e,s)}else t.fillStyle=this.color,t.font=this.font,t.textAlign=\"left\",t.textBaseline=\"alphabetic\",t.fillText(this.model.text,i,n+(0,d.font_metrics)(this.font).ascent);t.restore(),this._has_finished||\"failed\"!=this.provider.status&&!this.has_image_loaded||(this._has_finished=!0,this.parent.notify_finished_after_paint())}}s.MathTextView=m,m.__name__=\"MathTextView\";class f extends p.BaseText{constructor(t){super(t)}}s.MathText=f,f.__name__=\"MathText\";class v extends m{_process_text(t){}}s.AsciiView=v,v.__name__=\"AsciiView\";class y extends f{constructor(t){super(t)}}s.Ascii=y,o=y,y.__name__=\"Ascii\",o.prototype.default_view=v;class w extends m{_process_text(t){var e;return null===(e=this.provider.MathJax)||void 0===e?void 0:e.mathml2svg(t.trim())}}s.MathMLView=w,w.__name__=\"MathMLView\";class b extends f{constructor(t){super(t)}}s.MathML=b,r=b,b.__name__=\"MathML\",r.prototype.default_view=w;class M extends m{_process_text(t){var e;return null===(e=this.provider.MathJax)||void 0===e?void 0:e.tex2svg(t,void 0,this.model.macros)}}s.TeXView=M,M.__name__=\"TeXView\";class T extends f{constructor(t){super(t)}}s.TeX=T,a=T,T.__name__=\"TeX\",a.prototype.default_view=M,a.define((({Boolean:t,Number:e,String:s,Dict:i,Tuple:n,Or:o})=>({macros:[i(o(s,n(s,e))),{}],inline:[t,!1]})))},\n function _(i,e,t,s,o){s();const a=i(19);t.load_image=async function(i,e){return new n(i,e).promise};class n{constructor(i,e={}){this._image=new Image,this._finished=!1;const{attempts:t=1,timeout:s=1}=e;this.promise=new Promise(((o,n)=>{this._image.crossOrigin=\"anonymous\";let r=0;this._image.onerror=()=>{if(++r==t){const s=`unable to load ${i} image after ${t} attempts`;if(a.logger.warn(s),null==this._image.crossOrigin)return void(null!=e.failed&&e.failed());a.logger.warn(`attempting to load ${i} without a cross origin policy`),this._image.crossOrigin=null,r=0}setTimeout((()=>this._image.src=i),s)},this._image.onload=()=>{this._finished=!0,null!=e.loaded&&e.loaded(this._image),o(this._image)},this._image.src=i}))}get finished(){return this._finished}get image(){if(this._finished)return this._image;throw new Error(\"not loaded yet\")}}t.ImageLoader=n,n.__name__=\"ImageLoader\"},\n function _(t,e,a,s,n){var r=this&&this.__createBinding||(Object.create?function(t,e,a,s){void 0===s&&(s=a),Object.defineProperty(t,s,{enumerable:!0,get:function(){return e[a]}})}:function(t,e,a,s){void 0===s&&(s=a),t[s]=e[a]}),i=this&&this.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,\"default\",{enumerable:!0,value:e})}:function(t,e){t.default=e}),d=this&&this.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var a in t)\"default\"!==a&&Object.prototype.hasOwnProperty.call(t,a)&&r(e,t,a);return i(e,t),e};s();const o=t(15),u=t(138);class c{constructor(){this.ready=new o.Signal0(this,\"ready\"),this.status=\"not_started\"}}a.MathJaxProvider=c,c.__name__=\"MathJaxProvider\";class h extends c{get MathJax(){return null}async fetch(){this.status=\"failed\"}}a.NoProvider=h,h.__name__=\"NoProvider\";class l extends c{get MathJax(){return\"undefined\"!=typeof MathJax?MathJax:null}async fetch(){const t=document.createElement(\"script\");t.src=\"https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js\",t.onload=()=>{this.status=\"loaded\",this.ready.emit()},t.onerror=()=>{this.status=\"failed\"},this.status=\"loading\",document.head.appendChild(t)}}a.CDNProvider=l,l.__name__=\"CDNProvider\";class _ extends c{get MathJax(){return this._mathjax}async fetch(){this.status=\"loading\";try{const e=await(0,u.load_module)(Promise.resolve().then((()=>d(t(519)))));this._mathjax=e,this.status=\"loaded\",this.ready.emit()}catch(t){this.status=\"failed\"}}}a.BundleProvider=_,_.__name__=\"BundleProvider\",a.default_provider=new _},\n function _(n,r,o,t,c){t(),o.load_module=async function(n){try{return await n}catch(n){if((r=n)instanceof Error&&\"code\"in r&&\"MODULE_NOT_FOUND\"===n.code)return null;throw n}var r}},\n function _(e,t,i,n,s){var a;n();const x=e(133),_=e(120);class l extends x.BaseTextView{initialize(){super.initialize(),this._has_finished=!0}graphics(){return new _.TextBox({text:this.model.text})}}i.PlainTextView=l,l.__name__=\"PlainTextView\";class r extends x.BaseText{constructor(e){super(e)}}i.PlainText=r,a=r,r.__name__=\"PlainText\",a.prototype.default_view=l},\n function _(t,s,o,e,i){e();const r=t(1);var a;const l=t(128),_=t(141),n=t(142),p=(0,r.__importStar)(t(48)),c=t(20),h=t(120),m=t(8);class u extends l.AxisView{_paint(t,s,o){this._draw_group_separators(t,s,o)}_draw_group_separators(t,s,o){const[e]=this.ranges,[i,r]=this.computed_bounds;if(!e.tops||e.tops.length<2||!this.visuals.separator_line.doit)return;const a=this.dimension,l=(a+1)%2,_=[[],[]];let n=0;for(let t=0;ti&&pnew h.GraphicsBoxes(t.map((t=>(0,m.isString)(t)?new h.TextBox({text:t}):t))),_=t=>l(this.model.formatter.doFormat(t,this));if(1==t.levels){const t=_(i.major);a.push([t,r.major,this.model.major_label_orientation,this.visuals.major_label_text])}else if(2==t.levels){const t=_(i.major.map((t=>t[1])));a.push([t,r.major,this.model.major_label_orientation,this.visuals.major_label_text]),a.push([l(i.tops),r.tops,this.model.group_label_orientation,this.visuals.group_text])}else if(3==t.levels){const t=_(i.major.map((t=>t[2]))),s=i.mids.map((t=>t[1]));a.push([t,r.major,this.model.major_label_orientation,this.visuals.major_label_text]),a.push([l(s),r.mids,this.model.subgroup_label_orientation,this.visuals.subgroup_text]),a.push([l(i.tops),r.tops,this.model.group_label_orientation,this.visuals.group_text])}return a}get tick_coords(){const t=this.dimension,s=(t+1)%2,[o]=this.ranges,[e,i]=this.computed_bounds,r=this.model.ticker.get_ticks(e,i,o,this.loc),a={major:[[],[]],mids:[[],[]],tops:[[],[]],minor:[[],[]]};return a.major[t]=r.major,a.major[s]=r.major.map((()=>this.loc)),3==o.levels&&(a.mids[t]=r.mids,a.mids[s]=r.mids.map((()=>this.loc))),o.levels>1&&(a.tops[t]=r.tops,a.tops[s]=r.tops.map((()=>this.loc))),a}}o.CategoricalAxisView=u,u.__name__=\"CategoricalAxisView\";class d extends l.Axis{constructor(t){super(t)}}o.CategoricalAxis=d,a=d,d.__name__=\"CategoricalAxis\",a.prototype.default_view=u,a.mixins([[\"separator_\",p.Line],[\"group_\",p.Text],[\"subgroup_\",p.Text]]),a.define((({Number:t,Or:s})=>({group_label_orientation:[s(c.TickLabelOrientation,t),\"parallel\"],subgroup_label_orientation:[s(c.TickLabelOrientation,t),\"parallel\"]}))),a.override({ticker:()=>new _.CategoricalTicker,formatter:()=>new n.CategoricalTickFormatter,separator_line_color:\"lightgrey\",separator_line_width:2,group_text_font_style:\"bold\",group_text_font_size:\"11px\",group_text_color:\"grey\",subgroup_text_font_style:\"bold\",subgroup_text_font_size:\"11px\"})},\n function _(t,c,o,s,e){s();const r=t(130);class i extends r.Ticker{constructor(t){super(t)}get_ticks(t,c,o,s){var e,r;return{major:this._collect(o.factors,o,t,c),minor:[],tops:this._collect(null!==(e=o.tops)&&void 0!==e?e:[],o,t,c),mids:this._collect(null!==(r=o.mids)&&void 0!==r?r:[],o,t,c)}}_collect(t,c,o,s){const e=[];for(const r of t){const t=c.synthetic(r);t>o&&tnew _.DatetimeTicker,formatter:()=>new m.DatetimeTickFormatter})},\n function _(e,i,s,n,r){var t;n();const a=e(143),o=e(146),c=e(147);class _ extends a.ContinuousAxisView{}s.LinearAxisView=_,_.__name__=\"LinearAxisView\";class u extends a.ContinuousAxis{constructor(e){super(e)}}s.LinearAxis=u,t=u,u.__name__=\"LinearAxis\",t.prototype.default_view=_,t.override({ticker:()=>new c.BasicTicker,formatter:()=>new o.BasicTickFormatter})},\n function _(i,t,e,n,o){var r;n();const s=i(131),c=i(34);function _(i){let t=\"\";for(const e of i)t+=\"-\"==e?\"\\u2212\":e;return t}e.unicode_replace=_;class a extends s.TickFormatter{constructor(i){super(i),this.last_precision=3}get scientific_limit_low(){return 10**this.power_limit_low}get scientific_limit_high(){return 10**this.power_limit_high}_need_sci(i){if(!this.use_scientific)return!1;const{scientific_limit_high:t}=this,{scientific_limit_low:e}=this,n=i.length<2?0:Math.abs(i[1]-i[0])/1e4;for(const o of i){const i=Math.abs(o);if(!(i<=n)&&(i>=t||i<=e))return!0}return!1}_format_with_precision(i,t,e){return t?i.map((i=>_(i.toExponential(e)))):i.map((i=>_((0,c.to_fixed)(i,e))))}_auto_precision(i,t){const e=new Array(i.length),n=this.last_precision<=15;i:for(let o=this.last_precision;n?o<=15:o>=1;n?o++:o--){if(t){e[0]=i[0].toExponential(o);for(let t=1;t({precision:[n(t,e),\"auto\"],use_scientific:[i,!0],power_limit_high:[t,5],power_limit_low:[t,-3]})))},\n function _(c,e,s,i,n){i();const r=c(148);class t extends r.AdaptiveTicker{constructor(c){super(c)}}s.BasicTicker=t,t.__name__=\"BasicTicker\"},\n function _(t,i,a,s,e){var n;s();const r=t(149),_=t(9),l=t(10);class h extends r.ContinuousTicker{constructor(t){super(t)}get_min_interval(){return this.min_interval}get_max_interval(){var t;return null!==(t=this.max_interval)&&void 0!==t?t:1/0}initialize(){super.initialize();const t=(0,_.nth)(this.mantissas,-1)/this.base,i=(0,_.nth)(this.mantissas,0)*this.base;this.extended_mantissas=[t,...this.mantissas,i],this.base_factor=0===this.get_min_interval()?1:this.get_min_interval()}get_interval(t,i,a){const s=i-t,e=this.get_ideal_interval(t,i,a),n=Math.floor((0,l.log)(e/this.base_factor,this.base)),r=this.base**n*this.base_factor,h=this.extended_mantissas,m=h.map((t=>Math.abs(a-s/(t*r)))),v=h[(0,_.argmin)(m)]*r;return(0,l.clamp)(v,this.get_min_interval(),this.get_max_interval())}}a.AdaptiveTicker=h,n=h,h.__name__=\"AdaptiveTicker\",n.define((({Number:t,Array:i,Nullable:a})=>({base:[t,10],mantissas:[i(t),[1,2,5]],min_interval:[t,0],max_interval:[a(t),null]})))},\n function _(t,n,i,s,e){var o;s();const r=t(130),c=t(9);class _ extends r.Ticker{constructor(t){super(t)}get_ticks(t,n,i,s){return this.get_ticks_no_defaults(t,n,s,this.desired_num_ticks)}get_ticks_no_defaults(t,n,i,s){const e=this.get_interval(t,n,s),o=Math.floor(t/e),r=Math.ceil(n/e);let _;_=isFinite(o)&&isFinite(r)?(0,c.range)(o,r+1):[];const u=_.map((t=>t*e)).filter((i=>t<=i&&i<=n)),a=this.num_minor_ticks,f=[];if(a>0&&u.length>0){const i=e/a,s=(0,c.range)(0,a).map((t=>t*i));for(const i of s.slice(1)){const s=u[0]-i;t<=s&&s<=n&&f.push(s)}for(const i of u)for(const e of s){const s=i+e;t<=s&&s<=n&&f.push(s)}}return{major:u,minor:f}}get_ideal_interval(t,n,i){return(n-t)/i}}i.ContinuousTicker=_,o=_,_.__name__=\"ContinuousTicker\",o.define((({Int:t})=>({num_minor_ticks:[t,5],desired_num_ticks:[t,6]})))},\n function _(s,t,e,n,i){n();var r;const o=(0,s(1).__importDefault)(s(151)),a=s(131),c=s(19),u=s(152),m=s(9),h=s(8);function d(s){return(0,o.default)(s,\"%Y %m %d %H %M %S\").split(/\\s+/).map((s=>parseInt(s,10)))}function l(s,t){if((0,h.isFunction)(t))return t(s);{const e=(0,u.sprintf)(\"$1%06d\",function(s){return Math.round(s/1e3%1*1e6)}(s));return-1==(t=t.replace(/((^|[^%])(%%)*)%f/,e)).indexOf(\"%\")?t:(0,o.default)(s,t)}}const f=[\"microseconds\",\"milliseconds\",\"seconds\",\"minsec\",\"minutes\",\"hourmin\",\"hours\",\"days\",\"months\",\"years\"];class _ extends a.TickFormatter{constructor(s){super(s),this.strip_leading_zeros=!0}initialize(){super.initialize(),this._update_width_formats()}_update_width_formats(){const s=+(0,o.default)(new Date),t=function(t){const e=t.map((t=>l(s,t).length)),n=(0,m.sort_by)((0,m.zip)(e,t),(([s])=>s));return(0,m.unzip)(n)};this._width_formats={microseconds:t(this.microseconds),milliseconds:t(this.milliseconds),seconds:t(this.seconds),minsec:t(this.minsec),minutes:t(this.minutes),hourmin:t(this.hourmin),hours:t(this.hours),days:t(this.days),months:t(this.months),years:t(this.years)}}_get_resolution_str(s,t){const e=1.1*s;switch(!1){case!(e<.001):return\"microseconds\";case!(e<1):return\"milliseconds\";case!(e<60):return t>=60?\"minsec\":\"seconds\";case!(e<3600):return t>=3600?\"hourmin\":\"minutes\";case!(e<86400):return\"hours\";case!(e<2678400):return\"days\";case!(e<31536e3):return\"months\";default:return\"years\"}}doFormat(s,t){if(0==s.length)return[];const e=Math.abs(s[s.length-1]-s[0])/1e3,n=e/(s.length-1),i=this._get_resolution_str(n,e),[,[r]]=this._width_formats[i],o=[],a=f.indexOf(i),u={};for(const s of f)u[s]=0;u.seconds=5,u.minsec=4,u.minutes=4,u.hourmin=3,u.hours=3;for(const t of s){let s,e;try{e=d(t),s=l(t,r)}catch(s){c.logger.warn(`unable to format tick for timestamp value ${t}`),c.logger.warn(` - ${s}`),o.push(\"ERR\");continue}let n=!1,m=a;for(;0==e[u[f[m]]];){let r;if(m+=1,m==f.length)break;if((\"minsec\"==i||\"hourmin\"==i)&&!n){if(\"minsec\"==i&&0==e[4]&&0!=e[5]||\"hourmin\"==i&&0==e[3]&&0!=e[4]){r=this._width_formats[f[a-1]][1][0],s=l(t,r);break}n=!0}r=this._width_formats[f[m]][1][0],s=l(t,r)}if(this.strip_leading_zeros){let t=s.replace(/^0+/g,\"\");t!=s&&isNaN(parseInt(t))&&(t=`0${t}`),o.push(t)}else o.push(s)}return o}}e.DatetimeTickFormatter=_,r=_,_.__name__=\"DatetimeTickFormatter\",r.define((({String:s,Array:t})=>({microseconds:[t(s),[\"%fus\"]],milliseconds:[t(s),[\"%3Nms\",\"%S.%3Ns\"]],seconds:[t(s),[\"%Ss\"]],minsec:[t(s),[\":%M:%S\"]],minutes:[t(s),[\":%M\",\"%Mm\"]],hourmin:[t(s),[\"%H:%M\"]],hours:[t(s),[\"%Hh\",\"%H:%M\"]],days:[t(s),[\"%m/%d\",\"%a%d\"]],months:[t(s),[\"%m/%Y\",\"%b %Y\"]],years:[t(s),[\"%Y\"]]})))},\n function _(e,t,n,r,o){!function(e){\"object\"==typeof t&&t.exports?t.exports=e():\"function\"==typeof define?define(e):this.tz=e()}((function(){function e(e,t,n){var r,o=t.day[1];do{r=new Date(Date.UTC(n,t.month,Math.abs(o++)))}while(t.day[0]<7&&r.getUTCDay()!=t.day[0]);return(r={clock:t.clock,sort:r.getTime(),rule:t,save:6e4*t.save,offset:e.offset})[r.clock]=r.sort+6e4*t.time,r.posix?r.wallclock=r[r.clock]+(e.offset+t.saved):r.posix=r[r.clock]-(e.offset+t.saved),r}function t(t,n,r){var o,a,u,i,l,s,c,f=t[t.zone],h=[],T=new Date(r).getUTCFullYear(),g=1;for(o=1,a=f.length;o=T-g;--c)for(o=0,a=s.length;o=h[o][n]&&h[o][h[o].clock]>u[h[o].clock]&&(i=h[o])}return i&&((l=/^(.*)\\/(.*)$/.exec(u.format))?i.abbrev=l[i.save?2:1]:i.abbrev=u.format.replace(/%s/,i.rule.letter)),i||u}function n(e,n){return\"UTC\"==e.zone?n:(e.entry=t(e,\"posix\",n),n+e.entry.offset+e.entry.save)}function r(e,n){return\"UTC\"==e.zone?n:(e.entry=r=t(e,\"wallclock\",n),0<(o=n-r.wallclock)&&o9)t+=s*l[c-10];else{if(a=new Date(n(e,t)),c<7)for(;s;)a.setUTCDate(a.getUTCDate()+i),a.getUTCDay()==c&&(s-=i);else 7==c?a.setUTCFullYear(a.getUTCFullYear()+s):8==c?a.setUTCMonth(a.getUTCMonth()+s):a.setUTCDate(a.getUTCDate()+s);null==(t=r(e,a.getTime()))&&(t=r(e,a.getTime()+864e5*i)-864e5*i)}return t}var a={clock:function(){return+new Date},zone:\"UTC\",entry:{abbrev:\"UTC\",offset:0,save:0},UTC:1,z:function(e,t,n,r){var o,a,u=this.entry.offset+this.entry.save,i=Math.abs(u/1e3),l=[],s=3600;for(o=0;o<3;o++)l.push((\"0\"+Math.floor(i/s)).slice(-2)),i%=s,s/=60;return\"^\"!=n||u?(\"^\"==n&&(r=3),3==r?(a=(a=l.join(\":\")).replace(/:00$/,\"\"),\"^\"!=n&&(a=a.replace(/:00$/,\"\"))):r?(a=l.slice(0,r+1).join(\":\"),\"^\"==n&&(a=a.replace(/:00$/,\"\"))):a=l.slice(0,2).join(\"\"),a=(a=(u<0?\"-\":\"+\")+a).replace(/([-+])(0)/,{_:\" $1\",\"-\":\"$1\"}[n]||\"$1$2\")):\"Z\"},\"%\":function(e){return\"%\"},n:function(e){return\"\\n\"},t:function(e){return\"\\t\"},U:function(e){return s(e,0)},W:function(e){return s(e,1)},V:function(e){return c(e)[0]},G:function(e){return c(e)[1]},g:function(e){return c(e)[1]%100},j:function(e){return Math.floor((e.getTime()-Date.UTC(e.getUTCFullYear(),0))/864e5)+1},s:function(e){return Math.floor(e.getTime()/1e3)},C:function(e){return Math.floor(e.getUTCFullYear()/100)},N:function(e){return e.getTime()%1e3*1e6},m:function(e){return e.getUTCMonth()+1},Y:function(e){return e.getUTCFullYear()},y:function(e){return e.getUTCFullYear()%100},H:function(e){return e.getUTCHours()},M:function(e){return e.getUTCMinutes()},S:function(e){return e.getUTCSeconds()},e:function(e){return e.getUTCDate()},d:function(e){return e.getUTCDate()},u:function(e){return e.getUTCDay()||7},w:function(e){return e.getUTCDay()},l:function(e){return e.getUTCHours()%12||12},I:function(e){return e.getUTCHours()%12||12},k:function(e){return e.getUTCHours()},Z:function(e){return this.entry.abbrev},a:function(e){return this[this.locale].day.abbrev[e.getUTCDay()]},A:function(e){return this[this.locale].day.full[e.getUTCDay()]},h:function(e){return this[this.locale].month.abbrev[e.getUTCMonth()]},b:function(e){return this[this.locale].month.abbrev[e.getUTCMonth()]},B:function(e){return this[this.locale].month.full[e.getUTCMonth()]},P:function(e){return this[this.locale].meridiem[Math.floor(e.getUTCHours()/12)].toLowerCase()},p:function(e){return this[this.locale].meridiem[Math.floor(e.getUTCHours()/12)]},R:function(e,t){return this.convert([t,\"%H:%M\"])},T:function(e,t){return this.convert([t,\"%H:%M:%S\"])},D:function(e,t){return this.convert([t,\"%m/%d/%y\"])},F:function(e,t){return this.convert([t,\"%Y-%m-%d\"])},x:function(e,t){return this.convert([t,this[this.locale].date])},r:function(e,t){return this.convert([t,this[this.locale].time12||\"%I:%M:%S\"])},X:function(e,t){return this.convert([t,this[this.locale].time24])},c:function(e,t){return this.convert([t,this[this.locale].dateTime])},convert:function(e){if(!e.length)return\"1.0.23\";var t,a,u,l,s,c=Object.create(this),f=[];for(t=0;t=o?Math.floor((n-o)/7)+1:0}function c(e){var t,n,r;return n=e.getUTCFullYear(),t=new Date(Date.UTC(n,0)).getUTCDay(),(r=s(e,1)+(t>1&&t<=4?1:0))?53!=r||4==t||3==t&&29==new Date(n,1,29).getDate()?[r,e.getUTCFullYear()]:[1,e.getUTCFullYear()+1]:(n=e.getUTCFullYear()-1,[r=4==(t=new Date(Date.UTC(n,0)).getUTCDay())||3==t&&29==new Date(n,1,29).getDate()?53:52,e.getUTCFullYear()-1])}return u=u.toLowerCase().split(\"|\"),\"delmHMSUWVgCIky\".replace(/./g,(function(e){a[e].pad=2})),a.N.pad=9,a.j.pad=3,a.k.style=\"_\",a.l.style=\"_\",a.e.style=\"_\",function(){return a.convert(arguments)}}))},\n function _(r,t,n,e,i){e();const u=r(1),a=(0,u.__importStar)(r(153)),f=r(154),o=(0,u.__importDefault)(r(151)),l=r(21),s=r(8);function c(r,...t){return(0,f.sprintf)(r,...t)}function m(r,t,n){if((0,s.isNumber)(r)){return c((()=>{switch(!1){case Math.floor(r)!=r:return\"%d\";case!(Math.abs(r)>.1&&Math.abs(r)<1e3):return\"%0.3f\";default:return\"%0.3e\"}})(),r)}return`${r}`}function _(r,t,e){if(null==t)return m;if(null!=e&&r in e){const t=e[r];if((0,s.isString)(t)){if(t in n.DEFAULT_FORMATTERS)return n.DEFAULT_FORMATTERS[t];throw new Error(`Unknown tooltip field formatter type '${t}'`)}return function(r,n,e){return t.format(r,n,e)}}return n.DEFAULT_FORMATTERS.numeral}function p(r,t,n){const e=t.get_column(r);if(null==e)return null;if((0,s.isNumber)(n))return e[n];const i=e[n.index];if((0,s.isTypedArray)(i)||(0,s.isArray)(i)){if((0,s.isArray)(i[0])){return i[n.dim2][n.dim1]}return i[n.flat_index]}return i}function d(r,t,n,e){if(\"$\"==r[0]){return function(r,t){if(r in t)return t[r];throw new Error(`Unknown special variable '$${r}'`)}(r.substring(1),e)}return p(r.substring(1).replace(/[{}]/g,\"\"),t,n)}n.FormatterType=(0,l.Enum)(\"numeral\",\"printf\",\"datetime\"),n.DEFAULT_FORMATTERS={numeral:(r,t,n)=>a.format(r,t),datetime:(r,t,n)=>(0,o.default)(r,t),printf:(r,t,n)=>c(t,r)},n.sprintf=c,n.basic_formatter=m,n.get_formatter=_,n._get_column_value=p,n.get_value=d,n.replace_placeholders=function(r,t,n,e,i={},u){let a,f;if((0,s.isString)(r)?(a=r,f=!1):(a=r.html,f=!0),a=a.replace(/@\\$name/g,(r=>`@{${i.name}}`)),a=a.replace(/((?:\\$\\w+)|(?:@\\w+)|(?:@{(?:[^{}]+)}))(?:{([^{}]+)})?/g,((r,a,o)=>{const l=d(a,t,n,i);if(null==l)return u?u(\"???\"):\"???\";if(\"safe\"==o)return f=!0,`${l}`;const s=`${_(a,o,e)(l,o,i)}`;return u?u(s):s})),f){return[...(new DOMParser).parseFromString(a,\"text/html\").body.childNodes]}return a}},\n function _(e,n,t,r,i){\n /*!\n * numbro.js\n * version : 1.6.2\n * author : Företagsplatsen AB\n * license : MIT\n * http://www.foretagsplatsen.se\n */\n var a,o={},l=o,u=\"en-US\",c=null,s=\"0,0\";void 0!==n&&n.exports;function f(e){this._value=e}function d(e){var n,t=\"\";for(n=0;n-1?function(e,n){var t,r,i,a;return t=(a=e.toString()).split(\"e\")[0],i=a.split(\"e\")[1],a=t.split(\".\")[0]+(r=t.split(\".\")[1]||\"\")+d(i-r.length),n>0&&(a+=\".\"+d(n)),a}(e,n):(t(e*o)/o).toFixed(n),r&&(i=new RegExp(\"0{1,\"+r+\"}$\"),a=a.replace(i,\"\")),a}function p(e,n,t){var r;return r=n.indexOf(\"$\")>-1?function(e,n,t){var r,i,a=n,l=a.indexOf(\"$\"),c=a.indexOf(\"(\"),s=a.indexOf(\"+\"),f=a.indexOf(\"-\"),d=\"\",h=\"\";-1===a.indexOf(\"$\")?\"infix\"===o[u].currency.position?(h=o[u].currency.symbol,o[u].currency.spaceSeparated&&(h=\" \"+h+\" \")):o[u].currency.spaceSeparated&&(d=\" \"):a.indexOf(\" $\")>-1?(d=\" \",a=a.replace(\" $\",\"\")):a.indexOf(\"$ \")>-1?(d=\" \",a=a.replace(\"$ \",\"\")):a=a.replace(\"$\",\"\");if(i=m(e,a,t,h),-1===n.indexOf(\"$\"))switch(o[u].currency.position){case\"postfix\":i.indexOf(\")\")>-1?((i=i.split(\"\")).splice(-1,0,d+o[u].currency.symbol),i=i.join(\"\")):i=i+d+o[u].currency.symbol;break;case\"infix\":break;case\"prefix\":i.indexOf(\"(\")>-1||i.indexOf(\"-\")>-1?(i=i.split(\"\"),r=Math.max(c,f)+1,i.splice(r,0,o[u].currency.symbol+d),i=i.join(\"\")):i=o[u].currency.symbol+d+i;break;default:throw Error('Currency position should be among [\"prefix\", \"infix\", \"postfix\"]')}else l<=1?i.indexOf(\"(\")>-1||i.indexOf(\"+\")>-1||i.indexOf(\"-\")>-1?(r=1,(l-1?((i=i.split(\"\")).splice(-1,0,d+o[u].currency.symbol),i=i.join(\"\")):i=i+d+o[u].currency.symbol;return i}(e,n,t):n.indexOf(\"%\")>-1?function(e,n,t){var r,i=\"\";e*=100,n.indexOf(\" %\")>-1?(i=\" \",n=n.replace(\" %\",\"\")):n=n.replace(\"%\",\"\");(r=m(e,n,t)).indexOf(\")\")>-1?((r=r.split(\"\")).splice(-1,0,i+\"%\"),r=r.join(\"\")):r=r+i+\"%\";return r}(e,n,t):n.indexOf(\":\")>-1?function(e){var n=Math.floor(e/60/60),t=Math.floor((e-60*n*60)/60),r=Math.round(e-60*n*60-60*t);return n+\":\"+(t<10?\"0\"+t:t)+\":\"+(r<10?\"0\"+r:r)}(e):m(e,n,t),r}function m(e,n,t,r){var i,a,l,s,f,d,p,m,x,g,O,b,w,y,M,v,$,B=!1,E=!1,F=!1,k=\"\",U=!1,N=!1,S=!1,j=!1,D=!1,C=\"\",L=\"\",T=Math.abs(e),K=[\"B\",\"KiB\",\"MiB\",\"GiB\",\"TiB\",\"PiB\",\"EiB\",\"ZiB\",\"YiB\"],G=[\"B\",\"KB\",\"MB\",\"GB\",\"TB\",\"PB\",\"EB\",\"ZB\",\"YB\"],I=\"\",P=!1,R=!1;if(0===e&&null!==c)return c;if(!isFinite(e))return\"\"+e;if(0===n.indexOf(\"{\")){var W=n.indexOf(\"}\");if(-1===W)throw Error('Format should also contain a \"}\"');b=n.slice(1,W),n=n.slice(W+1)}else b=\"\";if(n.indexOf(\"}\")===n.length-1){var Y=n.indexOf(\"{\");if(-1===Y)throw Error('Format should also contain a \"{\"');w=n.slice(Y+1,-1),n=n.slice(0,Y+1)}else w=\"\";if(v=null===($=-1===n.indexOf(\".\")?n.match(/([0-9]+).*/):n.match(/([0-9]+)\\..*/))?-1:$[1].length,-1!==n.indexOf(\"-\")&&(P=!0),n.indexOf(\"(\")>-1?(B=!0,n=n.slice(1,-1)):n.indexOf(\"+\")>-1&&(E=!0,n=n.replace(/\\+/g,\"\")),n.indexOf(\"a\")>-1){if(g=n.split(\".\")[0].match(/[0-9]+/g)||[\"0\"],g=parseInt(g[0],10),U=n.indexOf(\"aK\")>=0,N=n.indexOf(\"aM\")>=0,S=n.indexOf(\"aB\")>=0,j=n.indexOf(\"aT\")>=0,D=U||N||S||j,n.indexOf(\" a\")>-1?(k=\" \",n=n.replace(\" a\",\"\")):n=n.replace(\"a\",\"\"),p=0===(p=(f=Math.floor(Math.log(T)/Math.LN10)+1)%3)?3:p,g&&0!==T&&(d=Math.floor(Math.log(T)/Math.LN10)+1-g,m=3*~~((Math.min(g,f)-p)/3),T/=Math.pow(10,m),-1===n.indexOf(\".\")&&g>3))for(n+=\"[.]\",M=(M=0===d?0:3*~~(d/3)-d)<0?M+3:M,i=0;i=Math.pow(10,12)&&!D||j?(k+=o[u].abbreviations.trillion,e/=Math.pow(10,12)):T=Math.pow(10,9)&&!D||S?(k+=o[u].abbreviations.billion,e/=Math.pow(10,9)):T=Math.pow(10,6)&&!D||N?(k+=o[u].abbreviations.million,e/=Math.pow(10,6)):(T=Math.pow(10,3)&&!D||U)&&(k+=o[u].abbreviations.thousand,e/=Math.pow(10,3)))}if(n.indexOf(\"b\")>-1)for(n.indexOf(\" b\")>-1?(C=\" \",n=n.replace(\" b\",\"\")):n=n.replace(\"b\",\"\"),s=0;s<=K.length;s++)if(a=Math.pow(1024,s),l=Math.pow(1024,s+1),e>=a&&e0&&(e/=a);break}if(n.indexOf(\"d\")>-1)for(n.indexOf(\" d\")>-1?(C=\" \",n=n.replace(\" d\",\"\")):n=n.replace(\"d\",\"\"),s=0;s<=G.length;s++)if(a=Math.pow(1e3,s),l=Math.pow(1e3,s+1),e>=a&&e0&&(e/=a);break}if(n.indexOf(\"o\")>-1&&(n.indexOf(\" o\")>-1?(L=\" \",n=n.replace(\" o\",\"\")):n=n.replace(\"o\",\"\"),o[u].ordinal&&(L+=o[u].ordinal(e))),n.indexOf(\"[.]\")>-1&&(F=!0,n=n.replace(\"[.]\",\".\")),x=e.toString().split(\".\")[0],O=n.split(\".\")[1],y=n.indexOf(\",\"),O){if(x=(I=-1!==O.indexOf(\"*\")?h(e,e.toString().split(\".\")[1].length,t):O.indexOf(\"[\")>-1?h(e,(O=(O=O.replace(\"]\",\"\")).split(\"[\"))[0].length+O[1].length,t,O[1].length):h(e,O.length,t)).split(\".\")[0],I.split(\".\")[1].length)I=(r?k+r:o[u].delimiters.decimal)+I.split(\".\")[1];else I=\"\";F&&0===Number(I.slice(1))&&(I=\"\")}else x=h(e,null,t);return x.indexOf(\"-\")>-1&&(x=x.slice(1),R=!0),x.length-1&&(x=x.toString().replace(/(\\d)(?=(\\d{3})+(?!\\d))/g,\"$1\"+o[u].delimiters.thousands)),0===n.indexOf(\".\")&&(x=\"\"),b+(n.indexOf(\"(\")2)&&(o.length<2?!!o[0].match(/^\\d+.*\\d$/)&&!o[0].match(u):1===o[0].length?!!o[0].match(/^\\d+$/)&&!o[0].match(u)&&!!o[1].match(/^\\d+$/):!!o[0].match(/^\\d+.*\\d$/)&&!o[0].match(u)&&!!o[1].match(/^\\d+$/)))))},n.exports={format:function(e,n,t,r){return null!=t&&t!==a.culture()&&a.setCulture(t),p(Number(e),null!=n?n:s,null==r?Math.round:r)}}},\n function _(e,n,t,r,i){!function(){\"use strict\";var e={not_string:/[^s]/,not_bool:/[^t]/,not_type:/[^T]/,not_primitive:/[^v]/,number:/[diefg]/,numeric_arg:/[bcdiefguxX]/,json:/[j]/,not_json:/[^j]/,text:/^[^\\x25]+/,modulo:/^\\x25{2}/,placeholder:/^\\x25(?:([1-9]\\d*)\\$|\\(([^)]+)\\))?(\\+)?(0|'[^$])?(-)?(\\d+)?(?:\\.(\\d+))?([b-gijostTuvxX])/,key:/^([a-z_][a-z_\\d]*)/i,key_access:/^\\.([a-z_][a-z_\\d]*)/i,index_access:/^\\[(\\d+)\\]/,sign:/^[+-]/};function n(e){return i(a(e),arguments)}function r(e,t){return n.apply(null,[e].concat(t||[]))}function i(t,r){var i,s,a,o,p,c,l,u,f,d=1,g=t.length,y=\"\";for(s=0;s=0),o.type){case\"b\":i=parseInt(i,10).toString(2);break;case\"c\":i=String.fromCharCode(parseInt(i,10));break;case\"d\":case\"i\":i=parseInt(i,10);break;case\"j\":i=JSON.stringify(i,null,o.width?parseInt(o.width):0);break;case\"e\":i=o.precision?parseFloat(i).toExponential(o.precision):parseFloat(i).toExponential();break;case\"f\":i=o.precision?parseFloat(i).toFixed(o.precision):parseFloat(i);break;case\"g\":i=o.precision?String(Number(i.toPrecision(o.precision))):parseFloat(i);break;case\"o\":i=(parseInt(i,10)>>>0).toString(8);break;case\"s\":i=String(i),i=o.precision?i.substring(0,o.precision):i;break;case\"t\":i=String(!!i),i=o.precision?i.substring(0,o.precision):i;break;case\"T\":i=Object.prototype.toString.call(i).slice(8,-1).toLowerCase(),i=o.precision?i.substring(0,o.precision):i;break;case\"u\":i=parseInt(i,10)>>>0;break;case\"v\":i=i.valueOf(),i=o.precision?i.substring(0,o.precision):i;break;case\"x\":i=(parseInt(i,10)>>>0).toString(16);break;case\"X\":i=(parseInt(i,10)>>>0).toString(16).toUpperCase()}e.json.test(o.type)?y+=i:(!e.number.test(o.type)||u&&!o.sign?f=\"\":(f=u?\"+\":\"-\",i=i.toString().replace(e.sign,\"\")),c=o.pad_char?\"0\"===o.pad_char?\"0\":o.pad_char.charAt(1):\" \",l=o.width-(f+i).length,p=o.width&&l>0?c.repeat(l):\"\",y+=o.align?f+i+p:\"0\"===c?f+p+i:p+f+i)}return y}var s=Object.create(null);function a(n){if(s[n])return s[n];for(var t,r=n,i=[],a=0;r;){if(null!==(t=e.text.exec(r)))i.push(t[0]);else if(null!==(t=e.modulo.exec(r)))i.push(\"%\");else{if(null===(t=e.placeholder.exec(r)))throw new SyntaxError(\"[sprintf] unexpected placeholder\");if(t[2]){a|=1;var o=[],p=t[2],c=[];if(null===(c=e.key.exec(p)))throw new SyntaxError(\"[sprintf] failed to parse named argument key\");for(o.push(c[1]);\"\"!==(p=p.substring(c[0].length));)if(null!==(c=e.key_access.exec(p)))o.push(c[1]);else{if(null===(c=e.index_access.exec(p)))throw new SyntaxError(\"[sprintf] failed to parse named argument key\");o.push(c[1])}t[2]=o}else a|=2;if(3===a)throw new Error(\"[sprintf] mixing positional and named placeholders is not (yet) supported\");i.push({placeholder:t[0],param_no:t[1],keys:t[2],sign:t[3],pad_char:t[4],align:t[5],width:t[6],precision:t[7],type:t[8]})}r=r.substring(t[0].length)}return s[n]=i}void 0!==t&&(t.sprintf=n,t.vsprintf=r),\"undefined\"!=typeof window&&(window.sprintf=n,window.vsprintf=r,\"function\"==typeof define&&define.amd&&define((function(){return{sprintf:n,vsprintf:r}})))}()},\n function _(e,n,i,a,s){var r;a();const t=e(9),c=e(148),m=e(156),_=e(157),k=e(160),o=e(161),T=e(159);class w extends m.CompositeTicker{constructor(e){super(e)}}i.DatetimeTicker=w,r=w,w.__name__=\"DatetimeTicker\",r.override({num_minor_ticks:0,tickers:()=>[new c.AdaptiveTicker({mantissas:[1,2,5],base:10,min_interval:0,max_interval:500*T.ONE_MILLI,num_minor_ticks:0}),new c.AdaptiveTicker({mantissas:[1,2,5,10,15,20,30],base:60,min_interval:T.ONE_SECOND,max_interval:30*T.ONE_MINUTE,num_minor_ticks:0}),new c.AdaptiveTicker({mantissas:[1,2,4,6,8,12],base:24,min_interval:T.ONE_HOUR,max_interval:12*T.ONE_HOUR,num_minor_ticks:0}),new _.DaysTicker({days:(0,t.range)(1,32)}),new _.DaysTicker({days:(0,t.range)(1,31,3)}),new _.DaysTicker({days:[1,8,15,22]}),new _.DaysTicker({days:[1,15]}),new k.MonthsTicker({months:(0,t.range)(0,12,1)}),new k.MonthsTicker({months:(0,t.range)(0,12,2)}),new k.MonthsTicker({months:(0,t.range)(0,12,4)}),new k.MonthsTicker({months:(0,t.range)(0,12,6)}),new o.YearsTicker({})]})},\n function _(t,e,i,r,s){var n;r();const _=t(149),a=t(9);class l extends _.ContinuousTicker{constructor(t){super(t)}get min_intervals(){return this.tickers.map((t=>t.get_min_interval()))}get max_intervals(){return this.tickers.map((t=>t.get_max_interval()))}get_min_interval(){return this.min_intervals[0]}get_max_interval(){return this.max_intervals[0]}get_best_ticker(t,e,i){const r=e-t,s=this.get_ideal_interval(t,e,i),n=[(0,a.sorted_index)(this.min_intervals,s)-1,(0,a.sorted_index)(this.max_intervals,s)],_=[this.min_intervals[n[0]],this.max_intervals[n[1]]].map((t=>Math.abs(i-r/t)));let l;if((0,a.is_empty)(_.filter((t=>!isNaN(t)))))l=this.tickers[0];else{const t=n[(0,a.argmin)(_)];l=this.tickers[t]}return l}get_interval(t,e,i){return this.get_best_ticker(t,e,i).get_interval(t,e,i)}get_ticks_no_defaults(t,e,i,r){return this.get_best_ticker(t,e,r).get_ticks_no_defaults(t,e,i,r)}}i.CompositeTicker=l,n=l,l.__name__=\"CompositeTicker\",n.define((({Array:t,Ref:e})=>({tickers:[t(e(_.ContinuousTicker)),[]]})))},\n function _(t,e,n,s,o){var a;s();const i=t(158),r=t(159),c=t(9);class _ extends i.SingleIntervalTicker{constructor(t){super(t)}initialize(){super.initialize();const t=this.days;t.length>1?this.interval=(t[1]-t[0])*r.ONE_DAY:this.interval=31*r.ONE_DAY}get_ticks_no_defaults(t,e,n,s){const o=function(t,e){const n=(0,r.last_month_no_later_than)(new Date(t)),s=(0,r.last_month_no_later_than)(new Date(e));s.setUTCMonth(s.getUTCMonth()+1);const o=[],a=n;for(;o.push((0,r.copy_date)(a)),a.setUTCMonth(a.getUTCMonth()+1),!(a>s););return o}(t,e),a=this.days,i=this.interval,_=(0,c.concat)(o.map((t=>((t,e)=>{const n=t.getUTCMonth(),s=[];for(const o of a){const a=(0,r.copy_date)(t);a.setUTCDate(o),new Date(a.getTime()+e/2).getUTCMonth()==n&&s.push(a)}return s})(t,i))));return{major:_.map((t=>t.getTime())).filter((n=>t<=n&&n<=e)),minor:[]}}}n.DaysTicker=_,a=_,_.__name__=\"DaysTicker\",a.define((({Int:t,Array:e})=>({days:[e(t),[]]}))),a.override({num_minor_ticks:0})},\n function _(e,n,t,r,i){var a;r();const l=e(149);class s extends l.ContinuousTicker{constructor(e){super(e)}get_interval(e,n,t){return this.interval}get_min_interval(){return this.interval}get_max_interval(){return this.interval}}t.SingleIntervalTicker=s,a=s,s.__name__=\"SingleIntervalTicker\",a.define((({Number:e})=>({interval:[e]})))},\n function _(t,n,e,_,E){function N(t){return new Date(t.getTime())}function O(t){const n=N(t);return n.setUTCDate(1),n.setUTCHours(0),n.setUTCMinutes(0),n.setUTCSeconds(0),n.setUTCMilliseconds(0),n}_(),e.ONE_MILLI=1,e.ONE_SECOND=1e3,e.ONE_MINUTE=60*e.ONE_SECOND,e.ONE_HOUR=60*e.ONE_MINUTE,e.ONE_DAY=24*e.ONE_HOUR,e.ONE_MONTH=30*e.ONE_DAY,e.ONE_YEAR=365*e.ONE_DAY,e.copy_date=N,e.last_month_no_later_than=O,e.last_year_no_later_than=function(t){const n=O(t);return n.setUTCMonth(0),n}},\n function _(t,e,n,a,r){var s;a();const i=t(158),o=t(159),l=t(9);class _ extends i.SingleIntervalTicker{constructor(t){super(t)}initialize(){super.initialize();const t=this.months;t.length>1?this.interval=(t[1]-t[0])*o.ONE_MONTH:this.interval=12*o.ONE_MONTH}get_ticks_no_defaults(t,e,n,a){const r=function(t,e){const n=(0,o.last_year_no_later_than)(new Date(t)),a=(0,o.last_year_no_later_than)(new Date(e));a.setUTCFullYear(a.getUTCFullYear()+1);const r=[],s=n;for(;r.push((0,o.copy_date)(s)),s.setUTCFullYear(s.getUTCFullYear()+1),!(s>a););return r}(t,e),s=this.months;return{major:(0,l.concat)(r.map((t=>s.map((e=>{const n=(0,o.copy_date)(t);return n.setUTCMonth(e),n}))))).map((t=>t.getTime())).filter((n=>t<=n&&n<=e)),minor:[]}}}n.MonthsTicker=_,s=_,_.__name__=\"MonthsTicker\",s.define((({Int:t,Array:e})=>({months:[e(t),[]]})))},\n function _(e,t,a,i,r){i();const n=e(147),_=e(158),s=e(159);class c extends _.SingleIntervalTicker{constructor(e){super(e)}initialize(){super.initialize(),this.interval=s.ONE_YEAR,this.basic_ticker=new n.BasicTicker({num_minor_ticks:0})}get_ticks_no_defaults(e,t,a,i){const r=(0,s.last_year_no_later_than)(new Date(e)).getUTCFullYear(),n=(0,s.last_year_no_later_than)(new Date(t)).getUTCFullYear();return{major:this.basic_ticker.get_ticks_no_defaults(r,n,a,i).major.map((e=>Date.UTC(e,0,1))).filter((a=>e<=a&&a<=t)),minor:[]}}}a.YearsTicker=c,c.__name__=\"YearsTicker\"},\n function _(e,o,i,s,t){var n;s();const r=e(143),_=e(163),c=e(164);class a extends r.ContinuousAxisView{}i.LogAxisView=a,a.__name__=\"LogAxisView\";class u extends r.ContinuousAxis{constructor(e){super(e)}}i.LogAxis=u,n=u,u.__name__=\"LogAxis\",n.prototype.default_view=a,n.override({ticker:()=>new c.LogTicker,formatter:()=>new _.LogTickFormatter})},\n function _(e,t,n,o,r){var i;o();const a=e(131),s=e(146),c=e(164),l=e(120),{abs:u,log:x,round:_}=Math;class p extends a.TickFormatter{constructor(e){super(e)}initialize(){super.initialize(),this.basic_formatter=new s.BasicTickFormatter}format_graphics(e,t){var n,o;if(0==e.length)return[];const r=null!==(o=null===(n=this.ticker)||void 0===n?void 0:n.base)&&void 0!==o?o:10,i=this._exponents(e,r);return null==i?this.basic_formatter.format_graphics(e,t):i.map((e=>{if(u(e)u(e)({ticker:[n(t(c.LogTicker)),null],min_exponent:[e,0]})))},\n function _(t,o,e,s,n){var r;s();const i=t(148),a=t(9);class c extends i.AdaptiveTicker{constructor(t){super(t)}get_ticks_no_defaults(t,o,e,s){const n=this.num_minor_ticks,r=[],i=this.base,c=Math.log(t)/Math.log(i),f=Math.log(o)/Math.log(i),l=f-c;let h;if(isFinite(l))if(l<2){const e=this.get_interval(t,o,s),i=Math.floor(t/e),c=Math.ceil(o/e);if(h=(0,a.range)(i,c+1).filter((t=>0!=t)).map((t=>t*e)).filter((e=>t<=e&&e<=o)),n>0&&h.length>0){const t=e/n,o=(0,a.range)(0,n).map((o=>o*t));for(const t of o.slice(1))r.push(h[0]-t);for(const t of h)for(const e of o)r.push(t+e)}}else{const t=Math.ceil(.999999*c),o=Math.floor(1.000001*f),e=Math.ceil((o-t)/9);if(h=(0,a.range)(t-1,o+1,e).map((t=>i**t)),n>0&&h.length>0){const t=i**e/n,o=(0,a.range)(1,n+1).map((o=>o*t));for(const t of o)r.push(h[0]/t);r.push(h[0]);for(const t of h)for(const e of o)r.push(t*e)}}else h=[];return{major:h.filter((e=>t<=e&&e<=o)),minor:r.filter((e=>t<=e&&e<=o))}}}e.LogTicker=c,r=c,c.__name__=\"LogTicker\",r.override({mantissas:[1,5]})},\n function _(e,r,t,i,a){var o;i();const s=e(128),c=e(145),n=e(166),_=e(167);class x extends s.AxisView{}t.MercatorAxisView=x,x.__name__=\"MercatorAxisView\";class d extends c.LinearAxis{constructor(e){super(e)}}t.MercatorAxis=d,o=d,d.__name__=\"MercatorAxis\",o.prototype.default_view=x,o.override({ticker:()=>new _.MercatorTicker({dimension:\"lat\"}),formatter:()=>new n.MercatorTickFormatter({dimension:\"lat\"})})},\n function _(r,t,e,o,n){var i;o();const c=r(146),s=r(20),a=r(78);class l extends c.BasicTickFormatter{constructor(r){super(r)}doFormat(r,t){if(null==this.dimension)throw new Error(\"MercatorTickFormatter.dimension not configured\");if(0==r.length)return[];const e=r.length,o=new Array(e);if(\"lon\"==this.dimension)for(let n=0;n({dimension:[r(s.LatLon),null]})))},\n function _(t,o,n,s,r){var e;s();const i=t(147),c=t(20),_=t(78);class a extends i.BasicTicker{constructor(t){super(t)}get_ticks_no_defaults(t,o,n,s){if(null==this.dimension)throw new Error(`${this}.dimension wasn't configured`);return[t,o]=(0,_.clip_mercator)(t,o,this.dimension),\"lon\"==this.dimension?this._get_ticks_lon(t,o,n,s):this._get_ticks_lat(t,o,n,s)}_get_ticks_lon(t,o,n,s){const[r]=_.wgs84_mercator.invert(t,n),[e,i]=_.wgs84_mercator.invert(o,n),c=super.get_ticks_no_defaults(r,e,n,s),a=[];for(const t of c.major)if((0,_.in_bounds)(t,\"lon\")){const[o]=_.wgs84_mercator.compute(t,i);a.push(o)}const m=[];for(const t of c.minor)if((0,_.in_bounds)(t,\"lon\")){const[o]=_.wgs84_mercator.compute(t,i);m.push(o)}return{major:a,minor:m}}_get_ticks_lat(t,o,n,s){const[,r]=_.wgs84_mercator.invert(n,t),[e,i]=_.wgs84_mercator.invert(n,o),c=super.get_ticks_no_defaults(r,i,n,s),a=[];for(const t of c.major)if((0,_.in_bounds)(t,\"lat\")){const[,o]=_.wgs84_mercator.compute(e,t);a.push(o)}const m=[];for(const t of c.minor)if((0,_.in_bounds)(t,\"lat\")){const[,o]=_.wgs84_mercator.compute(e,t);m.push(o)}return{major:a,minor:m}}}n.MercatorTicker=a,e=a,a.__name__=\"MercatorTicker\",e.define((({Nullable:t})=>({dimension:[t(c.LatLon),null]})))},\n function _(e,i,r,c,k){c(),k(\"AdaptiveTicker\",e(148).AdaptiveTicker),k(\"BasicTicker\",e(147).BasicTicker),k(\"CategoricalTicker\",e(141).CategoricalTicker),k(\"CompositeTicker\",e(156).CompositeTicker),k(\"ContinuousTicker\",e(149).ContinuousTicker),k(\"DatetimeTicker\",e(155).DatetimeTicker),k(\"DaysTicker\",e(157).DaysTicker),k(\"FixedTicker\",e(169).FixedTicker),k(\"LogTicker\",e(164).LogTicker),k(\"MercatorTicker\",e(167).MercatorTicker),k(\"MonthsTicker\",e(160).MonthsTicker),k(\"SingleIntervalTicker\",e(158).SingleIntervalTicker),k(\"Ticker\",e(130).Ticker),k(\"YearsTicker\",e(161).YearsTicker),k(\"BinnedTicker\",e(170).BinnedTicker)},\n function _(r,t,e,i,n){var s;i();const _=r(149);class c extends _.ContinuousTicker{constructor(r){super(r)}get_ticks_no_defaults(r,t,e,i){return{major:this.ticks,minor:this.minor_ticks}}get_interval(r,t,e){return 0}get_min_interval(){return 0}get_max_interval(){return 0}}e.FixedTicker=c,s=c,c.__name__=\"FixedTicker\",s.define((({Number:r,Array:t})=>({ticks:[t(r),[]],minor_ticks:[t(r),[]]})))},\n function _(e,n,t,r,i){var o;r();const a=e(130),s=e(171),c=e(12);class m extends a.Ticker{constructor(e){super(e)}get_ticks(e,n,t,r){const{binning:i}=this.mapper.metrics,o=Math.max(0,(0,c.left_edge_index)(e,i)),a=Math.min((0,c.left_edge_index)(n,i)+1,i.length-1),s=[];for(let e=o;e<=a;e++)s.push(i[e]);const{num_major_ticks:m}=this,_=[],h=\"auto\"==m?s.length:m,l=Math.max(1,Math.floor(s.length/h));for(let e=0;e({mapper:[n(s.ScanningColorMapper)],num_major_ticks:[t(e,r),8]})))},\n function _(n,e,i,r,o){r();const t=n(172),a=n(12);class c extends t.ContinuousColorMapper{constructor(n){super(n)}cmap(n,e,i,r,o){if(no.binning[o.binning.length-1])return r;return e[(0,a.left_edge_index)(n,o.binning)]}}i.ScanningColorMapper=c,c.__name__=\"ScanningColorMapper\"},\n function _(t,e,o,n,s){var l;n();const c=t(173),i=t(175),a=t(9),h=t(8);class r extends c.ColorMapper{constructor(t){super(t),this._scan_data=null}connect_signals(){super.connect_signals();const t=()=>{for(const[t]of this.domain)this.connect(t.view.change,(()=>this.update_data())),this.connect(t.data_source.selected.change,(()=>this.update_data()))};this.connect(this.properties.domain.change,(()=>t())),t()}update_data(){const{domain:t,palette:e}=this,o=[...this._collect(t)];this._scan_data=this.scan(o,e.length),this.metrics_change.emit(),this.change.emit()}get metrics(){return null==this._scan_data&&this.update_data(),this._scan_data}*_collect(t){for(const[e,o]of t)for(const t of(0,h.isArray)(o)?o:[o]){let o=e.data_source.get_column(t);o=e.view.indices.select(o);const n=e.view.masked,s=e.data_source.selected.indices;let l;if(null!=n&&s.length>0?l=(0,a.intersection)([...n],s):null!=n?l=[...n]:s.length>0&&(l=s),null!=l&&(o=(0,a.map)(l,(t=>o[t]))),o.length>0&&!(0,h.isNumber)(o[0]))for(const t of o)yield*t;else yield*o}}_v_compute(t,e,o,n){const{nan_color:s}=n;let{low_color:l,high_color:c}=n;null==l&&(l=o[0]),null==c&&(c=o[o.length-1]);const{domain:i}=this,h=(0,a.is_empty)(i)?t:[...this._collect(i)];this._scan_data=this.scan(h,o.length),this.metrics_change.emit();for(let n=0,i=t.length;n({high:[a(t),null],low:[a(t),null],high_color:[a(n),null],low_color:[a(n),null],domain:[c(l(o(i.GlyphRenderer),s(e,c(e)))),[]]})))},\n function _(e,r,t,n,o){var a;n();const c=e(174),i=e(15),_=e(24),l=e(22),s=e(27);function p(e){return(0,l.encode_rgba)((0,l.color2rgba)(e))}function u(e){const r=new Uint32Array(e.length);for(let t=0,n=e.length;te))),r}get rgba_mapper(){const e=this,r=u(this.palette),t=this._colors(p);return{v_compute(n){const o=new _.ColorArray(n.length);return e._v_compute(n,o,r,t),new Uint8ClampedArray((0,s.to_big_endian)(o).buffer)}}}_colors(e){return{nan_color:e(this.nan_color)}}}t.ColorMapper=h,a=h,h.__name__=\"ColorMapper\",a.define((({Color:e,Array:r})=>({palette:[r(e)],nan_color:[e,\"gray\"]})))},\n function _(r,e,n,s,o){s();const p=r(56);class t extends p.Transform{constructor(r){super(r)}compute(r){throw new Error(\"mapping single values is not supported\")}}n.Mapper=t,t.__name__=\"Mapper\"},\n function _(e,t,i,s,l){var h;s();const n=e(176),o=e(177),a=e(186),c=e(187),_=e(189),r=e(179),d=e(70),p=e(190),g=e(24),u=e(12),y=e(13),m=e(113),v=e(67),f={fill:{},line:{}},w={fill:{fill_alpha:.3,fill_color:\"grey\"},line:{line_alpha:.3,line_color:\"grey\"}},b={fill:{fill_alpha:.2},line:{}},V={fill:{fill_alpha:.2},line:{}};class x extends n.DataRendererView{get glyph_view(){return this.glyph}async lazy_initialize(){var e;await super.lazy_initialize();const t=this.model.glyph;this.glyph=await this.build_glyph_view(t);const i=\"fill\"in this.glyph.visuals,s=\"line\"in this.glyph.visuals,l=Object.assign({},t.attributes);function h(e){const h=(0,y.clone)(l);return i&&(0,y.extend)(h,e.fill),s&&(0,y.extend)(h,e.line),new t.constructor(h)}function n(e,t){return t instanceof r.Glyph?t:h(\"auto\"==t?e:{fill:{},line:{}})}delete l.id;let{selection_glyph:o,nonselection_glyph:a,hover_glyph:c,muted_glyph:_}=this.model;o=n(f,o),this.selection_glyph=await this.build_glyph_view(o),a=n(b,a),this.nonselection_glyph=await this.build_glyph_view(a),null!=c&&(this.hover_glyph=await this.build_glyph_view(c)),_=n(V,_),this.muted_glyph=await this.build_glyph_view(_);const d=n(w,\"auto\");this.decimated_glyph=await this.build_glyph_view(d),this.selection_glyph.set_base(this.glyph),this.nonselection_glyph.set_base(this.glyph),null===(e=this.hover_glyph)||void 0===e||e.set_base(this.glyph),this.muted_glyph.set_base(this.glyph),this.decimated_glyph.set_base(this.glyph),this.set_data()}async build_glyph_view(e){return(0,m.build_view)(e,{parent:this})}remove(){var e;this.glyph.remove(),this.selection_glyph.remove(),this.nonselection_glyph.remove(),null===(e=this.hover_glyph)||void 0===e||e.remove(),this.muted_glyph.remove(),this.decimated_glyph.remove(),super.remove()}connect_signals(){super.connect_signals();const e=()=>this.request_render(),t=()=>this.update_data();this.connect(this.model.change,e),this.connect(this.glyph.model.change,t),this.connect(this.selection_glyph.model.change,t),this.connect(this.nonselection_glyph.model.change,t),null!=this.hover_glyph&&this.connect(this.hover_glyph.model.change,t),this.connect(this.muted_glyph.model.change,t),this.connect(this.decimated_glyph.model.change,t),this.connect(this.model.data_source.change,t),this.connect(this.model.data_source.streaming,t),this.connect(this.model.data_source.patching,(e=>this.update_data(e))),this.connect(this.model.data_source.selected.change,e),this.connect(this.model.data_source._select,e),null!=this.hover_glyph&&this.connect(this.model.data_source.inspect,e),this.connect(this.model.properties.view.change,t),this.connect(this.model.view.properties.indices.change,t),this.connect(this.model.view.properties.masked.change,(()=>this.set_visuals())),this.connect(this.model.properties.visible.change,(()=>this.plot_view.invalidate_dataranges=!0));const{x_ranges:i,y_ranges:s}=this.plot_view.frame;for(const[,e]of i)e instanceof v.FactorRange&&this.connect(e.change,t);for(const[,e]of s)e instanceof v.FactorRange&&this.connect(e.change,t);const{transformchange:l,exprchange:h}=this.model.glyph;this.connect(l,t),this.connect(h,t)}_update_masked_indices(){const e=this.glyph.mask_data();return this.model.view.masked=e,e}update_data(e){this.set_data(e),this.request_render()}set_data(e){const t=this.model.data_source;this.all_indices=this.model.view.indices;const{all_indices:i}=this;this.glyph.set_data(t,i,e),this.set_visuals(),this._update_masked_indices();const{lod_factor:s}=this.plot_model,l=this.all_indices.count;this.decimated=new g.Indices(l);for(let e=0;e!n||n.is_empty()?[]:n.selected_glyph?this.model.view.convert_indices_from_subset(i):n.indices.length>0?n.indices:Object.keys(n.multiline_indices).map((e=>parseInt(e))))()),d=(0,u.filter)(i,(e=>r.has(t[e]))),{lod_threshold:p}=this.plot_model;let g,y,m;if(null!=this.model.document&&this.model.document.interactive_duration()>0&&!e&&null!=p&&t.length>p?(i=[...this.decimated],g=this.decimated_glyph,y=this.decimated_glyph,m=this.selection_glyph):(g=this.model.muted?this.muted_glyph:this.glyph,y=this.nonselection_glyph,m=this.selection_glyph),null!=this.hover_glyph&&d.length){const e=new Set(i);for(const t of d)e.delete(t);i=[...e]}if(h.length){const e={};for(const t of h)e[t]=!0;const l=new Array,n=new Array;if(this.glyph instanceof o.LineView)for(const i of t)null!=e[i]?l.push(i):n.push(i);else for(const s of i)null!=e[t[s]]?l.push(s):n.push(s);y.render(s,n),m.render(s,l),null!=this.hover_glyph&&(this.glyph instanceof o.LineView?this.hover_glyph.render(s,this.model.view.convert_indices_from_subset(d)):this.hover_glyph.render(s,d))}else if(this.glyph instanceof o.LineView)this.hover_glyph&&d.length?this.hover_glyph.render(s,this.model.view.convert_indices_from_subset(d)):g.render(s,t);else if(this.glyph instanceof a.PatchView||this.glyph instanceof c.HAreaView||this.glyph instanceof _.VAreaView)if(0==n.selected_glyphs.length||null==this.hover_glyph)g.render(s,t);else for(const e of n.selected_glyphs)e==this.glyph.model&&this.hover_glyph.render(s,t);else g.render(s,i),this.hover_glyph&&d.length&&this.hover_glyph.render(s,d);s.restore()}draw_legend(e,t,i,s,l,h,n,o){0!=this.glyph.data_size&&(null==o&&(o=this.model.get_reference_point(h,n)),this.glyph.draw_legend_for_index(e,{x0:t,x1:i,y0:s,y1:l},o))}hit_test(e){if(!this.model.visible)return null;const t=this.glyph.hit_test(e);return null==t?null:this.model.view.convert_selection_from_subset(t)}}i.GlyphRendererView=x,x.__name__=\"GlyphRendererView\";class G extends n.DataRenderer{constructor(e){super(e)}initialize(){super.initialize(),this.view.source!=this.data_source&&(this.view.source=this.data_source,this.view.compute_indices())}get_reference_point(e,t){if(null!=e){const i=this.data_source.get_column(e);if(null!=i)for(const[e,s]of Object.entries(this.view.indices_map))if(i[parseInt(e)]==t)return s}return 0}get_selection_manager(){return this.data_source.selection_manager}}i.GlyphRenderer=G,h=G,G.__name__=\"GlyphRenderer\",h.prototype.default_view=x,h.define((({Boolean:e,Auto:t,Or:i,Ref:s,Null:l,Nullable:h})=>({data_source:[s(d.ColumnarDataSource)],view:[s(p.CDSView),e=>new p.CDSView({source:e.data_source})],glyph:[s(r.Glyph)],hover_glyph:[h(s(r.Glyph)),null],nonselection_glyph:[i(s(r.Glyph),t,l),\"auto\"],selection_glyph:[i(s(r.Glyph),t,l),\"auto\"],muted_glyph:[i(s(r.Glyph),t,l),\"auto\"],muted:[e,!1]})))},\n function _(e,r,t,a,n){var s;a();const c=e(41);class _ extends c.RendererView{get xscale(){return this.coordinates.x_scale}get yscale(){return this.coordinates.y_scale}}t.DataRendererView=_,_.__name__=\"DataRendererView\";class i extends c.Renderer{constructor(e){super(e)}get selection_manager(){return this.get_selection_manager()}}t.DataRenderer=i,s=i,i.__name__=\"DataRenderer\",s.override({level:\"glyph\"})},\n function _(e,t,i,s,n){s();const l=e(1);var _;const r=e(178),o=e(184),a=(0,l.__importStar)(e(48)),h=(0,l.__importStar)(e(185)),c=e(72);class d extends r.XYGlyphView{async lazy_initialize(){await super.lazy_initialize();const{webgl:t}=this.renderer.plot_view.canvas_view;if(null==t?void 0:t.regl_wrapper.has_webgl){const{LineGL:i}=await Promise.resolve().then((()=>(0,l.__importStar)(e(426))));this.glglyph=new i(t.regl_wrapper,this)}}_render(e,t,i){const{sx:s,sy:n}=null!=i?i:this;let l=null;const _=e=>null!=l&&e-l!=1;let r=!0;e.beginPath();for(const i of t){const t=s[i],o=n[i];isFinite(t+o)?r||_(i)?(e.moveTo(t,o),r=!1):e.lineTo(t,o):r=!0,l=i}this.visuals.line.set_value(e),e.stroke()}_hit_point(e){const t=new c.Selection,i={x:e.sx,y:e.sy};let s=9999;const n=Math.max(2,this.line_width.value/2);for(let e=0,l=this.sx.length-1;e({x:[c.XCoordinateSpec,{field:\"x\"}],y:[c.YCoordinateSpec,{field:\"y\"}]})))},\n function _(e,t,s,i,n){i();const r=e(1),a=(0,r.__importStar)(e(18)),o=(0,r.__importStar)(e(65)),_=(0,r.__importStar)(e(45)),l=e(42),c=e(53),h=e(19),d=e(24),u=e(8),f=e(180),p=e(12),g=e(26),y=e(181),x=e(67),v=e(72),{abs:b,ceil:m}=Math;class w extends l.View{constructor(){super(...arguments),this._index=null,this._data_size=null,this._nohit_warned=new Set}get renderer(){return this.parent}get has_webgl(){return null!=this.glglyph}get index(){const{_index:e}=this;if(null!=e)return e;throw new Error(`${this}.index_data() wasn't called`)}get data_size(){const{_data_size:e}=this;if(null!=e)return e;throw new Error(`${this}.set_data() wasn't called`)}initialize(){super.initialize(),this.visuals=new _.Visuals(this)}request_render(){this.parent.request_render()}get canvas(){return this.renderer.parent.canvas_view}render(e,t,s){var i;null!=this.glglyph&&(this.renderer.needs_webgl_blit=this.glglyph.render(e,t,null!==(i=this.base)&&void 0!==i?i:this),this.renderer.needs_webgl_blit)||this._render(e,t,null!=s?s:this.base)}has_finished(){return!0}notify_finished(){this.renderer.notify_finished()}_bounds(e){return e}bounds(){return this._bounds(this.index.bbox)}log_bounds(){const{x0:e,x1:t}=this.index.bounds(o.positive_x()),{y0:s,y1:i}=this.index.bounds(o.positive_y());return this._bounds({x0:e,y0:s,x1:t,y1:i})}get_anchor_point(e,t,[s,i]){switch(e){case\"center\":case\"center_center\":{const[e,n]=this.scenterxy(t,s,i);return{x:e,y:n}}default:return null}}scenterx(e,t,s){return this.scenterxy(e,t,s)[0]}scentery(e,t,s){return this.scenterxy(e,t,s)[1]}sdist(e,t,s,i=\"edge\",n=!1){const r=t.length,a=new d.ScreenArray(r),o=e.s_compute;if(\"center\"==i)for(let e=0;em(e))),a}draw_legend_for_index(e,t,s){}hit_test(e){switch(e.type){case\"point\":if(null!=this._hit_point)return this._hit_point(e);break;case\"span\":if(null!=this._hit_span)return this._hit_span(e);break;case\"rect\":if(null!=this._hit_rect)return this._hit_rect(e);break;case\"poly\":if(null!=this._hit_poly)return this._hit_poly(e)}return this._nohit_warned.has(e.type)||(h.logger.debug(`'${e.type}' selection not available for ${this.model.type}`),this._nohit_warned.add(e.type)),null}_hit_rect_against_index(e){const{sx0:t,sx1:s,sy0:i,sy1:n}=e,[r,a]=this.renderer.coordinates.x_scale.r_invert(t,s),[o,_]=this.renderer.coordinates.y_scale.r_invert(i,n),l=[...this.index.indices({x0:r,x1:a,y0:o,y1:_})];return new v.Selection({indices:l})}_project_data(){}*_iter_visuals(){for(const e of this.visuals)for(const t of e)(t instanceof a.VectorSpec||t instanceof a.ScalarSpec)&&(yield t)}set_base(e){e!=this&&e instanceof this.constructor&&(this.base=e)}_configure(e,t){Object.defineProperty(this,(0,u.isString)(e)?e:e.attr,Object.assign({configurable:!0,enumerable:!0},t))}set_visuals(e,t){var s;for(const s of this._iter_visuals()){const{base:i}=this;if(null!=i){const e=i.model.properties[s.attr];if(null!=e&&(0,g.is_equal)(s.get_value(),e.get_value())){this._configure(s,{get:()=>i[`${s.attr}`]});continue}}const n=s.uniform(e).select(t);this._configure(s,{value:n})}for(const e of this.visuals)e.update();null===(s=this.glglyph)||void 0===s||s.set_visuals_changed()}set_data(e,t,s){var i;const{x_source:n,y_source:r}=this.renderer.coordinates,o=new Set(this._iter_visuals());this._data_size=t.count;for(const s of this.model)if((s instanceof a.VectorSpec||s instanceof a.ScalarSpec)&&!o.has(s))if(s instanceof a.BaseCoordinateSpec){const i=s.array(e);let o=t.select(i);const _=\"x\"==s.dimension?n:r;if(_ instanceof x.FactorRange)if(s instanceof a.CoordinateSpec)o=_.v_synthetic(o);else if(s instanceof a.CoordinateSeqSpec)for(let e=0;e{const s=new Uint32Array(r);for(let a=0;a>1;t[s]>i?e=s:n=s+1}return t[n]}class r extends d.default{get boxes(){return this._boxes}search_indices(i,t,n,e){if(this._pos!==this._boxes.length)throw new Error(\"Data not yet indexed - call index.finish().\");let s=this._boxes.length-4;const d=[],x=new o.Indices(this.numItems);for(;void 0!==s;){const o=Math.min(s+4*this.nodeSize,h(s,this._levelBounds));for(let h=s;h>2],r=this._boxes[h+0],l=this._boxes[h+1],a=this._boxes[h+2],_=this._boxes[h+3];na||t>_||(s<4*this.numItems?x.set(o):d.push(o)))}s=d.pop()}return x}}r.__name__=\"_FlatBush\";class l{constructor(i){this.index=null,i>0&&(this.index=new r(i))}add_rect(i,t,n,e){var s;isFinite(i+t+n+e)?null===(s=this.index)||void 0===s||s.add(i,t,n,e):this.add_empty()}add_point(i,t){var n;isFinite(i+t)?null===(n=this.index)||void 0===n||n.add(i,t,i,t):this.add_empty()}add_empty(){var i;null===(i=this.index)||void 0===i||i.add(1/0,1/0,-1/0,-1/0)}finish(){var i;null===(i=this.index)||void 0===i||i.finish()}_normalize(i){let{x0:t,y0:n,x1:e,y1:s}=i;return t>e&&([t,e]=[e,t]),n>s&&([n,s]=[s,n]),{x0:t,y0:n,x1:e,y1:s}}get bbox(){if(null==this.index)return(0,x.empty)();{const{minX:i,minY:t,maxX:n,maxY:e}=this.index;return{x0:i,y0:t,x1:n,y1:e}}}indices(i){if(null==this.index)return new o.Indices(0);{const{x0:t,y0:n,x1:e,y1:s}=this._normalize(i);return this.index.search_indices(t,n,e,s)}}bounds(i){const t=(0,x.empty)();if(null==this.index)return t;const{boxes:n}=this.index;for(const e of this.indices(i)){const s=n[4*e+0],d=n[4*e+1],o=n[4*e+2],x=n[4*e+3];s>=i.x0&&st.x1&&(t.x1=o),d>=i.y0&&dt.y1&&(t.y1=x)}return t}}n.SpatialIndex=l,l.__name__=\"SpatialIndex\"},\n function _(t,s,i,e,h){e();const n=(0,t(1).__importDefault)(t(183)),o=[Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];class r{static from(t){if(!(t instanceof ArrayBuffer))throw new Error(\"Data must be an instance of ArrayBuffer.\");const[s,i]=new Uint8Array(t,0,2);if(251!==s)throw new Error(\"Data does not appear to be in a Flatbush format.\");if(i>>4!=3)throw new Error(`Got v${i>>4} data when expected v3.`);const[e]=new Uint16Array(t,2,1),[h]=new Uint32Array(t,4,1);return new r(h,e,o[15&i],t)}constructor(t,s=16,i=Float64Array,e){if(void 0===t)throw new Error(\"Missing required argument: numItems.\");if(isNaN(t)||t<=0)throw new Error(`Unpexpected numItems value: ${t}.`);this.numItems=+t,this.nodeSize=Math.min(Math.max(+s,2),65535);let h=t,r=h;this._levelBounds=[4*h];do{h=Math.ceil(h/this.nodeSize),r+=h,this._levelBounds.push(4*r)}while(1!==h);this.ArrayType=i||Float64Array,this.IndexArrayType=r<16384?Uint16Array:Uint32Array;const a=o.indexOf(this.ArrayType),_=4*r*this.ArrayType.BYTES_PER_ELEMENT;if(a<0)throw new Error(`Unexpected typed array class: ${i}.`);e&&e instanceof ArrayBuffer?(this.data=e,this._boxes=new this.ArrayType(this.data,8,4*r),this._indices=new this.IndexArrayType(this.data,8+_,r),this._pos=4*r,this.minX=this._boxes[this._pos-4],this.minY=this._boxes[this._pos-3],this.maxX=this._boxes[this._pos-2],this.maxY=this._boxes[this._pos-1]):(this.data=new ArrayBuffer(8+_+r*this.IndexArrayType.BYTES_PER_ELEMENT),this._boxes=new this.ArrayType(this.data,8,4*r),this._indices=new this.IndexArrayType(this.data,8+_,r),this._pos=0,this.minX=1/0,this.minY=1/0,this.maxX=-1/0,this.maxY=-1/0,new Uint8Array(this.data,0,2).set([251,48+a]),new Uint16Array(this.data,2,1)[0]=s,new Uint32Array(this.data,4,1)[0]=t),this._queue=new n.default}add(t,s,i,e){const h=this._pos>>2;return this._indices[h]=h,this._boxes[this._pos++]=t,this._boxes[this._pos++]=s,this._boxes[this._pos++]=i,this._boxes[this._pos++]=e,tthis.maxX&&(this.maxX=i),e>this.maxY&&(this.maxY=e),h}finish(){if(this._pos>>2!==this.numItems)throw new Error(`Added ${this._pos>>2} items when expected ${this.numItems}.`);if(this.numItems<=this.nodeSize)return this._boxes[this._pos++]=this.minX,this._boxes[this._pos++]=this.minY,this._boxes[this._pos++]=this.maxX,void(this._boxes[this._pos++]=this.maxY);const t=this.maxX-this.minX,s=this.maxY-this.minY,i=new Uint32Array(this.numItems);for(let e=0;e>2]=t,this._boxes[this._pos++]=e,this._boxes[this._pos++]=h,this._boxes[this._pos++]=n,this._boxes[this._pos++]=o}}}search(t,s,i,e,h){if(this._pos!==this._boxes.length)throw new Error(\"Data not yet indexed - call index.finish().\");let n=this._boxes.length-4;const o=[],r=[];for(;void 0!==n;){const a=Math.min(n+4*this.nodeSize,_(n,this._levelBounds));for(let _=n;_>2];ithis._boxes[_+2]||s>this._boxes[_+3]||(n<4*this.numItems?(void 0===h||h(a))&&r.push(a):o.push(a)))}n=o.pop()}return r}neighbors(t,s,i=1/0,e=1/0,h){if(this._pos!==this._boxes.length)throw new Error(\"Data not yet indexed - call index.finish().\");let n=this._boxes.length-4;const o=this._queue,r=[],x=e*e;for(;void 0!==n;){const e=Math.min(n+4*this.nodeSize,_(n,this._levelBounds));for(let i=n;i>2],r=a(t,this._boxes[i],this._boxes[i+2]),_=a(s,this._boxes[i+1],this._boxes[i+3]),x=r*r+_*_;n<4*this.numItems?(void 0===h||h(e))&&o.push(-e-1,x):o.push(e,x)}for(;o.length&&o.peek()<0;){if(o.peekValue()>x)return o.clear(),r;if(r.push(-o.pop()-1),r.length===i)return o.clear(),r}n=o.pop()}return o.clear(),r}}function a(t,s,i){return t>1;s[h]>t?e=h:i=h+1}return s[i]}function x(t,s,i,e,h,n){if(Math.floor(e/n)>=Math.floor(h/n))return;const o=t[e+h>>1];let r=e-1,a=h+1;for(;;){do{r++}while(t[r]o);if(r>=a)break;d(t,s,i,r,a)}x(t,s,i,e,a,n),x(t,s,i,a+1,h,n)}function d(t,s,i,e,h){const n=t[e];t[e]=t[h],t[h]=n;const o=4*e,r=4*h,a=s[o],_=s[o+1],x=s[o+2],d=s[o+3];s[o]=s[r],s[o+1]=s[r+1],s[o+2]=s[r+2],s[o+3]=s[r+3],s[r]=a,s[r+1]=_,s[r+2]=x,s[r+3]=d;const m=i[e];i[e]=i[h],i[h]=m}function m(t,s){let i=t^s,e=65535^i,h=65535^(t|s),n=t&(65535^s),o=i|e>>1,r=i>>1^i,a=h>>1^e&n>>1^h,_=i&h>>1^n>>1^n;i=o,e=r,h=a,n=_,o=i&i>>2^e&e>>2,r=i&e>>2^e&(i^e)>>2,a^=i&h>>2^e&n>>2,_^=e&h>>2^(i^e)&n>>2,i=o,e=r,h=a,n=_,o=i&i>>4^e&e>>4,r=i&e>>4^e&(i^e)>>4,a^=i&h>>4^e&n>>4,_^=e&h>>4^(i^e)&n>>4,i=o,e=r,h=a,n=_,a^=i&h>>8^e&n>>8,_^=e&h>>8^(i^e)&n>>8,i=a^a>>1,e=_^_>>1;let x=t^s,d=e|65535^(x|i);return x=16711935&(x|x<<8),x=252645135&(x|x<<4),x=858993459&(x|x<<2),x=1431655765&(x|x<<1),d=16711935&(d|d<<8),d=252645135&(d|d<<4),d=858993459&(d|d<<2),d=1431655765&(d|d<<1),(d<<1|x)>>>0}i.default=r},\n function _(s,t,i,h,e){h();i.default=class{constructor(){this.ids=[],this.values=[],this.length=0}clear(){this.length=0}push(s,t){let i=this.length++;for(this.ids[i]=s,this.values[i]=t;i>0;){const s=i-1>>1,h=this.values[s];if(t>=h)break;this.ids[i]=this.ids[s],this.values[i]=h,i=s}this.ids[i]=s,this.values[i]=t}pop(){if(0===this.length)return;const s=this.ids[0];if(this.length--,this.length>0){const s=this.ids[0]=this.ids[this.length],t=this.values[0]=this.values[this.length],i=this.length>>1;let h=0;for(;h=t)break;this.ids[h]=e,this.values[h]=l,h=s}this.ids[h]=s,this.values[h]=t}return s}peek(){if(0!==this.length)return this.ids[0]}peekValue(){if(0!==this.length)return this.values[0]}}},\n function _(e,n,a,t,i){t();const l=(0,e(1).__importStar)(e(185));function r(e,n,{x0:a,x1:t,y0:i,y1:l},r){n.save(),n.beginPath(),n.moveTo(a,(i+l)/2),n.lineTo(t,(i+l)/2),e.line.apply(n,r),n.restore()}function c(e,n,{x0:a,x1:t,y0:i,y1:l},r){var c,o;const _=.1*Math.abs(t-a),s=.1*Math.abs(l-i),y=a+_,p=t-_,g=i+s,h=l-s;n.beginPath(),n.rect(y,g,p-y,h-g),e.fill.apply(n,r),null===(c=e.hatch)||void 0===c||c.apply(n,r),null===(o=e.line)||void 0===o||o.apply(n,r)}a.generic_line_scalar_legend=function(e,n,{x0:a,x1:t,y0:i,y1:l}){n.save(),n.beginPath(),n.moveTo(a,(i+l)/2),n.lineTo(t,(i+l)/2),e.line.apply(n),n.restore()},a.generic_line_vector_legend=r,a.generic_line_legend=r,a.generic_area_scalar_legend=function(e,n,{x0:a,x1:t,y0:i,y1:l}){var r,c;const o=.1*Math.abs(t-a),_=.1*Math.abs(l-i),s=a+o,y=t-o,p=i+_,g=l-_;n.beginPath(),n.rect(s,p,y-s,g-p),e.fill.apply(n),null===(r=e.hatch)||void 0===r||r.apply(n),null===(c=e.line)||void 0===c||c.apply(n)},a.generic_area_vector_legend=c,a.generic_area_legend=c,a.line_interpolation=function(e,n,a,t,i,r){const{sx:c,sy:o}=n;let _,s,y,p;\"point\"==n.type?([y,p]=e.yscale.r_invert(o-1,o+1),[_,s]=e.xscale.r_invert(c-1,c+1)):\"v\"==n.direction?([y,p]=e.yscale.r_invert(o,o),[_,s]=[Math.min(a-1,i-1),Math.max(a+1,i+1)]):([_,s]=e.xscale.r_invert(c,c),[y,p]=[Math.min(t-1,r-1),Math.max(t+1,r+1)]);const{x:g,y:h}=l.check_2_segments_intersect(_,y,s,p,a,t,i,r);return[g,h]}},\n function _(t,n,e,i,r){function s(t,n){return(t.x-n.x)**2+(t.y-n.y)**2}function o(t,n,e){const i=s(n,e);if(0==i)return s(t,n);const r=((t.x-n.x)*(e.x-n.x)+(t.y-n.y)*(e.y-n.y))/i;if(r<0)return s(t,n);if(r>1)return s(t,e);return s(t,{x:n.x+r*(e.x-n.x),y:n.y+r*(e.y-n.y)})}i(),e.point_in_poly=function(t,n,e,i){let r=!1,s=e[e.length-1],o=i[i.length-1];for(let u=0;u0&&_<1&&h>0&&h<1,x:t+_*(e-t),y:n+_*(i-n)}}}},\n function _(t,s,e,i,a){i();const l=t(1);var n;const _=t(178),o=t(184),c=(0,l.__importStar)(t(185)),h=(0,l.__importStar)(t(48)),r=t(72);class p extends _.XYGlyphView{_render(t,s,e){const{sx:i,sy:a}=null!=e?e:this;let l=!0;t.beginPath();for(const e of s){const s=i[e],n=a[e];isFinite(s+n)?l?(t.moveTo(s,n),l=!1):t.lineTo(s,n):(t.closePath(),l=!0)}t.closePath(),this.visuals.fill.apply(t),this.visuals.hatch.apply(t),this.visuals.line.apply(t)}draw_legend_for_index(t,s,e){(0,o.generic_area_scalar_legend)(this.visuals,t,s)}_hit_point(t){const s=new r.Selection;return c.point_in_poly(t.sx,t.sy,this.sx,this.sy)&&(s.add_to_selected_glyphs(this.model),s.view=this),s}}e.PatchView=p,p.__name__=\"PatchView\";class d extends _.XYGlyph{constructor(t){super(t)}}e.Patch=d,n=d,d.__name__=\"Patch\",n.prototype.default_view=p,n.mixins([h.LineScalar,h.FillScalar,h.HatchScalar])},\n function _(t,s,e,i,n){i();const h=t(1);var r;const a=t(188),_=(0,h.__importStar)(t(185)),o=(0,h.__importStar)(t(18)),l=t(72);class c extends a.AreaView{_index_data(t){const{min:s,max:e}=Math,{data_size:i}=this;for(let n=0;n=0;s--)t.lineTo(n[s],h[s]);t.closePath(),this.visuals.fill.apply(t),this.visuals.hatch.apply(t)}_hit_point(t){const s=this.sy.length,e=new l.Selection;for(let i=0,n=s-1;i({x1:[o.XCoordinateSpec,{field:\"x1\"}],x2:[o.XCoordinateSpec,{field:\"x2\"}],y:[o.YCoordinateSpec,{field:\"y\"}]})))},\n function _(e,a,r,_,s){_();const n=e(1);var c;const i=e(179),l=e(184),t=(0,n.__importStar)(e(48));class o extends i.GlyphView{draw_legend_for_index(e,a,r){(0,l.generic_area_scalar_legend)(this.visuals,e,a)}}r.AreaView=o,o.__name__=\"AreaView\";class d extends i.Glyph{constructor(e){super(e)}}r.Area=d,c=d,d.__name__=\"Area\",c.mixins([t.FillScalar,t.HatchScalar])},\n function _(t,s,e,i,n){i();const h=t(1);var r;const a=t(188),_=(0,h.__importStar)(t(185)),o=(0,h.__importStar)(t(18)),l=t(72);class c extends a.AreaView{_index_data(t){const{min:s,max:e}=Math,{data_size:i}=this;for(let n=0;n=0;s--)t.lineTo(i[s],h[s]);t.closePath(),this.visuals.fill.apply(t),this.visuals.hatch.apply(t)}scenterxy(t){return[this.sx[t],(this.sy1[t]+this.sy2[t])/2]}_hit_point(t){const s=this.sx.length,e=new l.Selection;for(let i=0,n=s-1;i({x:[o.XCoordinateSpec,{field:\"x\"}],y1:[o.YCoordinateSpec,{field:\"y1\"}],y2:[o.YCoordinateSpec,{field:\"y2\"}]})))},\n function _(e,i,s,t,n){var c;t();const o=e(53),r=e(24),u=e(191),_=e(70);class a extends o.Model{constructor(e){super(e)}initialize(){super.initialize(),this.compute_indices()}connect_signals(){super.connect_signals(),this.connect(this.properties.filters.change,(()=>this.compute_indices()));const e=()=>{const e=()=>this.compute_indices();null!=this.source&&(this.connect(this.source.change,e),this.source instanceof _.ColumnarDataSource&&(this.connect(this.source.streaming,e),this.connect(this.source.patching,e)))};let i=null!=this.source;i?e():this.connect(this.properties.source.change,(()=>{i||(e(),i=!0)}))}compute_indices(){var e;const{source:i}=this;if(null==i)return;const s=null!==(e=i.get_length())&&void 0!==e?e:1,t=r.Indices.all_set(s);for(const e of this.filters)t.intersect(e.compute_indices(i));this.indices=t,this._indices=[...t],this.indices_map_to_subset()}indices_map_to_subset(){this.indices_map={};for(let e=0;ethis._indices[e]))}convert_selection_to_subset(e){return e.map((e=>this.indices_map[e]))}convert_indices_from_subset(e){return e.map((e=>this._indices[e]))}}s.CDSView=a,c=a,a.__name__=\"CDSView\",c.define((({Array:e,Ref:i})=>({filters:[e(i(u.Filter)),[]],source:[i(_.ColumnarDataSource)]}))),c.internal((({Int:e,Dict:i,Ref:s,Nullable:t})=>({indices:[s(r.Indices)],indices_map:[i(e),{}],masked:[t(s(r.Indices)),null]})))},\n function _(e,t,n,s,c){s();const o=e(53);class r extends o.Model{constructor(e){super(e)}}n.Filter=r,r.__name__=\"Filter\"},\n function _(t,r,a,e,c){e(),c(\"BasicTickFormatter\",t(146).BasicTickFormatter),c(\"CategoricalTickFormatter\",t(142).CategoricalTickFormatter),c(\"DatetimeTickFormatter\",t(150).DatetimeTickFormatter),c(\"FuncTickFormatter\",t(193).FuncTickFormatter),c(\"LogTickFormatter\",t(163).LogTickFormatter),c(\"MercatorTickFormatter\",t(166).MercatorTickFormatter),c(\"NumeralTickFormatter\",t(194).NumeralTickFormatter),c(\"PrintfTickFormatter\",t(195).PrintfTickFormatter),c(\"TickFormatter\",t(131).TickFormatter)},\n function _(t,e,n,s,r){var c;s();const i=t(131),a=t(13),u=t(34);class o extends i.TickFormatter{constructor(t){super(t)}get names(){return(0,a.keys)(this.args)}get values(){return(0,a.values)(this.args)}_make_func(){const t=(0,u.use_strict)(this.code);return new Function(\"tick\",\"index\",\"ticks\",...this.names,t)}doFormat(t,e){const n=this._make_func().bind({});return t.map(((t,e,s)=>`${n(t,e,s,...this.values)}`))}}n.FuncTickFormatter=o,c=o,o.__name__=\"FuncTickFormatter\",c.define((({Unknown:t,String:e,Dict:n})=>({args:[n(t),{}],code:[e,\"\"]})))},\n function _(r,n,t,o,e){o();var a;const u=(0,r(1).__importStar)(r(153)),c=r(131),i=r(20);class s extends c.TickFormatter{constructor(r){super(r)}get _rounding_fn(){switch(this.rounding){case\"round\":case\"nearest\":return Math.round;case\"floor\":case\"rounddown\":return Math.floor;case\"ceil\":case\"roundup\":return Math.ceil}}doFormat(r,n){const{format:t,language:o,_rounding_fn:e}=this;return r.map((r=>u.format(r,t,o,e)))}}t.NumeralTickFormatter=s,a=s,s.__name__=\"NumeralTickFormatter\",a.define((({String:r})=>({format:[r,\"0,0\"],language:[r,\"en\"],rounding:[i.RoundingFunction,\"round\"]})))},\n function _(t,r,n,o,a){var e;o();const i=t(131),s=t(152);class c extends i.TickFormatter{constructor(t){super(t)}doFormat(t,r){return t.map((t=>(0,s.sprintf)(this.format,t)))}}n.PrintfTickFormatter=c,e=c,c.__name__=\"PrintfTickFormatter\",e.define((({String:t})=>({format:[t,\"%s\"]})))},\n function _(r,o,a,p,e){p(),e(\"CategoricalColorMapper\",r(197).CategoricalColorMapper),e(\"CategoricalMarkerMapper\",r(199).CategoricalMarkerMapper),e(\"CategoricalPatternMapper\",r(200).CategoricalPatternMapper),e(\"ContinuousColorMapper\",r(172).ContinuousColorMapper),e(\"ColorMapper\",r(173).ColorMapper),e(\"LinearColorMapper\",r(201).LinearColorMapper),e(\"LogColorMapper\",r(202).LogColorMapper),e(\"ScanningColorMapper\",r(171).ScanningColorMapper),e(\"EqHistColorMapper\",r(203).EqHistColorMapper)},\n function _(t,o,r,a,e){var c;a();const s=t(198),l=t(173),n=t(67);class _ extends l.ColorMapper{constructor(t){super(t)}_v_compute(t,o,r,{nan_color:a}){(0,s.cat_v_compute)(t,this.factors,r,o,this.start,this.end,a)}}r.CategoricalColorMapper=_,c=_,_.__name__=\"CategoricalColorMapper\",c.define((({Number:t,Nullable:o})=>({factors:[n.FactorSeq],start:[t,0],end:[o(t),null]})))},\n function _(n,t,e,l,i){l();const c=n(12),u=n(8);function f(n,t){if(n.length!=t.length)return!1;for(let e=0,l=n.length;ef(n,h)))),s=_<0||_>=e.length?r:e[_],l[g]=s}}},\n function _(e,r,a,t,s){var c;t();const l=e(198),n=e(67),u=e(174),o=e(20);class p extends u.Mapper{constructor(e){super(e)}v_compute(e){const r=new Array(e.length);return(0,l.cat_v_compute)(e,this.factors,this.markers,r,this.start,this.end,this.default_value),r}}a.CategoricalMarkerMapper=p,c=p,p.__name__=\"CategoricalMarkerMapper\",c.define((({Number:e,Array:r,Nullable:a})=>({factors:[n.FactorSeq],markers:[r(o.MarkerType)],start:[e,0],end:[a(e),null],default_value:[o.MarkerType,\"circle\"]})))},\n function _(t,e,a,r,n){var s;r();const c=t(198),l=t(67),p=t(174),u=t(20);class o extends p.Mapper{constructor(t){super(t)}v_compute(t){const e=new Array(t.length);return(0,c.cat_v_compute)(t,this.factors,this.patterns,e,this.start,this.end,this.default_value),e}}a.CategoricalPatternMapper=o,s=o,o.__name__=\"CategoricalPatternMapper\",s.define((({Number:t,Array:e,Nullable:a})=>({factors:[l.FactorSeq],patterns:[e(u.HatchPatternType)],start:[t,0],end:[a(t),null],default_value:[u.HatchPatternType,\" \"]})))},\n function _(n,r,o,t,a){t();const e=n(172),i=n(12);class s extends e.ContinuousColorMapper{constructor(n){super(n)}scan(n,r){const o=null!=this.low?this.low:(0,i.min)(n),t=null!=this.high?this.high:(0,i.max)(n);return{max:t,min:o,norm_factor:1/(t-o),normed_interval:1/r}}cmap(n,r,o,t,a){const e=r.length-1;if(n==a.max)return r[e];const i=(n-a.min)*a.norm_factor,s=Math.floor(i/a.normed_interval);return s<0?o:s>e?t:r[s]}}o.LinearColorMapper=s,s.__name__=\"LinearColorMapper\"},\n function _(o,t,n,r,l){r();const a=o(172),s=o(12);class e extends a.ContinuousColorMapper{constructor(o){super(o)}scan(o,t){const n=null!=this.low?this.low:(0,s.min)(o),r=null!=this.high?this.high:(0,s.max)(o);return{max:r,min:n,scale:t/(Math.log(r)-Math.log(n))}}cmap(o,t,n,r,l){const a=t.length-1;if(o>l.max)return r;if(o==l.max)return t[a];if(oa&&(e=a),t[e]}}n.LogColorMapper=e,e.__name__=\"LogColorMapper\"},\n function _(e,n,s,t,l){var i;t();const r=e(171),o=e(12),c=e(9);class a extends r.ScanningColorMapper{constructor(e){super(e)}scan(e,n){let s=null!=this.low?this.low:(0,o.min)(e);const t=null!=this.high?this.high:(0,o.max)(e),l=this.bins,i=(0,c.linspace)(s,t,l+1),r=(0,o.bin_counts)(e,i);let a=0;for(let e=0;e1&&(f=1-n)}const d=(0,c.linspace)(f,1,n+1),g=(0,o.interpolate)(d,p,_);return this.rescale_discrete_levels?s=g[0]:g[0]=s,g[g.length-1]=t,{min:s,max:t,binning:g}}}s.EqHistColorMapper=a,i=a,a.__name__=\"EqHistColorMapper\",i.define((({Boolean:e,Int:n})=>({bins:[n,65536],rescale_discrete_levels:[e,!1]})))},\n function _(a,e,l,c,n){c(),n(\"CategoricalScale\",a(62).CategoricalScale),n(\"ContinuousScale\",a(60).ContinuousScale),n(\"LinearScale\",a(59).LinearScale),n(\"LinearInterpolationScale\",a(205).LinearInterpolationScale),n(\"LogScale\",a(61).LogScale),n(\"Scale\",a(55).Scale)},\n function _(e,r,n,t,a){var i;t();const s=e(55),o=e(59),c=e(12);class _ extends s.Scale{constructor(e){super(e)}connect_signals(){super.connect_signals();const{source_range:e,target_range:r}=this.properties;this.on_change([e,r],(()=>{this.linear_scale=new o.LinearScale({source_range:this.source_range,target_range:this.target_range})}))}get s_compute(){throw new Error(\"not implemented\")}get s_invert(){throw new Error(\"not implemented\")}compute(e){return e}v_compute(e){const{binning:r}=this,{start:n,end:t}=this.source_range,a=n,i=t,s=r.length,o=(t-n)/(s-1),_=new Float64Array(s);for(let e=0;e{if(ei)return i;const n=(0,c.left_edge_index)(e,r);if(-1==n)return a;if(n>=s-1)return i;const t=r[n],o=(e-t)/(r[n+1]-t),l=_[n];return l+o*(_[n+1]-l)}));return this.linear_scale.v_compute(l)}invert(e){return e}v_invert(e){return new Float64Array(e)}}n.LinearInterpolationScale=_,i=_,_.__name__=\"LinearInterpolationScale\",i.internal((({Arrayable:e,Ref:r})=>({binning:[e],linear_scale:[r(o.LinearScale),e=>new o.LinearScale({source_range:e.source_range,target_range:e.target_range})]})))},\n function _(a,n,e,g,R){g(),R(\"DataRange\",a(64).DataRange),R(\"DataRange1d\",a(63).DataRange1d),R(\"FactorRange\",a(67).FactorRange),R(\"Range\",a(57).Range),R(\"Range1d\",a(58).Range1d)},\n function _(a,o,i,t,e){t();var n=a(124);e(\"Sizeable\",n.Sizeable),e(\"SizingPolicy\",n.SizingPolicy);var c=a(125);e(\"Layoutable\",c.Layoutable),e(\"LayoutItem\",c.LayoutItem);var r=a(208);e(\"HStack\",r.HStack),e(\"VStack\",r.VStack);var l=a(209);e(\"Grid\",l.Grid),e(\"Row\",l.Row),e(\"Column\",l.Column);var S=a(210);e(\"ContentBox\",S.ContentBox),e(\"VariadicBox\",S.VariadicBox)},\n function _(t,e,h,i,r){i();const n=t(125),o=t(65);class s extends n.Layoutable{constructor(){super(...arguments),this.children=[]}*[Symbol.iterator](){yield*this.children}}h.Stack=s,s.__name__=\"Stack\";class c extends s{_measure(t){let e=0,h=0;for(const t of this.children){const i=t.measure({width:0,height:0});e+=i.width,h=Math.max(h,i.height)}return{width:e,height:h}}_set_geometry(t,e){super._set_geometry(t,e);const h=this.absolute?t.top:0;let i=this.absolute?t.left:0;const{height:r}=t;for(const t of this.children){const{width:e}=t.measure({width:0,height:0});t.set_geometry(new o.BBox({left:i,width:e,top:h,height:r})),i+=e}}}h.HStack=c,c.__name__=\"HStack\";class a extends s{_measure(t){let e=0,h=0;for(const t of this.children){const i=t.measure({width:0,height:0});e=Math.max(e,i.width),h+=i.height}return{width:e,height:h}}_set_geometry(t,e){super._set_geometry(t,e);const h=this.absolute?t.left:0;let i=this.absolute?t.top:0;const{width:r}=t;for(const t of this.children){const{height:e}=t.measure({width:0,height:0});t.set_geometry(new o.BBox({top:i,height:e,left:h,width:r})),i+=e}}}h.VStack=a,a.__name__=\"VStack\";class l extends n.Layoutable{constructor(){super(...arguments),this.children=[]}*[Symbol.iterator](){yield*this.children}_measure(t){const{width_policy:e,height_policy:h}=this.sizing,{min:i,max:r}=Math;let n=0,o=0;for(const e of this.children){const{width:h,height:i}=e.measure(t);n=r(n,h),o=r(o,i)}return{width:(()=>{const{width:h}=this.sizing;if(t.width==1/0)return\"fixed\"==e&&null!=h?h:n;switch(e){case\"fixed\":return null!=h?h:n;case\"min\":return n;case\"fit\":return null!=h?i(t.width,h):t.width;case\"max\":return null!=h?r(t.width,h):t.width}})(),height:(()=>{const{height:e}=this.sizing;if(t.height==1/0)return\"fixed\"==h&&null!=e?e:o;switch(h){case\"fixed\":return null!=e?e:o;case\"min\":return o;case\"fit\":return null!=e?i(t.height,e):t.height;case\"max\":return null!=e?r(t.height,e):t.height}})()}}_set_geometry(t,e){super._set_geometry(t,e);const h=this.absolute?t:t.relative(),{left:i,right:r,top:n,bottom:s}=h,c=Math.round(h.vcenter),a=Math.round(h.hcenter);for(const e of this.children){const{margin:h,halign:l,valign:d}=e.sizing,{width:u,height:g,inner:_}=e.measure(t),w=(()=>{switch(`${d}_${l}`){case\"start_start\":return new o.BBox({left:i+h.left,top:n+h.top,width:u,height:g});case\"start_center\":return new o.BBox({hcenter:a,top:n+h.top,width:u,height:g});case\"start_end\":return new o.BBox({right:r-h.right,top:n+h.top,width:u,height:g});case\"center_start\":return new o.BBox({left:i+h.left,vcenter:c,width:u,height:g});case\"center_center\":return new o.BBox({hcenter:a,vcenter:c,width:u,height:g});case\"center_end\":return new o.BBox({right:r-h.right,vcenter:c,width:u,height:g});case\"end_start\":return new o.BBox({left:i+h.left,bottom:s-h.bottom,width:u,height:g});case\"end_center\":return new o.BBox({hcenter:a,bottom:s-h.bottom,width:u,height:g});case\"end_end\":return new o.BBox({right:r-h.right,bottom:s-h.bottom,width:u,height:g})}})(),m=null==_?w:new o.BBox({left:w.left+_.left,top:w.top+_.top,right:w.right-_.right,bottom:w.bottom-_.bottom});e.set_geometry(w,m)}}}h.NodeLayout=l,l.__name__=\"NodeLayout\"},\n function _(t,i,s,e,o){e();const n=t(124),l=t(125),r=t(8),h=t(65),c=t(9),{max:a,round:g}=Math;class p{constructor(t){this.def=t,this._map=new Map}get(t){let i=this._map.get(t);return void 0===i&&(i=this.def(),this._map.set(t,i)),i}apply(t,i){const s=this.get(t);this._map.set(t,i(s))}}p.__name__=\"DefaultMap\";class f{constructor(){this._items=[],this._nrows=0,this._ncols=0}get nrows(){return this._nrows}get ncols(){return this._ncols}add(t,i){const{r1:s,c1:e}=t;this._nrows=a(this._nrows,s+1),this._ncols=a(this._ncols,e+1),this._items.push({span:t,data:i})}at(t,i){return this._items.filter((({span:s})=>s.r0<=t&&t<=s.r1&&s.c0<=i&&i<=s.c1)).map((({data:t})=>t))}row(t){return this._items.filter((({span:i})=>i.r0<=t&&t<=i.r1)).map((({data:t})=>t))}col(t){return this._items.filter((({span:i})=>i.c0<=t&&t<=i.c1)).map((({data:t})=>t))}foreach(t){for(const{span:i,data:s}of this._items)t(i,s)}map(t){const i=new f;for(const{span:s,data:e}of this._items)i.add(s,t(s,e));return i}}f.__name__=\"Container\";class _ extends l.Layoutable{constructor(t=[]){super(),this.items=t,this.rows=\"auto\",this.cols=\"auto\",this.spacing=0}*[Symbol.iterator](){for(const{layout:t}of this.items)yield t}is_width_expanding(){if(super.is_width_expanding())return!0;if(\"fixed\"==this.sizing.width_policy)return!1;const{cols:t}=this._state;return(0,c.some)(t,(t=>\"max\"==t.policy))}is_height_expanding(){if(super.is_height_expanding())return!0;if(\"fixed\"==this.sizing.height_policy)return!1;const{rows:t}=this._state;return(0,c.some)(t,(t=>\"max\"==t.policy))}_init(){var t,i,s,e;super._init();const o=new f;for(const{layout:t,row:i,col:s,row_span:e,col_span:n}of this.items)if(t.sizing.visible){const l=i,r=s,h=i+(null!=e?e:1)-1,c=s+(null!=n?n:1)-1;o.add({r0:l,c0:r,r1:h,c1:c},t)}const{nrows:n,ncols:l}=o,h=new Array(n);for(let s=0;s{var t;const i=(0,r.isPlainObject)(this.rows)?null!==(t=this.rows[s])&&void 0!==t?t:this.rows[\"*\"]:this.rows;return null==i?{policy:\"auto\"}:(0,r.isNumber)(i)?{policy:\"fixed\",height:i}:(0,r.isString)(i)?{policy:i}:i})(),n=null!==(t=e.align)&&void 0!==t?t:\"auto\";if(\"fixed\"==e.policy)h[s]={policy:\"fixed\",height:e.height,align:n};else if(\"min\"==e.policy)h[s]={policy:\"min\",align:n};else if(\"fit\"==e.policy||\"max\"==e.policy)h[s]={policy:e.policy,flex:null!==(i=e.flex)&&void 0!==i?i:1,align:n};else{if(\"auto\"!=e.policy)throw new Error(\"unrechable\");(0,c.some)(o.row(s),(t=>t.is_height_expanding()))?h[s]={policy:\"max\",flex:1,align:n}:h[s]={policy:\"min\",align:n}}}const a=new Array(l);for(let t=0;t{var i;const s=(0,r.isPlainObject)(this.cols)?null!==(i=this.cols[t])&&void 0!==i?i:this.cols[\"*\"]:this.cols;return null==s?{policy:\"auto\"}:(0,r.isNumber)(s)?{policy:\"fixed\",width:s}:(0,r.isString)(s)?{policy:s}:s})(),n=null!==(s=i.align)&&void 0!==s?s:\"auto\";if(\"fixed\"==i.policy)a[t]={policy:\"fixed\",width:i.width,align:n};else if(\"min\"==i.policy)a[t]={policy:\"min\",align:n};else if(\"fit\"==i.policy||\"max\"==i.policy)a[t]={policy:i.policy,flex:null!==(e=i.flex)&&void 0!==e?e:1,align:n};else{if(\"auto\"!=i.policy)throw new Error(\"unrechable\");(0,c.some)(o.col(t),(t=>t.is_width_expanding()))?a[t]={policy:\"max\",flex:1,align:n}:a[t]={policy:\"min\",align:n}}}const[g,p]=(0,r.isNumber)(this.spacing)?[this.spacing,this.spacing]:this.spacing;this._state={items:o,nrows:n,ncols:l,rows:h,cols:a,rspacing:g,cspacing:p}}_measure_totals(t,i){const{nrows:s,ncols:e,rspacing:o,cspacing:n}=this._state;return{height:(0,c.sum)(t)+(s-1)*o,width:(0,c.sum)(i)+(e-1)*n}}_measure_cells(t){const{items:i,nrows:s,ncols:e,rows:o,cols:l,rspacing:r,cspacing:h}=this._state,c=new Array(s);for(let t=0;t{const{r0:e,c0:f,r1:d,c1:u}=i,w=(d-e)*r,m=(u-f)*h;let y=0;for(let i=e;i<=d;i++)y+=t(i,f).height;y+=w;let x=0;for(let i=f;i<=u;i++)x+=t(e,i).width;x+=m;const b=s.measure({width:x,height:y});_.add(i,{layout:s,size_hint:b});const z=new n.Sizeable(b).grow_by(s.sizing.margin);z.height-=w,z.width-=m;const v=[];for(let t=e;t<=d;t++){const i=o[t];\"fixed\"==i.policy?z.height-=i.height:v.push(t)}if(z.height>0){const t=g(z.height/v.length);for(const i of v)c[i]=a(c[i],t)}const j=[];for(let t=f;t<=u;t++){const i=l[t];\"fixed\"==i.policy?z.width-=i.width:j.push(t)}if(z.width>0){const t=g(z.width/j.length);for(const i of j)p[i]=a(p[i],t)}}));return{size:this._measure_totals(c,p),row_heights:c,col_widths:p,size_hints:_}}_measure_grid(t){const{nrows:i,ncols:s,rows:e,cols:o,rspacing:n,cspacing:l}=this._state,r=this._measure_cells(((t,i)=>{const s=e[t],n=o[i];return{width:\"fixed\"==n.policy?n.width:1/0,height:\"fixed\"==s.policy?s.height:1/0}}));let h;h=\"fixed\"==this.sizing.height_policy&&null!=this.sizing.height?this.sizing.height:t.height!=1/0&&this.is_height_expanding()?t.height:r.size.height;let c,p=0;for(let t=0;t0)for(let t=0;ti?i:e,t--}}}c=\"fixed\"==this.sizing.width_policy&&null!=this.sizing.width?this.sizing.width:t.width!=1/0&&this.is_width_expanding()?t.width:r.size.width;let f=0;for(let t=0;t0)for(let t=0;ts?s:o,t--}}}const{row_heights:_,col_widths:d,size_hints:u}=this._measure_cells(((t,i)=>({width:r.col_widths[i],height:r.row_heights[t]})));return{size:this._measure_totals(_,d),row_heights:_,col_widths:d,size_hints:u}}_measure(t){const{size:i}=this._measure_grid(t);return i}_set_geometry(t,i){super._set_geometry(t,i);const{nrows:s,ncols:e,rspacing:o,cspacing:n}=this._state,{row_heights:l,col_widths:r,size_hints:c}=this._measure_grid(t),f=this._state.rows.map(((t,i)=>Object.assign(Object.assign({},t),{top:0,height:l[i],get bottom(){return this.top+this.height}}))),_=this._state.cols.map(((t,i)=>Object.assign(Object.assign({},t),{left:0,width:r[i],get right(){return this.left+this.width}}))),d=c.map(((t,i)=>Object.assign(Object.assign({},i),{outer:new h.BBox,inner:new h.BBox})));for(let i=0,e=this.absolute?t.top:0;i{const{layout:r,size_hint:c}=l,{sizing:a}=r,{width:p,height:d}=c,u=function(t,i){let s=(i-t)*n;for(let e=t;e<=i;e++)s+=_[e].width;return s}(i,e),w=function(t,i){let s=(i-t)*o;for(let e=t;e<=i;e++)s+=f[e].height;return s}(t,s),m=i==e&&\"auto\"!=_[i].align?_[i].align:a.halign,y=t==s&&\"auto\"!=f[t].align?f[t].align:a.valign;let x=_[i].left;\"start\"==m?x+=a.margin.left:\"center\"==m?x+=g((u-p)/2):\"end\"==m&&(x+=u-a.margin.right-p);let b=f[t].top;\"start\"==y?b+=a.margin.top:\"center\"==y?b+=g((w-d)/2):\"end\"==y&&(b+=w-a.margin.bottom-d),l.outer=new h.BBox({left:x,top:b,width:p,height:d})}));const u=f.map((()=>({start:new p((()=>0)),end:new p((()=>0))}))),w=_.map((()=>({start:new p((()=>0)),end:new p((()=>0))})));d.foreach((({r0:t,c0:i,r1:s,c1:e},{size_hint:o,outer:n})=>{const{inner:l}=o;null!=l&&(u[t].start.apply(n.top,(t=>a(t,l.top))),u[s].end.apply(f[s].bottom-n.bottom,(t=>a(t,l.bottom))),w[i].start.apply(n.left,(t=>a(t,l.left))),w[e].end.apply(_[e].right-n.right,(t=>a(t,l.right))))})),d.foreach((({r0:t,c0:i,r1:s,c1:e},o)=>{const{size_hint:n,outer:l}=o,r=t=>{const i=this.absolute?l:l.relative(),s=i.left+t.left,e=i.top+t.top,o=i.right-t.right,n=i.bottom-t.bottom;return new h.BBox({left:s,top:e,right:o,bottom:n})};if(null!=n.inner){let h=r(n.inner);if(!1!==n.align){const o=u[t].start.get(l.top),n=u[s].end.get(f[s].bottom-l.bottom),c=w[i].start.get(l.left),a=w[e].end.get(_[e].right-l.right);try{h=r({top:o,bottom:n,left:c,right:a})}catch(t){}}o.inner=h}else o.inner=l})),d.foreach(((t,{layout:i,outer:s,inner:e})=>{i.set_geometry(s,e)}))}}s.Grid=_,_.__name__=\"Grid\";class d extends _{constructor(t){super(),this.items=t.map(((t,i)=>({layout:t,row:0,col:i}))),this.rows=\"fit\"}}s.Row=d,d.__name__=\"Row\";class u extends _{constructor(t){super(),this.items=t.map(((t,i)=>({layout:t,row:i,col:0}))),this.cols=\"fit\"}}s.Column=u,u.__name__=\"Column\"},\n function _(e,t,s,n,i){n();const a=e(125),c=e(124),o=e(43);class r extends a.ContentLayoutable{constructor(e){super(),this.content_size=(0,o.unsized)(e,(()=>new c.Sizeable((0,o.size)(e))))}_content_size(){return this.content_size}}s.ContentBox=r,r.__name__=\"ContentBox\";class _ extends a.Layoutable{constructor(e){super(),this.el=e}_measure(e){const t=new c.Sizeable(e).bounded_to(this.sizing.size);return(0,o.sized)(this.el,t,(()=>{const e=new c.Sizeable((0,o.content_size)(this.el)),{border:t,padding:s}=(0,o.extents)(this.el);return e.grow_by(t).grow_by(s).map(Math.ceil)}))}}s.VariadicBox=_,_.__name__=\"VariadicBox\";class h extends _{constructor(e){super(e),this._cache=new Map}_measure(e){const{width:t,height:s}=e,n=`${t},${s}`;let i=this._cache.get(n);return null==i&&(i=super._measure(e),this._cache.set(n,i)),i}invalidate_cache(){this._cache.clear()}}s.CachedVariadicBox=h,h.__name__=\"CachedVariadicBox\"},\n function _(t,e,i,h,o){h();const s=t(124),r=t(125),n=t(65);class g extends r.Layoutable{constructor(){super(...arguments),this.min_border={left:0,top:0,right:0,bottom:0},this.padding={left:0,top:0,right:0,bottom:0}}*[Symbol.iterator](){yield this.top_panel,yield this.bottom_panel,yield this.left_panel,yield this.right_panel,yield this.center_panel}_measure(t){t=new s.Sizeable({width:\"fixed\"==this.sizing.width_policy||t.width==1/0?this.sizing.width:t.width,height:\"fixed\"==this.sizing.height_policy||t.height==1/0?this.sizing.height:t.height});const e=this.left_panel.measure({width:0,height:t.height}),i=Math.max(e.width,this.min_border.left)+this.padding.left,h=this.right_panel.measure({width:0,height:t.height}),o=Math.max(h.width,this.min_border.right)+this.padding.right,r=this.top_panel.measure({width:t.width,height:0}),n=Math.max(r.height,this.min_border.top)+this.padding.top,g=this.bottom_panel.measure({width:t.width,height:0}),a=Math.max(g.height,this.min_border.bottom)+this.padding.bottom,d=new s.Sizeable(t).shrink_by({left:i,right:o,top:n,bottom:a}),l=this.center_panel.measure(d);return{width:i+l.width+o,height:n+l.height+a,inner:{left:i,right:o,top:n,bottom:a},align:(()=>{const{width_policy:t,height_policy:e}=this.center_panel.sizing;return\"fixed\"!=t&&\"fixed\"!=e})()}}_set_geometry(t,e){super._set_geometry(t,e),this.center_panel.set_geometry(e);const i=this.left_panel.measure({width:0,height:t.height}),h=this.right_panel.measure({width:0,height:t.height}),o=this.top_panel.measure({width:t.width,height:0}),s=this.bottom_panel.measure({width:t.width,height:0}),{left:r,top:g,right:a,bottom:d}=e;this.top_panel.set_geometry(new n.BBox({left:r,right:a,bottom:g,height:o.height})),this.bottom_panel.set_geometry(new n.BBox({left:r,right:a,top:d,height:s.height})),this.left_panel.set_geometry(new n.BBox({top:g,bottom:d,right:r,width:i.width})),this.right_panel.set_geometry(new n.BBox({top:g,bottom:d,left:a,width:h.width}))}}i.BorderLayout=g,g.__name__=\"BorderLayout\"},\n function _(t,e,i,s,l){s();const n=t(1);var o;const a=t(119),_=t(10),d=t(20),h=t(120),r=t(123),u=(0,n.__importStar)(t(48));class c extends a.TextAnnotationView{update_layout(){const{panel:t}=this;this.layout=null!=t?new r.SideLayout(t,(()=>this.get_size()),!1):void 0}_get_size(){const{text:t}=this.model,e=new h.TextBox({text:t}),{angle:i,angle_units:s}=this.model;e.angle=(0,_.resolve_angle)(i,s),e.visuals=this.visuals.text.values();const{width:l,height:n}=e.size();return{width:l,height:n}}_render(){const{angle:t,angle_units:e}=this.model,i=(0,_.resolve_angle)(t,e),s=null!=this.layout?this.layout:this.plot_view.frame,l=this.coordinates.x_scale,n=this.coordinates.y_scale;let o=\"data\"==this.model.x_units?l.compute(this.model.x):s.bbox.xview.compute(this.model.x),a=\"data\"==this.model.y_units?n.compute(this.model.y):s.bbox.yview.compute(this.model.y);o+=this.model.x_offset,a-=this.model.y_offset;(\"canvas\"==this.model.render_mode?this._canvas_text.bind(this):this._css_text.bind(this))(this.layer.ctx,this.model.text,o,a,i)}}i.LabelView=c,c.__name__=\"LabelView\";class x extends a.TextAnnotation{constructor(t){super(t)}}i.Label=x,o=x,x.__name__=\"Label\",o.prototype.default_view=c,o.mixins([u.Text,[\"border_\",u.Line],[\"background_\",u.Fill]]),o.define((({Number:t,String:e,Angle:i})=>({x:[t],x_units:[d.SpatialUnits,\"data\"],y:[t],y_units:[d.SpatialUnits,\"data\"],text:[e,\"\"],angle:[i,0],angle_units:[d.AngleUnits,\"rad\"],x_offset:[t,0],y_offset:[t,0]}))),o.override({background_fill_color:null,border_line_color:null})},\n function _(t,e,s,i,l){i();const o=t(1);var a;const r=t(69),n=(0,o.__importStar)(t(48)),d=t(20),_=t(43),c=t(120),h=(0,o.__importStar)(t(18)),u=t(11);class v extends r.DataAnnotationView{set_data(t){var e;if(super.set_data(t),null===(e=this.els)||void 0===e||e.forEach((t=>(0,_.remove)(t))),\"css\"==this.model.render_mode){const t=this.els=[...this.text].map((()=>(0,_.div)({style:{display:\"none\"}})));for(const e of t)this.plot_view.canvas_view.add_overlay(e)}else delete this.els}remove(){var t;null===(t=this.els)||void 0===t||t.forEach((t=>(0,_.remove)(t))),super.remove()}_rerender(){\"css\"==this.model.render_mode?this.render():this.request_render()}map_data(){const{x_scale:t,y_scale:e}=this.coordinates,s=null!=this.layout?this.layout:this.plot_view.frame;this.sx=\"data\"==this.model.x_units?t.v_compute(this._x):s.bbox.xview.v_compute(this._x),this.sy=\"data\"==this.model.y_units?e.v_compute(this._y):s.bbox.yview.v_compute(this._y)}paint(){const t=\"canvas\"==this.model.render_mode?this._v_canvas_text.bind(this):this._v_css_text.bind(this),{ctx:e}=this.layer;for(let s=0,i=this.text.length;s{switch(this.visuals.text.text_align.get(e)){case\"left\":return[\"left\",\"0%\"];case\"center\":return[\"center\",\"-50%\"];case\"right\":return[\"right\",\"-100%\"]}})(),[d,c]=(()=>{switch(this.visuals.text.text_baseline.get(e)){case\"top\":return[\"top\",\"0%\"];case\"middle\":return[\"center\",\"-50%\"];case\"bottom\":return[\"bottom\",\"-100%\"];default:return[\"center\",\"-50%\"]}})();let h=`translate(${n}, ${c})`;o&&(h+=`rotate(${o}rad)`),a.style.transformOrigin=`${r} ${d}`,a.style.transform=h,this.layout,this.visuals.background_fill.doit&&(this.visuals.background_fill.set_vectorize(t,e),a.style.backgroundColor=t.fillStyle),this.visuals.border_line.doit&&(this.visuals.border_line.set_vectorize(t,e),a.style.borderStyle=t.lineDash.length<2?\"solid\":\"dashed\",a.style.borderWidth=`${t.lineWidth}px`,a.style.borderColor=t.strokeStyle),(0,_.display)(a)}}s.LabelSetView=v,v.__name__=\"LabelSetView\";class x extends r.DataAnnotation{constructor(t){super(t)}}s.LabelSet=x,a=x,x.__name__=\"LabelSet\",a.prototype.default_view=v,a.mixins([n.TextVector,[\"border_\",n.LineVector],[\"background_\",n.FillVector]]),a.define((()=>({x:[h.XCoordinateSpec,{field:\"x\"}],y:[h.YCoordinateSpec,{field:\"y\"}],x_units:[d.SpatialUnits,\"data\"],y_units:[d.SpatialUnits,\"data\"],text:[h.StringSpec,{field:\"text\"}],angle:[h.AngleSpec,0],x_offset:[h.NumberSpec,{value:0}],y_offset:[h.NumberSpec,{value:0}],render_mode:[d.RenderMode,\"canvas\"]}))),a.override({background_fill_color:null,border_line_color:null})},\n function _(t,e,i,l,s){l();const n=t(1);var o;const h=t(40),a=t(215),_=t(20),r=(0,n.__importStar)(t(48)),d=t(15),c=t(123),g=t(121),m=t(65),b=t(9),f=t(8),u=t(11);class x extends h.AnnotationView{update_layout(){const{panel:t}=this;this.layout=null!=t?new c.SideLayout(t,(()=>this.get_size())):void 0}cursor(t,e){return\"none\"==this.model.click_policy?null:\"pointer\"}get legend_padding(){return null!=this.model.border_line_color?this.model.padding:0}connect_signals(){super.connect_signals(),this.connect(this.model.change,(()=>this.request_render())),this.connect(this.model.item_change,(()=>this.request_render()))}compute_legend_bbox(){const t=this.model.get_legend_names(),{glyph_height:e,glyph_width:i}=this.model,{label_height:l,label_width:s}=this.model;this.max_label_height=(0,b.max)([(0,g.font_metrics)(this.visuals.label_text.font_value()).height,l,e]);const{ctx:n}=this.layer;n.save(),this.visuals.label_text.set_value(n),this.text_widths=new Map;for(const e of t)this.text_widths.set(e,(0,b.max)([n.measureText(e).width,s]));this.visuals.title_text.set_value(n),this.title_height=this.model.title?(0,g.font_metrics)(this.visuals.title_text.font_value()).height+this.model.title_standoff:0,this.title_width=this.model.title?n.measureText(this.model.title).width:0,n.restore();const o=Math.max((0,b.max)([...this.text_widths.values()]),0),h=this.model.margin,{legend_padding:a}=this,_=this.model.spacing,{label_standoff:r}=this.model;let d,c;if(\"vertical\"==this.model.orientation)d=t.length*this.max_label_height+Math.max(t.length-1,0)*_+2*a+this.title_height,c=(0,b.max)([o+i+r+2*a,this.title_width+2*a]);else{let e=2*a+Math.max(t.length-1,0)*_;for(const[,t]of this.text_widths)e+=(0,b.max)([t,s])+i+r;c=(0,b.max)([this.title_width+2*a,e]),d=this.max_label_height+this.title_height+2*a}const x=null!=this.layout?this.layout:this.plot_view.frame,[p,w]=x.bbox.ranges,{location:v}=this.model;let y,k;if((0,f.isString)(v))switch(v){case\"top_left\":y=p.start+h,k=w.start+h;break;case\"top\":case\"top_center\":y=(p.end+p.start)/2-c/2,k=w.start+h;break;case\"top_right\":y=p.end-h-c,k=w.start+h;break;case\"bottom_right\":y=p.end-h-c,k=w.end-h-d;break;case\"bottom\":case\"bottom_center\":y=(p.end+p.start)/2-c/2,k=w.end-h-d;break;case\"bottom_left\":y=p.start+h,k=w.end-h-d;break;case\"left\":case\"center_left\":y=p.start+h,k=(w.end+w.start)/2-d/2;break;case\"center\":case\"center_center\":y=(p.end+p.start)/2-c/2,k=(w.end+w.start)/2-d/2;break;case\"right\":case\"center_right\":y=p.end-h-c,k=(w.end+w.start)/2-d/2}else if((0,f.isArray)(v)&&2==v.length){const[t,e]=v;y=x.bbox.xview.compute(t),k=x.bbox.yview.compute(e)-d}else(0,u.unreachable)();return new m.BBox({left:y,top:k,width:c,height:d})}interactive_bbox(){return this.compute_legend_bbox()}interactive_hit(t,e){return this.interactive_bbox().contains(t,e)}on_hit(t,e){let i;const{glyph_width:l}=this.model,{legend_padding:s}=this,n=this.model.spacing,{label_standoff:o}=this.model;let h=i=s;const a=this.compute_legend_bbox(),_=\"vertical\"==this.model.orientation;for(const r of this.model.items){const d=r.get_labels_list_from_label_prop();for(const c of d){const d=a.x+h,g=a.y+i+this.title_height;let b,f;[b,f]=_?[a.width-2*s,this.max_label_height]:[this.text_widths.get(c)+l+o,this.max_label_height];if(new m.BBox({left:d,top:g,width:b,height:f}).contains(t,e)){switch(this.model.click_policy){case\"hide\":for(const t of r.renderers)t.visible=!t.visible;break;case\"mute\":for(const t of r.renderers)t.muted=!t.muted}return!0}_?i+=this.max_label_height+n:h+=this.text_widths.get(c)+l+o+n}}return!1}_render(){if(0==this.model.items.length)return;if(!(0,b.some)(this.model.items,(t=>t.visible)))return;for(const t of this.model.items)t.legend=this.model;const{ctx:t}=this.layer,e=this.compute_legend_bbox();t.save(),this._draw_legend_box(t,e),this._draw_legend_items(t,e),this._draw_title(t,e),t.restore()}_draw_legend_box(t,e){t.beginPath(),t.rect(e.x,e.y,e.width,e.height),this.visuals.background_fill.apply(t),this.visuals.border_line.apply(t)}_draw_legend_items(t,e){const{glyph_width:i,glyph_height:l}=this.model,{legend_padding:s}=this,n=this.model.spacing,{label_standoff:o}=this.model;let h=s,a=s;const _=\"vertical\"==this.model.orientation;for(const r of this.model.items){if(!r.visible)continue;const d=r.get_labels_list_from_label_prop(),c=r.get_field_from_label_prop();if(0==d.length)continue;const g=(()=>{switch(this.model.click_policy){case\"none\":return!0;case\"hide\":return(0,b.every)(r.renderers,(t=>t.visible));case\"mute\":return(0,b.every)(r.renderers,(t=>!t.muted))}})();for(const m of d){const d=e.x+h,b=e.y+a+this.title_height,f=d+i,u=b+l;_?a+=this.max_label_height+n:h+=this.text_widths.get(m)+i+o+n,this.visuals.label_text.set_value(t),t.fillText(m,f+o,b+this.max_label_height/2);for(const e of r.renderers){const i=this.plot_view.renderer_view(e);null==i||i.draw_legend(t,d,f,b,u,c,m,r.index)}if(!g){let l,n;[l,n]=_?[e.width-2*s,this.max_label_height]:[this.text_widths.get(m)+i+o,this.max_label_height],t.beginPath(),t.rect(d,b,l,n),this.visuals.inactive_fill.set_value(t),t.fill()}}}}_draw_title(t,e){const{title:i}=this.model;i&&this.visuals.title_text.doit&&(t.save(),t.translate(e.x0,e.y0+this.title_height),this.visuals.title_text.set_value(t),t.fillText(i,this.legend_padding,this.legend_padding-this.model.title_standoff),t.restore())}_get_size(){const{width:t,height:e}=this.compute_legend_bbox();return{width:t+2*this.model.margin,height:e+2*this.model.margin}}}i.LegendView=x,x.__name__=\"LegendView\";class p extends h.Annotation{constructor(t){super(t)}initialize(){super.initialize(),this.item_change=new d.Signal0(this,\"item_change\")}get_legend_names(){const t=[];for(const e of this.items){const i=e.get_labels_list_from_label_prop();t.push(...i)}return t}}i.Legend=p,o=p,p.__name__=\"Legend\",o.prototype.default_view=x,o.mixins([[\"label_\",r.Text],[\"title_\",r.Text],[\"inactive_\",r.Fill],[\"border_\",r.Line],[\"background_\",r.Fill]]),o.define((({Number:t,String:e,Array:i,Tuple:l,Or:s,Ref:n,Nullable:o})=>({orientation:[_.Orientation,\"vertical\"],location:[s(_.LegendLocation,l(t,t)),\"top_right\"],title:[o(e),null],title_standoff:[t,5],label_standoff:[t,5],glyph_height:[t,20],glyph_width:[t,20],label_height:[t,20],label_width:[t,20],margin:[t,10],padding:[t,10],spacing:[t,3],items:[i(n(a.LegendItem)),[]],click_policy:[_.LegendClickPolicy,\"none\"]}))),o.override({border_line_color:\"#e5e5e5\",border_line_alpha:.5,border_line_width:1,background_fill_color:\"#ffffff\",background_fill_alpha:.95,inactive_fill_color:\"white\",inactive_fill_alpha:.7,label_text_font_size:\"13px\",label_text_baseline:\"middle\",title_text_font_size:\"13px\",title_text_font_style:\"italic\"})},\n function _(e,r,l,n,t){n();const i=e(1);var s;const o=e(53),a=e(175),_=e(70),u=e(216),d=(0,i.__importStar)(e(18)),c=e(19),f=e(9);class h extends o.Model{constructor(e){super(e)}_check_data_sources_on_renderers(){if(null!=this.get_field_from_label_prop()){if(this.renderers.length<1)return!1;const e=this.renderers[0].data_source;if(null!=e)for(const r of this.renderers)if(r.data_source!=e)return!1}return!0}_check_field_label_on_data_source(){const e=this.get_field_from_label_prop();if(null!=e){if(this.renderers.length<1)return!1;const r=this.renderers[0].data_source;if(null!=r&&!(0,f.includes)(r.columns(),e))return!1}return!0}initialize(){super.initialize(),this.legend=null,this.connect(this.change,(()=>{var e;return null===(e=this.legend)||void 0===e?void 0:e.item_change.emit()}));this._check_data_sources_on_renderers()||c.logger.error(\"Non matching data sources on legend item renderers\");this._check_field_label_on_data_source()||c.logger.error(`Bad column name on label: ${this.label}`)}get_field_from_label_prop(){const{label:e}=this;return(0,u.isField)(e)?e.field:null}get_labels_list_from_label_prop(){if(!this.visible)return[];if((0,u.isValue)(this.label)){const{value:e}=this.label;return null!=e?[e]:[]}const e=this.get_field_from_label_prop();if(null!=e){let r;if(!this.renderers[0]||null==this.renderers[0].data_source)return[\"No source found\"];if(r=this.renderers[0].data_source,r instanceof _.ColumnarDataSource){const l=r.get_column(e);return null!=l?(0,f.uniq)(Array.from(l)):[\"Invalid field\"]}}return[]}}l.LegendItem=h,s=h,h.__name__=\"LegendItem\",s.define((({Boolean:e,Int:r,Array:l,Ref:n,Nullable:t})=>({label:[d.NullStringSpec,null],renderers:[l(n(a.GlyphRenderer)),[]],index:[t(r),null],visible:[e,!0]})))},\n function _(i,n,e,t,u){t();const c=i(8);e.isValue=function(i){return(0,c.isPlainObject)(i)&&\"value\"in i},e.isField=function(i){return(0,c.isPlainObject)(i)&&\"field\"in i},e.isExpr=function(i){return(0,c.isPlainObject)(i)&&\"expr\"in i}},\n function _(t,n,e,s,i){s();const o=t(1);var a;const l=t(40),c=(0,o.__importStar)(t(48)),r=t(20);class _ extends l.AnnotationView{connect_signals(){super.connect_signals(),this.connect(this.model.change,(()=>this.request_render()))}_render(){const{xs:t,ys:n}=this.model;if(t.length!=n.length)return;const e=t.length;if(e<3)return;const{frame:s}=this.plot_view,{ctx:i}=this.layer,o=this.coordinates.x_scale,a=this.coordinates.y_scale,{screen:l}=this.model;function c(t,n,e,s){return l?t:\"data\"==n?e.v_compute(t):s.v_compute(t)}const r=c(t,this.model.xs_units,o,s.bbox.xview),_=c(n,this.model.ys_units,a,s.bbox.yview);i.beginPath();for(let t=0;t({xs:[n(t),[]],xs_units:[r.SpatialUnits,\"data\"],ys:[n(t),[]],ys_units:[r.SpatialUnits,\"data\"]}))),a.internal((({Boolean:t})=>({screen:[t,!1]}))),a.override({fill_color:\"#fff9ba\",fill_alpha:.4,line_color:\"#cccccc\",line_alpha:.3})},\n function _(e,t,n,o,i){o();const s=e(1);var l;const r=e(40),c=(0,s.__importStar)(e(48));class a extends r.AnnotationView{connect_signals(){super.connect_signals(),this.connect(this.model.change,(()=>this.request_render()))}_render(){const{gradient:e,y_intercept:t}=this.model;if(null==e||null==t)return;const{frame:n}=this.plot_view,o=this.coordinates.x_scale,i=this.coordinates.y_scale;let s,l,r,c;if(0==e)s=i.compute(t),l=s,r=n.bbox.left,c=r+n.bbox.width;else{s=n.bbox.top,l=s+n.bbox.height;const a=(i.invert(s)-t)/e,_=(i.invert(l)-t)/e;r=o.compute(a),c=o.compute(_)}const{ctx:a}=this.layer;a.save(),a.beginPath(),this.visuals.line.set_value(a),a.moveTo(r,s),a.lineTo(c,l),a.stroke(),a.restore()}}n.SlopeView=a,a.__name__=\"SlopeView\";class _ extends r.Annotation{constructor(e){super(e)}}n.Slope=_,l=_,_.__name__=\"Slope\",l.prototype.default_view=a,l.mixins(c.Line),l.define((({Number:e,Nullable:t})=>({gradient:[t(e),null],y_intercept:[t(e),null]}))),l.override({line_color:\"black\"})},\n function _(e,t,i,o,n){o();const s=e(1);var l;const a=e(40),r=(0,s.__importStar)(e(48)),c=e(20);class d extends a.AnnotationView{connect_signals(){super.connect_signals(),this.connect(this.model.change,(()=>this.plot_view.request_paint(this)))}_render(){const{location:e}=this.model;if(null==e)return;const{frame:t}=this.plot_view,i=this.coordinates.x_scale,o=this.coordinates.y_scale,n=(t,i)=>\"data\"==this.model.location_units?t.compute(e):this.model.for_hover?e:i.compute(e);let s,l,a,r;\"width\"==this.model.dimension?(a=n(o,t.bbox.yview),l=t.bbox.left,r=t.bbox.width,s=this.model.line_width):(a=t.bbox.top,l=n(i,t.bbox.xview),r=this.model.line_width,s=t.bbox.height);const{ctx:c}=this.layer;c.save(),c.beginPath(),this.visuals.line.set_value(c),c.moveTo(l,a),\"width\"==this.model.dimension?c.lineTo(l+r,a):c.lineTo(l,a+s),c.stroke(),c.restore()}}i.SpanView=d,d.__name__=\"SpanView\";class _ extends a.Annotation{constructor(e){super(e)}}i.Span=_,l=_,_.__name__=\"Span\",l.prototype.default_view=d,l.mixins(r.Line),l.define((({Number:e,Nullable:t})=>({render_mode:[c.RenderMode,\"canvas\"],location:[t(e),null],location_units:[c.SpatialUnits,\"data\"],dimension:[c.Dimension,\"width\"]}))),l.internal((({Boolean:e})=>({for_hover:[e,!1]}))),l.override({line_color:\"black\"})},\n function _(i,e,t,o,l){var s;o();const a=i(40),_=i(221),n=i(113),r=i(43),h=i(123),b=i(65);class v extends a.AnnotationView{constructor(){super(...arguments),this._invalidate_toolbar=!0,this._previous_bbox=new b.BBox}update_layout(){this.layout=new h.SideLayout(this.panel,(()=>this.get_size()),!0)}initialize(){super.initialize(),this.el=(0,r.div)(),this.plot_view.canvas_view.add_event(this.el)}async lazy_initialize(){await super.lazy_initialize(),this._toolbar_view=await(0,n.build_view)(this.model.toolbar,{parent:this}),this.plot_view.visibility_callbacks.push((i=>this._toolbar_view.set_visibility(i)))}remove(){this._toolbar_view.remove(),(0,r.remove)(this.el),super.remove()}render(){this.model.visible||(0,r.undisplay)(this.el),super.render()}_render(){const{bbox:i}=this.layout;this._previous_bbox.equals(i)||((0,r.position)(this.el,i),this._previous_bbox=i,this._invalidate_toolbar=!0),this._invalidate_toolbar&&(this.el.style.position=\"absolute\",this.el.style.overflow=\"hidden\",(0,r.empty)(this.el),this.el.appendChild(this._toolbar_view.el),this._toolbar_view.layout.bbox=i,this._toolbar_view.render(),this._invalidate_toolbar=!1),(0,r.display)(this.el)}_get_size(){const{tools:i,logo:e}=this.model.toolbar;return{width:30*i.length+(null!=e?25:0)+15,height:30}}}t.ToolbarPanelView=v,v.__name__=\"ToolbarPanelView\";class d extends a.Annotation{constructor(i){super(i)}}t.ToolbarPanel=d,s=d,d.__name__=\"ToolbarPanel\",s.prototype.default_view=v,s.define((({Ref:i})=>({toolbar:[i(_.Toolbar)]})))},\n function _(t,e,s,i,o){var c;i();const n=t(8),a=t(9),l=t(13),r=t(222),_=t(223),u=t(232),p=t(233);function v(t){switch(t){case\"tap\":return\"active_tap\";case\"pan\":return\"active_drag\";case\"pinch\":case\"scroll\":return\"active_scroll\";case\"multi\":return\"active_multi\"}return null}function h(t){return\"tap\"==t||\"pan\"==t}s.Drag=r.Tool,s.Inspection=r.Tool,s.Scroll=r.Tool,s.Tap=r.Tool;class f extends p.ToolbarBase{constructor(t){super(t)}connect_signals(){super.connect_signals();const{tools:t,active_drag:e,active_inspect:s,active_scroll:i,active_tap:o,active_multi:c}=this.properties;this.on_change([t,e,s,i,o,c],(()=>this._init_tools()))}_init_tools(){if(super._init_tools(),\"auto\"==this.active_inspect);else if(this.active_inspect instanceof u.InspectTool){let t=!1;for(const e of this.inspectors)e!=this.active_inspect?e.active=!1:t=!0;t||(this.active_inspect=null)}else if((0,n.isArray)(this.active_inspect)){const t=(0,a.intersection)(this.active_inspect,this.inspectors);t.length!=this.active_inspect.length&&(this.active_inspect=t);for(const t of this.inspectors)(0,a.includes)(this.active_inspect,t)||(t.active=!1)}else if(null==this.active_inspect)for(const t of this.inspectors)t.active=!1;const t=t=>{t.active?this._active_change(t):t.active=!0};for(const t of(0,l.values)(this.gestures)){t.tools=(0,a.sort_by)(t.tools,(t=>t.default_order));for(const e of t.tools)this.connect(e.properties.active.change,(()=>this._active_change(e)))}for(const[e,s]of(0,l.entries)(this.gestures)){const i=v(e);if(i){const o=this[i];\"auto\"==o?0!=s.tools.length&&h(e)&&t(s.tools[0]):null!=o&&((0,a.includes)(this.tools,o)?t(o):this[i]=null)}}}}s.Toolbar=f,c=f,f.__name__=\"Toolbar\",c.prototype.default_view=p.ToolbarBaseView,c.define((({Or:t,Ref:e,Auto:i,Null:o})=>({active_drag:[t(e(s.Drag),i,o),\"auto\"],active_inspect:[t(e(s.Inspection),i,o),\"auto\"],active_scroll:[t(e(s.Scroll),i,o),\"auto\"],active_tap:[t(e(s.Tap),i,o),\"auto\"],active_multi:[t(e(_.GestureTool),i,o),\"auto\"]})))},\n function _(t,e,n,o,s){var i;o();const a=t(42),r=t(9),l=t(53);class c extends a.View{get plot_view(){return this.parent}get plot_model(){return this.parent.model}connect_signals(){super.connect_signals(),this.connect(this.model.properties.active.change,(()=>{this.model.active?this.activate():this.deactivate()}))}activate(){}deactivate(){}}n.ToolView=c,c.__name__=\"ToolView\";class _ extends l.Model{constructor(t){super(t)}get synthetic_renderers(){return[]}_get_dim_limits([t,e],[n,o],s,i){const a=s.bbox.h_range;let l;\"width\"==i||\"both\"==i?(l=[(0,r.min)([t,n]),(0,r.max)([t,n])],l=[(0,r.max)([l[0],a.start]),(0,r.min)([l[1],a.end])]):l=[a.start,a.end];const c=s.bbox.v_range;let _;return\"height\"==i||\"both\"==i?(_=[(0,r.min)([e,o]),(0,r.max)([e,o])],_=[(0,r.max)([_[0],c.start]),(0,r.min)([_[1],c.end])]):_=[c.start,c.end],[l,_]}static register_alias(t,e){this.prototype._known_aliases.set(t,e)}static from_string(t){const e=this.prototype._known_aliases.get(t);if(null!=e)return e();{const e=[...this.prototype._known_aliases.keys()];throw new Error(`unexpected tool name '${t}', possible tools are ${e.join(\", \")}`)}}}n.Tool=_,i=_,_.__name__=\"Tool\",i.prototype._known_aliases=new Map,i.define((({String:t,Nullable:e})=>({description:[e(t),null]}))),i.internal((({Boolean:t})=>({active:[t,!1]})))},\n function _(e,o,t,s,n){s();const u=e(224),_=e(231);class l extends u.ButtonToolView{}t.GestureToolView=l,l.__name__=\"GestureToolView\";class i extends u.ButtonTool{constructor(e){super(e),this.button_view=_.OnOffButtonView}}t.GestureTool=i,i.__name__=\"GestureTool\"},\n function _(t,e,o,s,i){s();const n=t(1);var l;const r=(0,n.__importDefault)(t(225)),a=t(226),u=t(222),h=t(43),_=t(34),d=t(8),c=t(9),m=(0,n.__importStar)(t(227)),p=m,v=(0,n.__importDefault)(t(228)),f=(0,n.__importDefault)(t(229)),g=t(230);class b extends a.DOMView{initialize(){super.initialize();const t=this.model.menu;if(null!=t){const e=this.parent.model.toolbar_location,o=\"left\"==e||\"above\"==e,s=this.parent.model.horizontal?\"vertical\":\"horizontal\";this._menu=new g.ContextMenu(o?(0,c.reversed)(t):t,{orientation:s,prevent_hide:t=>t.target==this.el})}this._hammer=new r.default(this.el,{touchAction:\"auto\",inputClass:r.default.TouchMouseInput}),this.connect(this.model.change,(()=>this.render())),this._hammer.on(\"tap\",(t=>{var e;(null===(e=this._menu)||void 0===e?void 0:e.is_open)?this._menu.hide():t.target==this.el&&this._clicked()})),this._hammer.on(\"press\",(()=>this._pressed())),this.el.addEventListener(\"keydown\",(t=>{t.keyCode==h.Keys.Enter&&this._clicked()}))}remove(){var t;this._hammer.destroy(),null===(t=this._menu)||void 0===t||t.remove(),super.remove()}styles(){return[...super.styles(),m.default,v.default,f.default]}css_classes(){return super.css_classes().concat(p.toolbar_button)}render(){(0,h.empty)(this.el);const t=this.model.computed_icon;(0,d.isString)(t)&&((0,_.startsWith)(t,\"data:image\")?this.el.style.backgroundImage=`url(\"${t}\")`:this.el.classList.add(t)),this.el.title=this.model.tooltip,this.el.tabIndex=0,null!=this._menu&&this.root.el.appendChild(this._menu.el)}_pressed(){var t;const e=(()=>{switch(this.parent.model.toolbar_location){case\"right\":return{left_of:this.el};case\"left\":return{right_of:this.el};case\"above\":return{below:this.el};case\"below\":return{above:this.el}}})();null===(t=this._menu)||void 0===t||t.toggle(e)}}o.ButtonToolButtonView=b,b.__name__=\"ButtonToolButtonView\";class w extends u.ToolView{}o.ButtonToolView=w,w.__name__=\"ButtonToolView\";class y extends u.Tool{constructor(t){super(t)}_get_dim_tooltip(t){const{description:e,tool_name:o}=this;return null!=e?e:\"both\"==t?o:`${o} (${\"width\"==t?\"x\":\"y\"}-axis)`}get tooltip(){var t;return null!==(t=this.description)&&void 0!==t?t:this.tool_name}get computed_icon(){return this.icon}get menu(){return null}}o.ButtonTool=y,l=y,y.__name__=\"ButtonTool\",l.internal((({Boolean:t})=>({disabled:[t,!1]})))},\n function _(t,e,i,n,r){\n /*! Hammer.JS - v2.0.7 - 2016-04-22\n * http://hammerjs.github.io/\n *\n * Copyright (c) 2016 Jorik Tangelder;\n * Licensed under the MIT license */\n !function(t,i,n,r){\"use strict\";var s,o=[\"\",\"webkit\",\"Moz\",\"MS\",\"ms\",\"o\"],a=i.createElement(\"div\"),h=Math.round,u=Math.abs,c=Date.now;function l(t,e,i){return setTimeout(T(t,i),e)}function p(t,e,i){return!!Array.isArray(t)&&(f(t,i[e],i),!0)}function f(t,e,i){var n;if(t)if(t.forEach)t.forEach(e,i);else if(t.length!==r)for(n=0;n\\s*\\(/gm,\"{anonymous}()@\"):\"Unknown Stack Trace\",s=t.console&&(t.console.warn||t.console.log);return s&&s.call(t.console,r,n),e.apply(this,arguments)}}s=\"function\"!=typeof Object.assign?function(t){if(t===r||null===t)throw new TypeError(\"Cannot convert undefined or null to object\");for(var e=Object(t),i=1;i-1}function S(t){return t.trim().split(/\\s+/g)}function b(t,e,i){if(t.indexOf&&!i)return t.indexOf(e);for(var n=0;ni[e]})):n.sort()),n}function x(t,e){for(var i,n,s=e[0].toUpperCase()+e.slice(1),a=0;a1&&!i.firstMultiple?i.firstMultiple=H(e):1===s&&(i.firstMultiple=!1);var o=i.firstInput,a=i.firstMultiple,h=a?a.center:o.center,l=e.center=L(n);e.timeStamp=c(),e.deltaTime=e.timeStamp-o.timeStamp,e.angle=G(h,l),e.distance=j(h,l),function(t,e){var i=e.center,n=t.offsetDelta||{},r=t.prevDelta||{},s=t.prevInput||{};1!==e.eventType&&4!==s.eventType||(r=t.prevDelta={x:s.deltaX||0,y:s.deltaY||0},n=t.offsetDelta={x:i.x,y:i.y});e.deltaX=r.x+(i.x-n.x),e.deltaY=r.y+(i.y-n.y)}(i,e),e.offsetDirection=V(e.deltaX,e.deltaY);var p=U(e.deltaTime,e.deltaX,e.deltaY);e.overallVelocityX=p.x,e.overallVelocityY=p.y,e.overallVelocity=u(p.x)>u(p.y)?p.x:p.y,e.scale=a?(f=a.pointers,v=n,j(v[0],v[1],W)/j(f[0],f[1],W)):1,e.rotation=a?function(t,e){return G(e[1],e[0],W)+G(t[1],t[0],W)}(a.pointers,n):0,e.maxPointers=i.prevInput?e.pointers.length>i.prevInput.maxPointers?e.pointers.length:i.prevInput.maxPointers:e.pointers.length,function(t,e){var i,n,s,o,a=t.lastInterval||e,h=e.timeStamp-a.timeStamp;if(8!=e.eventType&&(h>25||a.velocity===r)){var c=e.deltaX-a.deltaX,l=e.deltaY-a.deltaY,p=U(h,c,l);n=p.x,s=p.y,i=u(p.x)>u(p.y)?p.x:p.y,o=V(c,l),t.lastInterval=e}else i=a.velocity,n=a.velocityX,s=a.velocityY,o=a.direction;e.velocity=i,e.velocityX=n,e.velocityY=s,e.direction=o}(i,e);var f,v;var d=t.element;_(e.srcEvent.target,d)&&(d=e.srcEvent.target);e.target=d}(t,i),t.emit(\"hammer.input\",i),t.recognize(i),t.session.prevInput=i}function H(t){for(var e=[],i=0;i=u(e)?t<0?2:4:e<0?8:16}function j(t,e,i){i||(i=F);var n=e[i[0]]-t[i[0]],r=e[i[1]]-t[i[1]];return Math.sqrt(n*n+r*r)}function G(t,e,i){i||(i=F);var n=e[i[0]]-t[i[0]],r=e[i[1]]-t[i[1]];return 180*Math.atan2(r,n)/Math.PI}q.prototype={handler:function(){},init:function(){this.evEl&&I(this.element,this.evEl,this.domHandler),this.evTarget&&I(this.target,this.evTarget,this.domHandler),this.evWin&&I(O(this.element),this.evWin,this.domHandler)},destroy:function(){this.evEl&&A(this.element,this.evEl,this.domHandler),this.evTarget&&A(this.target,this.evTarget,this.domHandler),this.evWin&&A(O(this.element),this.evWin,this.domHandler)}};var Z={mousedown:1,mousemove:2,mouseup:4},B=\"mousedown\",$=\"mousemove mouseup\";function J(){this.evEl=B,this.evWin=$,this.pressed=!1,q.apply(this,arguments)}g(J,q,{handler:function(t){var e=Z[t.type];1&e&&0===t.button&&(this.pressed=!0),2&e&&1!==t.which&&(e=4),this.pressed&&(4&e&&(this.pressed=!1),this.callback(this.manager,e,{pointers:[t],changedPointers:[t],pointerType:X,srcEvent:t}))}});var K={pointerdown:1,pointermove:2,pointerup:4,pointercancel:8,pointerout:8},Q={2:N,3:\"pen\",4:X,5:\"kinect\"},tt=\"pointerdown\",et=\"pointermove pointerup pointercancel\";function it(){this.evEl=tt,this.evWin=et,q.apply(this,arguments),this.store=this.manager.session.pointerEvents=[]}t.MSPointerEvent&&!t.PointerEvent&&(tt=\"MSPointerDown\",et=\"MSPointerMove MSPointerUp MSPointerCancel\"),g(it,q,{handler:function(t){var e=this.store,i=!1,n=t.type.toLowerCase().replace(\"ms\",\"\"),r=K[n],s=Q[t.pointerType]||t.pointerType,o=s==N,a=b(e,t.pointerId,\"pointerId\");1&r&&(0===t.button||o)?a<0&&(e.push(t),a=e.length-1):12&r&&(i=!0),a<0||(e[a]=t,this.callback(this.manager,r,{pointers:e,changedPointers:[t],pointerType:s,srcEvent:t}),i&&e.splice(a,1))}});var nt={touchstart:1,touchmove:2,touchend:4,touchcancel:8},rt=\"touchstart\",st=\"touchstart touchmove touchend touchcancel\";function ot(){this.evTarget=rt,this.evWin=st,this.started=!1,q.apply(this,arguments)}function at(t,e){var i=P(t.touches),n=P(t.changedTouches);return 12&e&&(i=D(i.concat(n),\"identifier\",!0)),[i,n]}g(ot,q,{handler:function(t){var e=nt[t.type];if(1===e&&(this.started=!0),this.started){var i=at.call(this,t,e);12&e&&i[0].length-i[1].length==0&&(this.started=!1),this.callback(this.manager,e,{pointers:i[0],changedPointers:i[1],pointerType:N,srcEvent:t})}}});var ht={touchstart:1,touchmove:2,touchend:4,touchcancel:8},ut=\"touchstart touchmove touchend touchcancel\";function ct(){this.evTarget=ut,this.targetIds={},q.apply(this,arguments)}function lt(t,e){var i=P(t.touches),n=this.targetIds;if(3&e&&1===i.length)return n[i[0].identifier]=!0,[i,i];var r,s,o=P(t.changedTouches),a=[],h=this.target;if(s=i.filter((function(t){return _(t.target,h)})),1===e)for(r=0;r-1&&n.splice(t,1)}),2500)}}function dt(t){for(var e=t.srcEvent.clientX,i=t.srcEvent.clientY,n=0;n-1&&this.requireFail.splice(e,1),this},hasRequireFailures:function(){return this.requireFail.length>0},canRecognizeWith:function(t){return!!this.simultaneous[t.id]},emit:function(t){var e=this,i=this.state;function n(i){e.manager.emit(i,t)}i<8&&n(e.options.event+Dt(i)),n(e.options.event),t.additionalEvent&&n(t.additionalEvent),i>=8&&n(e.options.event+Dt(i))},tryEmit:function(t){if(this.canEmit())return this.emit(t);this.state=bt},canEmit:function(){for(var t=0;te.threshold&&r&e.direction},attrTest:function(t){return Ot.prototype.attrTest.call(this,t)&&(2&this.state||!(2&this.state)&&this.directionTest(t))},emit:function(t){this.pX=t.deltaX,this.pY=t.deltaY;var e=xt(t.direction);e&&(t.additionalEvent=this.options.event+e),this._super.emit.call(this,t)}}),g(Mt,Ot,{defaults:{event:\"pinch\",threshold:0,pointers:2},getTouchAction:function(){return[It]},attrTest:function(t){return this._super.attrTest.call(this,t)&&(Math.abs(t.scale-1)>this.options.threshold||2&this.state)},emit:function(t){if(1!==t.scale){var e=t.scale<1?\"in\":\"out\";t.additionalEvent=this.options.event+e}this._super.emit.call(this,t)}}),g(zt,Pt,{defaults:{event:\"press\",pointers:1,time:251,threshold:9},getTouchAction:function(){return[yt]},process:function(t){var e=this.options,i=t.pointers.length===e.pointers,n=t.distancee.time;if(this._input=t,!n||!i||12&t.eventType&&!r)this.reset();else if(1&t.eventType)this.reset(),this._timer=l((function(){this.state=8,this.tryEmit()}),e.time,this);else if(4&t.eventType)return 8;return bt},reset:function(){clearTimeout(this._timer)},emit:function(t){8===this.state&&(t&&4&t.eventType?this.manager.emit(this.options.event+\"up\",t):(this._input.timeStamp=c(),this.manager.emit(this.options.event,this._input)))}}),g(Nt,Ot,{defaults:{event:\"rotate\",threshold:0,pointers:2},getTouchAction:function(){return[It]},attrTest:function(t){return this._super.attrTest.call(this,t)&&(Math.abs(t.rotation)>this.options.threshold||2&this.state)}}),g(Xt,Ot,{defaults:{event:\"swipe\",threshold:10,velocity:.3,direction:30,pointers:1},getTouchAction:function(){return Rt.prototype.getTouchAction.call(this)},attrTest:function(t){var e,i=this.options.direction;return 30&i?e=t.overallVelocity:6&i?e=t.overallVelocityX:i&Y&&(e=t.overallVelocityY),this._super.attrTest.call(this,t)&&i&t.offsetDirection&&t.distance>this.options.threshold&&t.maxPointers==this.options.pointers&&u(e)>this.options.velocity&&4&t.eventType},emit:function(t){var e=xt(t.offsetDirection);e&&this.manager.emit(this.options.event+e,t),this.manager.emit(this.options.event,t)}}),g(Yt,Pt,{defaults:{event:\"tap\",pointers:1,taps:1,interval:300,time:250,threshold:9,posThreshold:10},getTouchAction:function(){return[Et]},process:function(t){var e=this.options,i=t.pointers.length===e.pointers,n=t.distance .bk-divider{cursor:default;overflow:hidden;background-color:#e5e5e5;}.bk-root .bk-context-menu.bk-horizontal > .bk-divider{width:1px;margin:5px 0;}.bk-root .bk-context-menu.bk-vertical > .bk-divider{height:1px;margin:0 5px;}.bk-root .bk-context-menu > :not(.bk-divider){border:1px solid transparent;}.bk-root .bk-context-menu > :not(.bk-divider).bk-active{border-color:#26aae1;}.bk-root .bk-context-menu > :not(.bk-divider):hover{background-color:#f9f9f9;}.bk-root .bk-context-menu > :not(.bk-divider):focus,.bk-root .bk-context-menu > :not(.bk-divider):focus-visible{outline:1px dotted #26aae1;outline-offset:-1px;}.bk-root .bk-context-menu > :not(.bk-divider)::-moz-focus-inner{border:0;}.bk-root .bk-context-menu.bk-horizontal > :not(.bk-divider):first-child{border-top-left-radius:4px;border-bottom-left-radius:4px;}.bk-root .bk-context-menu.bk-horizontal > :not(.bk-divider):last-child{border-top-right-radius:4px;border-bottom-right-radius:4px;}.bk-root .bk-context-menu.bk-vertical > :not(.bk-divider):first-child{border-top-left-radius:4px;border-top-right-radius:4px;}.bk-root .bk-context-menu.bk-vertical > :not(.bk-divider):last-child{border-bottom-left-radius:4px;border-bottom-right-radius:4px;}.bk-root .bk-menu{position:absolute;left:0;width:100%;z-index:100;cursor:pointer;font-size:12px;background-color:#fff;border:1px solid #ccc;border-radius:4px;box-shadow:0 6px 12px rgba(0, 0, 0, 0.175);}.bk-root .bk-menu.bk-above{bottom:100%;}.bk-root .bk-menu.bk-below{top:100%;}.bk-root .bk-menu > .bk-divider{height:1px;margin:7.5px 0;overflow:hidden;background-color:#e5e5e5;}.bk-root .bk-menu > :not(.bk-divider){padding:6px 12px;}.bk-root .bk-menu > :not(.bk-divider):hover,.bk-root .bk-menu > :not(.bk-divider).bk-active{background-color:#e6e6e6;}.bk-root .bk-caret{display:inline-block;vertical-align:middle;width:0;height:0;margin:0 5px;}.bk-root .bk-caret.bk-down{border-top:4px solid;}.bk-root .bk-caret.bk-up{border-bottom:4px solid;}.bk-root .bk-caret.bk-down,.bk-root .bk-caret.bk-up{border-right:4px solid transparent;border-left:4px solid transparent;}.bk-root .bk-caret.bk-left{border-right:4px solid;}.bk-root .bk-caret.bk-right{border-left:4px solid;}.bk-root .bk-caret.bk-left,.bk-root .bk-caret.bk-right{border-top:4px solid transparent;border-bottom:4px solid transparent;}\"},\n function _(t,e,i,n,o){n();const s=t(1),l=t(43),h=t(9),r=(0,s.__importStar)(t(229));class d{constructor(t,e={}){var i,n;this.items=t,this.el=(0,l.div)(),this._open=!1,this._item_click=t=>{var e;null===(e=t.handler)||void 0===e||e.call(t),this.hide()},this._on_mousedown=t=>{var e;const{target:i}=t;i instanceof Node&&this.el.contains(i)||(null===(e=this.prevent_hide)||void 0===e?void 0:e.call(this,t))||this.hide()},this._on_keydown=t=>{t.keyCode==l.Keys.Esc&&this.hide()},this._on_blur=()=>{this.hide()},this.orientation=null!==(i=e.orientation)&&void 0!==i?i:\"vertical\",this.reversed=null!==(n=e.reversed)&&void 0!==n&&n,this.prevent_hide=e.prevent_hide,(0,l.undisplay)(this.el)}get is_open(){return this._open}get can_open(){return 0!=this.items.length}remove(){(0,l.remove)(this.el),this._unlisten()}_listen(){document.addEventListener(\"mousedown\",this._on_mousedown),document.addEventListener(\"keydown\",this._on_keydown),window.addEventListener(\"blur\",this._on_blur)}_unlisten(){document.removeEventListener(\"mousedown\",this._on_mousedown),document.removeEventListener(\"keydown\",this._on_keydown),window.removeEventListener(\"blur\",this._on_blur)}_position(t){const e=this.el.parentElement;if(null!=e){const i=(()=>{if(\"left_of\"in t){const{left:e,top:i}=t.left_of.getBoundingClientRect();return{right:e,top:i}}if(\"right_of\"in t){const{top:e,right:i}=t.right_of.getBoundingClientRect();return{left:i,top:e}}if(\"below\"in t){const{left:e,bottom:i}=t.below.getBoundingClientRect();return{left:e,top:i}}if(\"above\"in t){const{left:e,top:i}=t.above.getBoundingClientRect();return{left:e,bottom:i}}return t})(),n=e.getBoundingClientRect();this.el.style.left=null!=i.left?i.left-n.left+\"px\":\"\",this.el.style.top=null!=i.top?i.top-n.top+\"px\":\"\",this.el.style.right=null!=i.right?n.right-i.right+\"px\":\"\",this.el.style.bottom=null!=i.bottom?n.bottom-i.bottom+\"px\":\"\"}}render(){var t;(0,l.empty)(this.el,!0),(0,l.classes)(this.el).add(\"bk-context-menu\",`bk-${this.orientation}`);const e=this.reversed?(0,h.reversed)(this.items):this.items;for(const i of e){let e;if(null==i)e=(0,l.div)({class:r.divider});else{if(null!=i.if&&!i.if())continue;if(null!=i.content)e=i.content;else{const n=null!=i.icon?(0,l.div)({class:[\"bk-menu-icon\",i.icon]}):null,o=[(null===(t=i.active)||void 0===t?void 0:t.call(i))?\"bk-active\":null,i.class];e=(0,l.div)({class:o,title:i.tooltip,tabIndex:0},n,i.label,i.content),e.addEventListener(\"click\",(()=>{this._item_click(i)})),e.addEventListener(\"keydown\",(t=>{t.keyCode==l.Keys.Enter&&this._item_click(i)}))}}this.el.appendChild(e)}}show(t){if(0!=this.items.length&&!this._open){if(this.render(),0==this.el.children.length)return;this._position(null!=t?t:{left:0,top:0}),(0,l.display)(this.el),this._listen(),this._open=!0}}hide(){this._open&&(this._open=!1,this._unlisten(),(0,l.undisplay)(this.el))}toggle(t){this._open?this.hide():this.show(t)}}i.ContextMenu=d,d.__name__=\"ContextMenu\"},\n function _(t,e,i,n,o){n();const s=t(1),c=t(224),l=(0,s.__importStar)(t(227)),a=t(43);class _ extends c.ButtonToolButtonView{render(){super.render(),(0,a.classes)(this.el).toggle(l.active,this.model.active)}_clicked(){const{active:t}=this.model;this.model.active=!t}}i.OnOffButtonView=_,_.__name__=\"OnOffButtonView\"},\n function _(e,o,t,n,s){var c;n();const l=e(224),_=e(231);class i extends l.ButtonToolView{}t.InspectToolView=i,i.__name__=\"InspectToolView\";class a extends l.ButtonTool{constructor(e){super(e),this.event_type=\"move\"}}t.InspectTool=a,c=a,a.__name__=\"InspectTool\",c.prototype.button_view=_.OnOffButtonView,c.define((({Boolean:e})=>({toggleable:[e,!0]}))),c.override({active:!0})},\n function _(t,o,e,l,i){l();const s=t(1);var n,a;const r=t(19),c=t(43),h=t(113),_=t(226),u=t(20),v=t(9),d=t(234),p=t(13),b=t(8),g=t(235),f=t(65),m=t(53),w=t(222),y=t(223),T=t(238),z=t(239),x=t(232),B=t(230),C=(0,s.__importStar)(t(227)),k=C,L=(0,s.__importStar)(t(240)),M=L;class S extends m.Model{constructor(t){super(t)}get visible(){var t;return!this.autohide||null!==(t=this._visible)&&void 0!==t&&t}}e.ToolbarViewModel=S,n=S,S.__name__=\"ToolbarViewModel\",n.define((({Boolean:t})=>({autohide:[t,!1]}))),n.internal((({Boolean:t,Nullable:o})=>({_visible:[o(t),null]})));class $ extends _.DOMView{constructor(){super(...arguments),this.layout={bbox:new f.BBox}}initialize(){super.initialize(),this._tool_button_views=new Map,this._toolbar_view_model=new S({autohide:this.model.autohide});const{toolbar_location:t}=this.model,o=\"left\"==t||\"above\"==t,e=this.model.horizontal?\"vertical\":\"horizontal\";this._overflow_menu=new B.ContextMenu([],{orientation:e,reversed:o})}async lazy_initialize(){await super.lazy_initialize(),await this._build_tool_button_views()}connect_signals(){super.connect_signals(),this.connect(this.model.properties.tools.change,(async()=>{await this._build_tool_button_views(),this.render()})),this.connect(this.model.properties.autohide.change,(()=>{this._toolbar_view_model.autohide=this.model.autohide,this._on_visible_change()})),this.connect(this._toolbar_view_model.properties._visible.change,(()=>this._on_visible_change()))}styles(){return[...super.styles(),C.default,L.default]}remove(){(0,h.remove_views)(this._tool_button_views),super.remove()}async _build_tool_button_views(){const t=null!=this.model._proxied_tools?this.model._proxied_tools:this.model.tools;await(0,h.build_views)(this._tool_button_views,t,{parent:this},(t=>t.button_view))}set_visibility(t){t!=this._toolbar_view_model._visible&&(this._toolbar_view_model._visible=t)}_on_visible_change(){const{visible:t}=this._toolbar_view_model;(0,c.classes)(this.el).toggle(k.toolbar_hidden,!t)}render(){(0,c.empty)(this.el),this.el.classList.add(k.toolbar),this.el.classList.add(k[this.model.toolbar_location]),this._toolbar_view_model.autohide=this.model.autohide,this._on_visible_change();const{horizontal:t}=this.model;let o=0;if(null!=this.model.logo){const e=\"grey\"===this.model.logo?M.grey:null,l=(0,c.a)({href:\"https://bokeh.org/\",target:\"_blank\",class:[M.logo,M.logo_small,e]});this.el.appendChild(l);const{width:i,height:s}=l.getBoundingClientRect();o+=t?i:s}for(const[,t]of this._tool_button_views)t.render();const e=[],l=t=>this._tool_button_views.get(t).el,{gestures:i}=this.model;for(const t of(0,p.values)(i))e.push(t.tools.map(l));e.push(this.model.actions.map(l)),e.push(this.model.inspectors.filter((t=>t.toggleable)).map(l));const s=e.filter((t=>0!=t.length)),n=()=>(0,c.div)({class:k.divider}),{bbox:a}=this.layout;let r=!1;this.root.el.appendChild(this._overflow_menu.el);const h=(0,c.div)({class:k.tool_overflow,tabIndex:0},t?\"\\u22ee\":\"\\u22ef\"),_=()=>{const t=(()=>{switch(this.model.toolbar_location){case\"right\":return{left_of:h};case\"left\":return{right_of:h};case\"above\":return{below:h};case\"below\":return{above:h}}})();this._overflow_menu.toggle(t)};h.addEventListener(\"click\",(()=>{_()})),h.addEventListener(\"keydown\",(t=>{t.keyCode==c.Keys.Enter&&_()}));for(const e of(0,d.join)(s,n))if(r)this._overflow_menu.items.push({content:e,class:t?k.right:k.above});else{this.el.appendChild(e);const{width:l,height:i}=e.getBoundingClientRect();if(o+=t?l:i,r=t?o>a.width-15:o>a.height-15,r){this.el.removeChild(e),this.el.appendChild(h);const{items:t}=this._overflow_menu;t.splice(0,t.length),t.push({content:e})}}}update_layout(){}update_position(){}after_layout(){this._has_finished=!0}export(t,o=!0){const e=\"png\"==t?\"canvas\":\"svg\",l=new g.CanvasLayer(e,o);return l.resize(0,0),l}}function V(){return{pan:{tools:[],active:null},scroll:{tools:[],active:null},pinch:{tools:[],active:null},tap:{tools:[],active:null},doubletap:{tools:[],active:null},press:{tools:[],active:null},pressup:{tools:[],active:null},rotate:{tools:[],active:null},move:{tools:[],active:null},multi:{tools:[],active:null}}}e.ToolbarBaseView=$,$.__name__=\"ToolbarBaseView\";class A extends m.Model{constructor(t){super(t)}initialize(){super.initialize(),this._init_tools()}_init_tools(){const t=function(t,o){if(t.length!=o.length)return!0;const e=new Set(o.map((t=>t.id)));return(0,v.some)(t,(t=>!e.has(t.id)))},o=this.tools.filter((t=>t instanceof x.InspectTool));t(this.inspectors,o)&&(this.inspectors=o);const e=this.tools.filter((t=>t instanceof z.HelpTool));t(this.help,e)&&(this.help=e);const l=this.tools.filter((t=>t instanceof T.ActionTool));t(this.actions,l)&&(this.actions=l);const i=(t,o)=>{t in this.gestures||r.logger.warn(`Toolbar: unknown event type '${t}' for tool: ${o}`)},s={pan:{tools:[],active:null},scroll:{tools:[],active:null},pinch:{tools:[],active:null},tap:{tools:[],active:null},doubletap:{tools:[],active:null},press:{tools:[],active:null},pressup:{tools:[],active:null},rotate:{tools:[],active:null},move:{tools:[],active:null},multi:{tools:[],active:null}};for(const t of this.tools)if(t instanceof y.GestureTool&&t.event_type)if((0,b.isString)(t.event_type))s[t.event_type].tools.push(t),i(t.event_type,t);else{s.multi.tools.push(t);for(const o of t.event_type)i(o,t)}for(const o of Object.keys(s)){const e=this.gestures[o];t(e.tools,s[o].tools)&&(e.tools=s[o].tools),e.active&&(0,v.every)(e.tools,(t=>t.id!=e.active.id))&&(e.active=null)}}get horizontal(){return\"above\"===this.toolbar_location||\"below\"===this.toolbar_location}get vertical(){return\"left\"===this.toolbar_location||\"right\"===this.toolbar_location}_active_change(t){const{event_type:o}=t;if(null==o)return;const e=(0,b.isString)(o)?[o]:o;for(const o of e)if(t.active){const e=this.gestures[o].active;null!=e&&t!=e&&(r.logger.debug(`Toolbar: deactivating tool: ${e} for event type '${o}'`),e.active=!1),this.gestures[o].active=t,r.logger.debug(`Toolbar: activating tool: ${t} for event type '${o}'`)}else this.gestures[o].active=null}}e.ToolbarBase=A,a=A,A.__name__=\"ToolbarBase\",a.prototype.default_view=$,a.define((({Boolean:t,Array:o,Ref:e,Nullable:l})=>({tools:[o(e(w.Tool)),[]],logo:[l(u.Logo),\"normal\"],autohide:[t,!1]}))),a.internal((({Array:t,Struct:o,Ref:e,Nullable:l})=>{const i=o({tools:t(e(y.GestureTool)),active:l(e(w.Tool))});return{gestures:[o({pan:i,scroll:i,pinch:i,tap:i,doubletap:i,press:i,pressup:i,rotate:i,move:i,multi:i}),V],actions:[t(e(T.ActionTool)),[]],inspectors:[t(e(x.InspectTool)),[]],help:[t(e(z.HelpTool)),[]],toolbar_location:[u.Location,\"right\"]}}))},\n function _(n,o,e,t,f){t();const r=n(9);function*i(n,o){const e=n.length;if(o>e)return;const t=(0,r.range)(o);for(yield t.map((o=>n[o]));;){let f;for(const n of(0,r.reversed)((0,r.range)(o)))if(t[n]!=n+e-o){f=n;break}if(null==f)return;t[f]+=1;for(const n of(0,r.range)(f+1,o))t[n]=t[n-1]+1;yield t.map((o=>n[o]))}}e.enumerate=function*(n){let o=0;for(const e of n)yield[e,o++]},e.join=function*(n,o){let e=!0;for(const t of n)e?e=!1:null!=o&&(yield o()),yield*t},e.combinations=i,e.subsets=function*(n){for(const o of(0,r.range)(n.length+1))yield*i(n,o)}},\n function _(t,e,s,i,n){i();const o=t(236),a=t(65),r=t(43);function h(t){!function(t){void 0===t.lineDash&&Object.defineProperty(t,\"lineDash\",{get:()=>t.getLineDash(),set:e=>t.setLineDash(e)})}(t),function(t){t.setImageSmoothingEnabled=e=>{t.imageSmoothingEnabled=e,t.mozImageSmoothingEnabled=e,t.oImageSmoothingEnabled=e,t.webkitImageSmoothingEnabled=e,t.msImageSmoothingEnabled=e},t.getImageSmoothingEnabled=()=>{const e=t.imageSmoothingEnabled;return null==e||e}}(t),function(t){t.ellipse||(t.ellipse=function(e,s,i,n,o,a,r,h=!1){const l=.551784;t.translate(e,s),t.rotate(o);let c=i,g=n;h&&(c=-i,g=-n),t.moveTo(-c,0),t.bezierCurveTo(-c,g*l,-c*l,g,0,g),t.bezierCurveTo(c*l,g,c,g*l,c,0),t.bezierCurveTo(c,-g*l,c*l,-g,0,-g),t.bezierCurveTo(-c*l,-g,-c,-g*l,-c,0),t.rotate(-o),t.translate(-e,-s)})}(t)}const l={position:\"absolute\",top:\"0\",left:\"0\",width:\"100%\",height:\"100%\"};class c{constructor(t,e){switch(this.backend=t,this.hidpi=e,this.pixel_ratio=1,this.bbox=new a.BBox,t){case\"webgl\":case\"canvas\":{this._el=this._canvas=(0,r.canvas)({style:l});const t=this.canvas.getContext(\"2d\");if(null==t)throw new Error(\"unable to obtain 2D rendering context\");this._ctx=t,e&&(this.pixel_ratio=devicePixelRatio);break}case\"svg\":{const t=new o.SVGRenderingContext2D;this._ctx=t,this._canvas=t.get_svg(),this._el=(0,r.div)({style:l},this._canvas);break}}this._ctx.layer=this,h(this._ctx)}get canvas(){return this._canvas}get ctx(){return this._ctx}get el(){return this._el}resize(t,e){this.bbox=new a.BBox({left:0,top:0,width:t,height:e});const s=this._ctx instanceof o.SVGRenderingContext2D?this._ctx:this.canvas;s.width=t*this.pixel_ratio,s.height=e*this.pixel_ratio}undo_transform(t){const{ctx:e}=this;if(void 0===e.getTransform)t(e);else{const s=e.getTransform();e.setTransform(this._base_transform);try{t(e)}finally{e.setTransform(s)}}}prepare(){const{ctx:t,hidpi:e,pixel_ratio:s}=this;t.save(),e&&(t.scale(s,s),t.translate(.5,.5)),void 0!==t.getTransform&&(this._base_transform=t.getTransform()),this.clear()}clear(){const{x:t,y:e,width:s,height:i}=this.bbox;this.ctx.clearRect(t,e,s,i)}finish(){this.ctx.restore()}to_blob(){const{_canvas:t}=this;if(t instanceof HTMLCanvasElement)return null!=t.msToBlob?Promise.resolve(t.msToBlob()):new Promise(((e,s)=>{t.toBlob((t=>null!=t?e(t):s()),\"image/png\")}));{const t=this._ctx.get_serialized_svg(!0),e=new Blob([t],{type:\"image/svg+xml\"});return Promise.resolve(e)}}}s.CanvasLayer=c,c.__name__=\"CanvasLayer\"},\n function _(t,e,i,s,r){s();const n=t(122),a=t(8),o=t(237),l=t(10),h=t(43);function _(t){var e;const i={left:\"start\",right:\"end\",center:\"middle\",start:\"start\",end:\"end\"};return null!==(e=i[t])&&void 0!==e?e:i.start}function c(t){var e;const i={alphabetic:\"alphabetic\",hanging:\"hanging\",top:\"text-before-edge\",bottom:\"text-after-edge\",middle:\"central\"};return null!==(e=i[t])&&void 0!==e?e:i.alphabetic}const p=function(t,e){const i=new Map,s=t.split(\",\");e=null!=e?e:10;for(let t=0;t=0?Math.acos(e):-Math.acos(e)}const v=b(f),A=b(g);this.lineTo(d+f[0]*r,m+f[1]*r),this.arc(d,m,r,v,A)}stroke(){\"path\"===this.__currentElement.nodeName&&this.__currentElement.setAttribute(\"paint-order\",\"fill\"),this.__applyCurrentDefaultPath(),this.__applyStyleToCurrentElement(\"stroke\"),null!=this._clip_path&&this.__currentElement.setAttribute(\"clip-path\",this._clip_path)}fill(t,e){let i=null;if(t instanceof Path2D)i=t;else{if(\"evenodd\"!=t&&\"nonzero\"!=t&&null!=t||null!=e)throw new Error(\"invalid arguments\");e=t}if(null!=i)throw new Error(\"not implemented\");\"none\"!=this.__currentElement.getAttribute(\"fill\")&&this.__init_element(),\"path\"===this.__currentElement.nodeName&&this.__currentElement.setAttribute(\"paint-order\",\"stroke\"),this.__applyCurrentDefaultPath(),this.__applyStyleToCurrentElement(\"fill\"),null!=e&&this.__currentElement.setAttribute(\"fill-rule\",e),null!=this._clip_path&&this.__currentElement.setAttribute(\"clip-path\",this._clip_path)}rect(t,e,i,s){isFinite(t+e+i+s)&&(this.moveTo(t,e),this.lineTo(t+i,e),this.lineTo(t+i,e+s),this.lineTo(t,e+s),this.lineTo(t,e))}fillRect(t,e,i,s){isFinite(t+e+i+s)&&(this.beginPath(),this.rect(t,e,i,s),this.fill())}strokeRect(t,e,i,s){isFinite(t+e+i+s)&&(this.beginPath(),this.rect(t,e,i,s),this.stroke())}__clearCanvas(){(0,h.empty)(this.__defs),(0,h.empty)(this.__root),this.__root.appendChild(this.__defs),this.__currentElement=this.__root}clearRect(t,e,i,s){if(!isFinite(t+e+i+s))return;if(0===t&&0===e&&i===this.width&&s===this.height)return void this.__clearCanvas();const r=this.__createElement(\"rect\",{x:t,y:e,width:i,height:s,fill:\"#FFFFFF\"},!0);this._apply_transform(r),this.__root.appendChild(r)}createLinearGradient(t,e,i,s){if(!isFinite(t+e+i+s))throw new Error(\"The provided double value is non-finite\");const[r,n]=this._transform.apply(t,e),[a,o]=this._transform.apply(i,s),l=this.__createElement(\"linearGradient\",{id:this._random_string(),x1:`${r}px`,x2:`${a}px`,y1:`${n}px`,y2:`${o}px`,gradientUnits:\"userSpaceOnUse\"},!1);return this.__defs.appendChild(l),new d(l,this)}createRadialGradient(t,e,i,s,r,n){if(!isFinite(t+e+i+s+r+n))throw new Error(\"The provided double value is non-finite\");const[a,o]=this._transform.apply(t,e),[l,h]=this._transform.apply(s,r),_=this.__createElement(\"radialGradient\",{id:this._random_string(),cx:`${l}px`,cy:`${h}px`,r:`${n}px`,r0:`${i}px`,fx:`${a}px`,fy:`${o}px`,gradientUnits:\"userSpaceOnUse\"},!1);return this.__defs.appendChild(_),new d(_,this)}__parseFont(){var t,e,i,s,r;const n=/^\\s*(?=(?:(?:[-a-z]+\\s*){0,2}(italic|oblique))?)(?=(?:(?:[-a-z]+\\s*){0,2}(small-caps))?)(?=(?:(?:[-a-z]+\\s*){0,2}(bold(?:er)?|lighter|[1-9]00))?)(?:(?:normal|\\1|\\2|\\3)\\s*){0,3}((?:xx?-)?(?:small|large)|medium|smaller|larger|[.\\d]+(?:\\%|in|[cem]m|ex|p[ctx]))(?:\\s*\\/\\s*(normal|[.\\d]+(?:\\%|in|[cem]m|ex|p[ctx])))?\\s*([-,\\'\\\"\\sa-z0-9]+?)\\s*$/i.exec(this.font);return{style:null!==(t=n[1])&&void 0!==t?t:\"normal\",size:null!==(e=n[4])&&void 0!==e?e:\"10px\",family:null!==(i=n[6])&&void 0!==i?i:\"sans-serif\",weight:null!==(s=n[3])&&void 0!==s?s:\"normal\",decoration:null!==(r=n[2])&&void 0!==r?r:\"normal\"}}__applyText(t,e,i,s){const r=this.__parseFont(),n=this.__createElement(\"text\",{\"font-family\":r.family,\"font-size\":r.size,\"font-style\":r.style,\"font-weight\":r.weight,\"text-decoration\":r.decoration,x:e,y:i,\"text-anchor\":_(this.textAlign),\"dominant-baseline\":c(this.textBaseline)},!0);n.appendChild(this.__document.createTextNode(t)),this._apply_transform(n),this.__currentElement=n,this.__applyStyleToCurrentElement(s);const a=(()=>{if(null!=this._clip_path){const t=this.__createElement(\"g\");return t.setAttribute(\"clip-path\",this._clip_path),t.appendChild(n),t}return n})();this.__root.appendChild(a)}fillText(t,e,i){null!=t&&isFinite(e+i)&&this.__applyText(t,e,i,\"fill\")}strokeText(t,e,i){null!=t&&isFinite(e+i)&&this.__applyText(t,e,i,\"stroke\")}measureText(t){return this.__ctx.font=this.font,this.__ctx.measureText(t)}arc(t,e,i,s,r,n=!1){this.ellipse(t,e,i,i,0,s,r,n)}ellipse(t,e,i,s,r,n,a,o=!1){if(!isFinite(t+e+i+s+r+n+a))return;if(i<0||s<0)throw new DOMException(\"IndexSizeError, radius can't be negative\");const h=o?a-n:n-a;n%=2*Math.PI,a%=2*Math.PI;const _=t+i*Math.cos(n),c=e+s*Math.sin(n);this.lineTo(_,c);const p=180*r/Math.PI,u=o?0:1;if(Math.abs(n-a)<2*l.float32_epsilon&&!(Math.abs(h)<2*l.float32_epsilon&&h<0)){const r=t+i*Math.cos(n+Math.PI),a=e+s*Math.sin(n+Math.PI),[o,l]=this._transform.apply(_,c),[h,d]=this._transform.apply(r,a);this.__addPathCommand(o,l,`A ${i} ${s} ${p} 0 ${u} ${h} ${d} A ${i} ${s} ${p} 0 ${u} ${o} ${l}`)}else{const r=t+i*Math.cos(a),l=e+s*Math.sin(a);let h=a-n;h<0&&(h+=2*Math.PI);const _=o!==h>Math.PI?1:0,[c,d]=this._transform.apply(r,l);this.__addPathCommand(c,d,`A ${i} ${s} ${p} ${_} ${u} ${c} ${d}`)}}clip(){const t=this.__createElement(\"clipPath\"),e=this._random_string();this.__applyCurrentDefaultPath(),t.setAttribute(\"id\",e),t.appendChild(this.__currentElement),this.__defs.appendChild(t),this._clip_path=`url(#${e})`}drawImage(t,...e){let i,s,r,n,a,o,l,h;if(2==e.length){if([i,s]=e,!isFinite(i+s))return;a=0,o=0,l=t.width,h=t.height,r=l,n=h}else if(4==e.length){if([i,s,r,n]=e,!isFinite(i+s+r+n))return;a=0,o=0,l=t.width,h=t.height}else{if(8!==e.length)throw new Error(`Inavlid number of arguments passed to drawImage: ${arguments.length}`);if([a,o,l,h,i,s,r,n]=e,!isFinite(a+o+l+h+i+s+r+n))return}const _=this.__root,c=this._transform.clone().translate(i,s);if(t instanceof f||t instanceof SVGSVGElement){const e=(t instanceof SVGSVGElement?t:t.get_svg()).cloneNode(!0);let i;c.is_identity&&1==this.globalAlpha&&null==this._clip_path?i=_:(i=this.__createElement(\"g\"),c.is_identity||this._apply_transform(i,c),1!=this.globalAlpha&&i.setAttribute(\"opacity\",`${this.globalAlpha}`),null!=this._clip_path&&i.setAttribute(\"clip-path\",this._clip_path),_.appendChild(i));for(const t of[...e.childNodes])if(t instanceof SVGDefsElement){for(const e of[...t.childNodes])if(e instanceof Element){const t=e.getAttribute(\"id\");this.__ids.add(t),this.__defs.appendChild(e.cloneNode(!0))}}else i.appendChild(t.cloneNode(!0))}else if(t instanceof HTMLImageElement||t instanceof SVGImageElement){const e=this.__createElement(\"image\");if(e.setAttribute(\"width\",`${r}`),e.setAttribute(\"height\",`${n}`),e.setAttribute(\"preserveAspectRatio\",\"none\"),1!=this.globalAlpha&&e.setAttribute(\"opacity\",`${this.globalAlpha}`),a||o||l!==t.width||h!==t.height){const e=this.__document.createElement(\"canvas\");e.width=r,e.height=n;e.getContext(\"2d\").drawImage(t,a,o,l,h,0,0,r,n),t=e}this._apply_transform(e,c);const i=t instanceof HTMLCanvasElement?t.toDataURL():t.getAttribute(\"src\");if(e.setAttribute(\"href\",i),null!=this._clip_path){const t=this.__createElement(\"g\");t.setAttribute(\"clip-path\",this._clip_path),t.appendChild(e),_.appendChild(t)}else _.appendChild(e)}else if(t instanceof HTMLCanvasElement){const e=this.__createElement(\"image\");e.setAttribute(\"width\",`${r}`),e.setAttribute(\"height\",`${n}`),e.setAttribute(\"preserveAspectRatio\",\"none\"),1!=this.globalAlpha&&e.setAttribute(\"opacity\",`${this.globalAlpha}`);const i=this.__document.createElement(\"canvas\");i.width=r,i.height=n;const s=i.getContext(\"2d\");if(s.imageSmoothingEnabled=!1,s.drawImage(t,a,o,l,h,0,0,r,n),t=i,this._apply_transform(e,c),e.setAttribute(\"href\",t.toDataURL()),null!=this._clip_path){const t=this.__createElement(\"g\");t.setAttribute(\"clip-path\",this._clip_path),t.appendChild(e),_.appendChild(t)}else _.appendChild(e)}}createPattern(t,e){const i=this.__document.createElementNS(\"http://www.w3.org/2000/svg\",\"pattern\"),s=this._random_string();if(i.setAttribute(\"id\",s),i.setAttribute(\"width\",`${this._to_number(t.width)}`),i.setAttribute(\"height\",`${this._to_number(t.height)}`),i.setAttribute(\"patternUnits\",\"userSpaceOnUse\"),t instanceof HTMLCanvasElement||t instanceof HTMLImageElement||t instanceof SVGImageElement){const e=this.__document.createElementNS(\"http://www.w3.org/2000/svg\",\"image\"),s=t instanceof HTMLCanvasElement?t.toDataURL():t.getAttribute(\"src\");e.setAttribute(\"href\",s),i.appendChild(e),this.__defs.appendChild(i)}else if(t instanceof f){for(const e of[...t.__root.childNodes])e instanceof SVGDefsElement||i.appendChild(e.cloneNode(!0));this.__defs.appendChild(i)}else{if(!(t instanceof SVGSVGElement))throw new Error(\"unsupported\");for(const e of[...t.childNodes])e instanceof SVGDefsElement||i.appendChild(e.cloneNode(!0));this.__defs.appendChild(i)}return new m(i,this)}getLineDash(){const{lineDash:t}=this;return(0,a.isString)(t)?t.split(\",\").map((t=>parseInt(t))):null==t?[]:t}setLineDash(t){t&&t.length>0?this.lineDash=t.join(\",\"):this.lineDash=null}_to_number(t){return(0,a.isNumber)(t)?t:t.baseVal.value}getTransform(){return this._transform.to_DOMMatrix()}setTransform(...t){let e;e=(0,a.isNumber)(t[0])?new DOMMatrix(t):t[0]instanceof DOMMatrix?t[0]:new DOMMatrix(Object.values(!t[0])),this._transform=n.AffineTransform.from_DOMMatrix(e)}resetTransform(){this._transform=new n.AffineTransform}isPointInPath(...t){throw new Error(\"not implemented\")}isPointInStroke(...t){throw new Error(\"not implemented\")}createImageData(...t){throw new Error(\"not implemented\")}getImageData(t,e,i,s){throw new Error(\"not implemented\")}putImageData(...t){throw new Error(\"not implemented\")}drawFocusIfNeeded(...t){throw new Error(\"not implemented\")}scrollPathIntoView(...t){throw new Error(\"not implemented\")}}i.SVGRenderingContext2D=f,f.__name__=\"SVGRenderingContext2D\",f.__random=o.random},\n function _(e,t,s,n,r){n();const o=2147483647;class i{constructor(e){this.seed=e%o,this.seed<=0&&(this.seed+=2147483646)}integer(){return this.seed=48271*this.seed%o,this.seed}float(){return(this.integer()-1)/2147483646}floats(e,t=0,s=1){const n=new Array(e);for(let r=0;rthis.doit(o)))}}n.ActionToolView=_,_.__name__=\"ActionToolView\";class d extends s.ButtonTool{constructor(o){super(o),this.button_view=l,this.do=new c.Signal(this,\"do\")}}n.ActionTool=d,d.__name__=\"ActionTool\"},\n function _(o,e,t,l,i){var s;l();const n=o(238),r=o(228);class c extends n.ActionToolView{doit(){window.open(this.model.redirect)}}t.HelpToolView=c,c.__name__=\"HelpToolView\";class _ extends n.ActionTool{constructor(o){super(o),this.tool_name=\"Help\",this.icon=r.tool_icon_help}}t.HelpTool=_,s=_,_.__name__=\"HelpTool\",s.prototype.default_view=c,s.define((({String:o})=>({redirect:[o,\"https://docs.bokeh.org/en/latest/docs/user_guide/tools.html\"]}))),s.override({description:\"Click the question mark to learn more about Bokeh plot tools.\"}),s.register_alias(\"help\",(()=>new _))},\n function _(o,l,g,A,r){A(),g.root=\"bk-root\",g.logo=\"bk-logo\",g.grey=\"bk-grey\",g.logo_small=\"bk-logo-small\",g.logo_notebook=\"bk-logo-notebook\",g.default=\".bk-root .bk-logo{margin:5px;position:relative;display:block;background-repeat:no-repeat;}.bk-root .bk-logo.bk-grey{filter:url(\\\"data:image/svg+xml;utf8,#grayscale\\\");filter:gray;-webkit-filter:grayscale(100%);}.bk-root .bk-logo-small{width:20px;height:20px;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAAAOkSURBVDiNjZRtaJVlGMd/1/08zzln5zjP1LWcU9N0NkN8m2CYjpgQYQXqSs0I84OLIC0hkEKoPtiH3gmKoiJDU7QpLgoLjLIQCpEsNJ1vqUOdO7ppbuec5+V+rj4ctwzd8IIbbi6u+8f1539dt3A78eXC7QizUF7gyV1fD1Yqg4JWz84yffhm0qkFqBogB9rM8tZdtwVsPUhWhGcFJngGeWrPzHm5oaMmkfEg1usvLFyc8jLRqDOMru7AyC8saQr7GG7f5fvDeH7Ej8CM66nIF+8yngt6HWaKh7k49Soy9nXurCi1o3qUbS3zWfrYeQDTB/Qj6kX6Ybhw4B+bOYoLKCC9H3Nu/leUTZ1JdRWkkn2ldcCamzrcf47KKXdAJllSlxAOkRgyHsGC/zRday5Qld9DyoM4/q/rUoy/CXh3jzOu3bHUVZeU+DEn8FInkPBFlu3+nW3Nw0mk6vCDiWg8CeJaxEwuHS3+z5RgY+YBR6V1Z1nxSOfoaPa4LASWxxdNp+VWTk7+4vzaou8v8PN+xo+KY2xsw6une2frhw05CTYOmQvsEhjhWjn0bmXPjpE1+kplmmkP3suftwTubK9Vq22qKmrBhpY4jvd5afdRA3wGjFAgcnTK2s4hY0/GPNIb0nErGMCRxWOOX64Z8RAC4oCXdklmEvcL8o0BfkNK4lUg9HTl+oPlQxdNo3Mg4Nv175e/1LDGzZen30MEjRUtmXSfiTVu1kK8W4txyV6BMKlbgk3lMwYCiusNy9fVfvvwMxv8Ynl6vxoByANLTWplvuj/nF9m2+PDtt1eiHPBr1oIfhCChQMBw6Aw0UulqTKZdfVvfG7VcfIqLG9bcldL/+pdWTLxLUy8Qq38heUIjh4XlzZxzQm19lLFlr8vdQ97rjZVOLf8nclzckbcD4wxXMidpX30sFd37Fv/GtwwhzhxGVAprjbg0gCAEeIgwCZyTV2Z1REEW8O4py0wsjeloKoMr6iCY6dP92H6Vw/oTyICIthibxjm/DfN9lVz8IqtqKYLUXfoKVMVQVVJOElGjrnnUt9T9wbgp8AyYKaGlqingHZU/uG2NTZSVqwHQTWkx9hxjkpWDaCg6Ckj5qebgBVbT3V3NNXMSiWSDdGV3hrtzla7J+duwPOToIg42ChPQOQjspnSlp1V+Gjdged7+8UN5CRAV7a5EdFNwCjEaBR27b3W890TE7g24NAP/mMDXRWrGoFPQI9ls/MWO2dWFAar/xcOIImbbpA3zgAAAABJRU5ErkJggg==);}.bk-root .bk-logo-notebook{display:inline-block;vertical-align:middle;margin-right:5px;}\"},\n function _(e,t,s,i,l){i();const o=e(1);var n;const a=e(40),h=e(20),r=e(43),c=(0,o.__importStar)(e(242)),d=c;class p extends a.AnnotationView{initialize(){super.initialize(),this.el=(0,r.div)({class:d.tooltip}),(0,r.undisplay)(this.el),this.plot_view.canvas_view.add_overlay(this.el)}remove(){(0,r.remove)(this.el),super.remove()}connect_signals(){super.connect_signals(),this.connect(this.model.properties.content.change,(()=>this.render())),this.connect(this.model.properties.position.change,(()=>this._reposition()))}styles(){return[...super.styles(),c.default]}render(){this.model.visible||(0,r.undisplay)(this.el),super.render()}_render(){const{content:e}=this.model;null!=e?((0,r.empty)(this.el),(0,r.classes)(this.el).toggle(\"bk-tooltip-custom\",this.model.custom),this.el.appendChild(e),this.model.show_arrow&&this.el.classList.add(d.tooltip_arrow)):(0,r.undisplay)(this.el)}_reposition(){const{position:e}=this.model;if(null==e)return void(0,r.undisplay)(this.el);const[t,s]=e,i=(()=>{const e=this.parent.layout.bbox.relative(),{attachment:i}=this.model;switch(i){case\"horizontal\":return t({attachment:[h.TooltipAttachment,\"horizontal\"],inner_only:[e,!0],show_arrow:[e,!0]}))),n.internal((({Boolean:e,Number:t,Tuple:s,Ref:i,Nullable:l})=>({position:[l(s(t,t)),null],content:[i(HTMLElement),()=>(0,r.div)()],custom:[e]}))),n.override({level:\"overlay\"})},\n function _(o,t,r,e,l){e(),r.root=\"bk-root\",r.tooltip=\"bk-tooltip\",r.left=\"bk-left\",r.tooltip_arrow=\"bk-tooltip-arrow\",r.right=\"bk-right\",r.above=\"bk-above\",r.below=\"bk-below\",r.tooltip_row_label=\"bk-tooltip-row-label\",r.tooltip_row_value=\"bk-tooltip-row-value\",r.tooltip_color_block=\"bk-tooltip-color-block\",r.default='.bk-root{}.bk-root .bk-tooltip{font-weight:300;font-size:12px;position:absolute;padding:5px;border:1px solid #e5e5e5;color:#2f2f2f;background-color:white;pointer-events:none;opacity:0.95;z-index:100;}.bk-root .bk-tooltip > div:not(:first-child){margin-top:5px;border-top:#e5e5e5 1px dashed;}.bk-root .bk-tooltip.bk-left.bk-tooltip-arrow::before{position:absolute;margin:-7px 0 0 0;top:50%;width:0;height:0;border-style:solid;border-width:7px 0 7px 0;border-color:transparent;content:\" \";display:block;left:-10px;border-right-width:10px;border-right-color:#909599;}.bk-root .bk-tooltip.bk-left::before{left:-10px;border-right-width:10px;border-right-color:#909599;}.bk-root .bk-tooltip.bk-right.bk-tooltip-arrow::after{position:absolute;margin:-7px 0 0 0;top:50%;width:0;height:0;border-style:solid;border-width:7px 0 7px 0;border-color:transparent;content:\" \";display:block;right:-10px;border-left-width:10px;border-left-color:#909599;}.bk-root .bk-tooltip.bk-right::after{right:-10px;border-left-width:10px;border-left-color:#909599;}.bk-root .bk-tooltip.bk-above::before{position:absolute;margin:0 0 0 -7px;left:50%;width:0;height:0;border-style:solid;border-width:0 7px 0 7px;border-color:transparent;content:\" \";display:block;top:-10px;border-bottom-width:10px;border-bottom-color:#909599;}.bk-root .bk-tooltip.bk-below::after{position:absolute;margin:0 0 0 -7px;left:50%;width:0;height:0;border-style:solid;border-width:0 7px 0 7px;border-color:transparent;content:\" \";display:block;bottom:-10px;border-top-width:10px;border-top-color:#909599;}.bk-root .bk-tooltip-row-label{text-align:right;color:#26aae1;}.bk-root .bk-tooltip-row-value{color:default;}.bk-root .bk-tooltip-color-block{width:12px;height:12px;margin-left:5px;margin-right:5px;outline:#dddddd solid 1px;display:inline-block;}'},\n function _(e,t,s,i,r){var a;i();const l=e(115),_=e(112),h=e(113),o=e(48);class n extends l.UpperLowerView{async lazy_initialize(){await super.lazy_initialize();const{lower_head:e,upper_head:t}=this.model;null!=e&&(this.lower_head=await(0,h.build_view)(e,{parent:this})),null!=t&&(this.upper_head=await(0,h.build_view)(t,{parent:this}))}set_data(e){var t,s;super.set_data(e),null===(t=this.lower_head)||void 0===t||t.set_data(e),null===(s=this.upper_head)||void 0===s||s.set_data(e)}paint(e){if(this.visuals.line.doit)for(let t=0,s=this._lower_sx.length;t({lower_head:[t(e(_.ArrowHead)),()=>new _.TeeHead({size:10})],upper_head:[t(e(_.ArrowHead)),()=>new _.TeeHead({size:10})]}))),a.override({level:\"underlay\"})},\n function _(n,o,t,u,e){u(),e(\"CustomJS\",n(245).CustomJS),e(\"OpenURL\",n(247).OpenURL)},\n function _(t,e,s,n,c){var a;n();const r=t(246),u=t(13),o=t(34);class i extends r.Callback{constructor(t){super(t)}get names(){return(0,u.keys)(this.args)}get values(){return(0,u.values)(this.args)}get func(){const t=(0,o.use_strict)(this.code);return new Function(...this.names,\"cb_obj\",\"cb_data\",t)}execute(t,e={}){return this.func.apply(t,this.values.concat(t,e))}}s.CustomJS=i,a=i,i.__name__=\"CustomJS\",a.define((({Unknown:t,String:e,Dict:s})=>({args:[s(t),{}],code:[e,\"\"]})))},\n function _(c,a,l,n,s){n();const e=c(53);class o extends e.Model{constructor(c){super(c)}}l.Callback=o,o.__name__=\"Callback\"},\n function _(e,t,n,o,i){var s;o();const c=e(246),r=e(152),a=e(8);class d extends c.Callback{constructor(e){super(e)}navigate(e){this.same_tab?window.location.href=e:window.open(e)}execute(e,{source:t}){const n=e=>{const n=(0,r.replace_placeholders)(this.url,t,e,void 0,void 0,encodeURI);if(!(0,a.isString)(n))throw new Error(\"HTML output is not supported in this context\");this.navigate(n)},{selected:o}=t;for(const e of o.indices)n(e);for(const e of o.line_indices)n(e)}}n.OpenURL=d,s=d,d.__name__=\"OpenURL\",s.define((({Boolean:e,String:t})=>({url:[t,\"http://\"],same_tab:[e,!1]})))},\n function _(a,n,i,e,r){e(),r(\"Canvas\",a(249).Canvas),r(\"CartesianFrame\",a(126).CartesianFrame),r(\"CoordinateMapping\",a(54).CoordinateMapping)},\n function _(e,t,i,s,a){var l,r=this&&this.__createBinding||(Object.create?function(e,t,i,s){void 0===s&&(s=i),Object.defineProperty(e,s,{enumerable:!0,get:function(){return t[i]}})}:function(e,t,i,s){void 0===s&&(s=i),e[s]=t[i]}),n=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,\"default\",{enumerable:!0,value:t})}:function(e,t){e.default=t}),o=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var i in e)\"default\"!==i&&Object.prototype.hasOwnProperty.call(e,i)&&r(t,e,i);return n(t,e),t};s();const h=e(14),c=e(28),u=e(226),_=e(19),d=e(43),p=e(20),b=e(13),v=e(250),g=e(65),w=e(138),y=e(235);const f=(()=>{let t;return async()=>void 0!==t?t:t=await async function(){const t=document.createElement(\"canvas\"),i=t.getContext(\"webgl\",{premultipliedAlpha:!0});if(null!=i){const s=await(0,w.load_module)(Promise.resolve().then((()=>o(e(410)))));if(null!=s){const e=s.get_regl(i);if(e.has_webgl)return{canvas:t,regl_wrapper:e};_.logger.trace(\"WebGL is supported, but not the required extensions\")}else _.logger.trace(\"WebGL is supported, but bokehjs(.min).js bundle is not available\")}else _.logger.trace(\"WebGL is not supported\");return null}()})(),m={position:\"absolute\",top:\"0\",left:\"0\",width:\"100%\",height:\"100%\"};class x extends u.DOMView{constructor(){super(...arguments),this.bbox=new g.BBox,this.webgl=null}initialize(){super.initialize(),this.underlays_el=(0,d.div)({style:m}),this.primary=this.create_layer(),this.overlays=this.create_layer(),this.overlays_el=(0,d.div)({style:m}),this.events_el=(0,d.div)({class:\"bk-canvas-events\",style:m});const e=[this.underlays_el,this.primary.el,this.overlays.el,this.overlays_el,this.events_el];(0,b.extend)(this.el.style,m),(0,d.append)(this.el,...e),this.ui_event_bus=new v.UIEventBus(this)}async lazy_initialize(){if(await super.lazy_initialize(),\"webgl\"==this.model.output_backend&&(this.webgl=await f(),c.settings.force_webgl&&null==this.webgl))throw new Error(\"webgl is not available\")}remove(){this.ui_event_bus.destroy(),super.remove()}add_underlay(e){this.underlays_el.appendChild(e)}add_overlay(e){this.overlays_el.appendChild(e)}add_event(e){this.events_el.appendChild(e)}get pixel_ratio(){return this.primary.pixel_ratio}resize(e,t){this.bbox=new g.BBox({left:0,top:0,width:e,height:t}),this.primary.resize(e,t),this.overlays.resize(e,t)}prepare_webgl(e){const{webgl:t}=this;if(null!=t){const{width:i,height:s}=this.bbox;t.canvas.width=this.pixel_ratio*i,t.canvas.height=this.pixel_ratio*s;const[a,l,r,n]=e,{xview:o,yview:h}=this.bbox,c=o.compute(a),u=h.compute(l+n),_=this.pixel_ratio;t.regl_wrapper.set_scissor(_*c,_*u,_*r,_*n),this._clear_webgl()}}blit_webgl(e){const{webgl:t}=this;if(null!=t){if(_.logger.debug(\"Blitting WebGL canvas\"),e.restore(),e.drawImage(t.canvas,0,0),e.save(),this.model.hidpi){const t=this.pixel_ratio;e.scale(t,t),e.translate(.5,.5)}this._clear_webgl()}}_clear_webgl(){const{webgl:e}=this;if(null!=e){const{regl_wrapper:t,canvas:i}=e;t.clear(i.width,i.height)}}compose(){const e=this.create_layer(),{width:t,height:i}=this.bbox;return e.resize(t,i),e.ctx.drawImage(this.primary.canvas,0,0),e.ctx.drawImage(this.overlays.canvas,0,0),e}create_layer(){const{output_backend:e,hidpi:t}=this.model;return new y.CanvasLayer(e,t)}to_blob(){return this.compose().to_blob()}}i.CanvasView=x,x.__name__=\"CanvasView\";class z extends h.HasProps{constructor(e){super(e)}}i.Canvas=z,l=z,z.__name__=\"Canvas\",l.prototype.default_view=x,l.internal((({Boolean:e})=>({hidpi:[e,!0],output_backend:[p.OutputBackend,\"canvas\"]})))},\n function _(t,e,s,n,i){n();const r=t(1),a=(0,r.__importDefault)(t(225)),_=t(15),h=t(19),o=t(43),l=(0,r.__importStar)(t(251)),c=t(252),p=t(9),u=t(8),v=t(27),d=t(230);class g{constructor(t){this.canvas_view=t,this.pan_start=new _.Signal(this,\"pan:start\"),this.pan=new _.Signal(this,\"pan\"),this.pan_end=new _.Signal(this,\"pan:end\"),this.pinch_start=new _.Signal(this,\"pinch:start\"),this.pinch=new _.Signal(this,\"pinch\"),this.pinch_end=new _.Signal(this,\"pinch:end\"),this.rotate_start=new _.Signal(this,\"rotate:start\"),this.rotate=new _.Signal(this,\"rotate\"),this.rotate_end=new _.Signal(this,\"rotate:end\"),this.tap=new _.Signal(this,\"tap\"),this.doubletap=new _.Signal(this,\"doubletap\"),this.press=new _.Signal(this,\"press\"),this.pressup=new _.Signal(this,\"pressup\"),this.move_enter=new _.Signal(this,\"move:enter\"),this.move=new _.Signal(this,\"move\"),this.move_exit=new _.Signal(this,\"move:exit\"),this.scroll=new _.Signal(this,\"scroll\"),this.keydown=new _.Signal(this,\"keydown\"),this.keyup=new _.Signal(this,\"keyup\"),this.hammer=new a.default(this.hit_area,{touchAction:\"auto\",inputClass:a.default.TouchMouseInput}),this._prev_move=null,this._curr_pan=null,this._curr_pinch=null,this._curr_rotate=null,this._configure_hammerjs(),this.hit_area.addEventListener(\"mousemove\",(t=>this._mouse_move(t))),this.hit_area.addEventListener(\"mouseenter\",(t=>this._mouse_enter(t))),this.hit_area.addEventListener(\"mouseleave\",(t=>this._mouse_exit(t))),this.hit_area.addEventListener(\"contextmenu\",(t=>this._context_menu(t))),this.hit_area.addEventListener(\"wheel\",(t=>this._mouse_wheel(t))),document.addEventListener(\"keydown\",this),document.addEventListener(\"keyup\",this),this.menu=new d.ContextMenu([],{prevent_hide:t=>2==t.button&&t.target==this.hit_area}),this.hit_area.appendChild(this.menu.el)}get hit_area(){return this.canvas_view.events_el}destroy(){this.menu.remove(),this.hammer.destroy(),document.removeEventListener(\"keydown\",this),document.removeEventListener(\"keyup\",this)}handleEvent(t){\"keydown\"==t.type?this._key_down(t):\"keyup\"==t.type&&this._key_up(t)}_configure_hammerjs(){this.hammer.get(\"doubletap\").recognizeWith(\"tap\"),this.hammer.get(\"tap\").requireFailure(\"doubletap\"),this.hammer.get(\"doubletap\").dropRequireFailure(\"tap\"),this.hammer.on(\"doubletap\",(t=>this._doubletap(t))),this.hammer.on(\"tap\",(t=>this._tap(t))),this.hammer.on(\"press\",(t=>this._press(t))),this.hammer.on(\"pressup\",(t=>this._pressup(t))),this.hammer.get(\"pan\").set({direction:a.default.DIRECTION_ALL}),this.hammer.on(\"panstart\",(t=>this._pan_start(t))),this.hammer.on(\"pan\",(t=>this._pan(t))),this.hammer.on(\"panend\",(t=>this._pan_end(t))),this.hammer.get(\"pinch\").set({enable:!0}),this.hammer.on(\"pinchstart\",(t=>this._pinch_start(t))),this.hammer.on(\"pinch\",(t=>this._pinch(t))),this.hammer.on(\"pinchend\",(t=>this._pinch_end(t))),this.hammer.get(\"rotate\").set({enable:!0}),this.hammer.on(\"rotatestart\",(t=>this._rotate_start(t))),this.hammer.on(\"rotate\",(t=>this._rotate(t))),this.hammer.on(\"rotateend\",(t=>this._rotate_end(t)))}register_tool(t){const e=t.model.event_type;null!=e&&((0,u.isString)(e)?this._register_tool(t,e):e.forEach(((e,s)=>this._register_tool(t,e,s<1))))}_register_tool(t,e,s=!0){const n=t,{id:i}=n.model,r=t=>e=>{e.id==i&&t(e.e)},a=t=>e=>{t(e.e)};switch(e){case\"pan\":null!=n._pan_start&&n.connect(this.pan_start,r(n._pan_start.bind(n))),null!=n._pan&&n.connect(this.pan,r(n._pan.bind(n))),null!=n._pan_end&&n.connect(this.pan_end,r(n._pan_end.bind(n)));break;case\"pinch\":null!=n._pinch_start&&n.connect(this.pinch_start,r(n._pinch_start.bind(n))),null!=n._pinch&&n.connect(this.pinch,r(n._pinch.bind(n))),null!=n._pinch_end&&n.connect(this.pinch_end,r(n._pinch_end.bind(n)));break;case\"rotate\":null!=n._rotate_start&&n.connect(this.rotate_start,r(n._rotate_start.bind(n))),null!=n._rotate&&n.connect(this.rotate,r(n._rotate.bind(n))),null!=n._rotate_end&&n.connect(this.rotate_end,r(n._rotate_end.bind(n)));break;case\"move\":null!=n._move_enter&&n.connect(this.move_enter,r(n._move_enter.bind(n))),null!=n._move&&n.connect(this.move,r(n._move.bind(n))),null!=n._move_exit&&n.connect(this.move_exit,r(n._move_exit.bind(n)));break;case\"tap\":null!=n._tap&&n.connect(this.tap,r(n._tap.bind(n))),null!=n._doubletap&&n.connect(this.doubletap,r(n._doubletap.bind(n)));break;case\"press\":null!=n._press&&n.connect(this.press,r(n._press.bind(n))),null!=n._pressup&&n.connect(this.pressup,r(n._pressup.bind(n)));break;case\"scroll\":null!=n._scroll&&n.connect(this.scroll,r(n._scroll.bind(n)));break;default:throw new Error(`unsupported event_type: ${e}`)}s&&(null!=n._keydown&&n.connect(this.keydown,a(n._keydown.bind(n))),null!=n._keyup&&n.connect(this.keyup,a(n._keyup.bind(n))),v.is_mobile&&null!=n._scroll&&\"pinch\"==e&&(h.logger.debug(\"Registering scroll on touch screen\"),n.connect(this.scroll,r(n._scroll.bind(n)))))}_hit_test_renderers(t,e,s){var n;const i=t.get_renderer_views();for(const t of(0,p.reversed)(i))if(null===(n=t.interactive_hit)||void 0===n?void 0:n.call(t,e,s))return t;return null}set_cursor(t=\"default\"){this.hit_area.style.cursor=t}_hit_test_frame(t,e,s){return t.frame.bbox.contains(e,s)}_hit_test_canvas(t,e,s){return t.layout.bbox.contains(e,s)}_hit_test_plot(t,e){for(const s of this.canvas_view.plot_views)if(s.layout.bbox.relative().contains(t,e))return s;return null}_trigger(t,e,s){var n;const{sx:i,sy:r}=e,a=this._hit_test_plot(i,r),_=t=>{const[s,n]=[i,r];return Object.assign(Object.assign({},e),{sx:s,sy:n})};if(\"panstart\"==e.type||\"pan\"==e.type||\"panend\"==e.type){let n;if(\"panstart\"==e.type&&null!=a?(this._curr_pan={plot_view:a},n=a):\"pan\"==e.type&&null!=this._curr_pan?n=this._curr_pan.plot_view:\"panend\"==e.type&&null!=this._curr_pan?(n=this._curr_pan.plot_view,this._curr_pan=null):n=null,null!=n){const e=_();this.__trigger(n,t,e,s)}}else if(\"pinchstart\"==e.type||\"pinch\"==e.type||\"pinchend\"==e.type){let n;if(\"pinchstart\"==e.type&&null!=a?(this._curr_pinch={plot_view:a},n=a):\"pinch\"==e.type&&null!=this._curr_pinch?n=this._curr_pinch.plot_view:\"pinchend\"==e.type&&null!=this._curr_pinch?(n=this._curr_pinch.plot_view,this._curr_pinch=null):n=null,null!=n){const e=_();this.__trigger(n,t,e,s)}}else if(\"rotatestart\"==e.type||\"rotate\"==e.type||\"rotateend\"==e.type){let n;if(\"rotatestart\"==e.type&&null!=a?(this._curr_rotate={plot_view:a},n=a):\"rotate\"==e.type&&null!=this._curr_rotate?n=this._curr_rotate.plot_view:\"rotateend\"==e.type&&null!=this._curr_rotate?(n=this._curr_rotate.plot_view,this._curr_rotate=null):n=null,null!=n){const e=_();this.__trigger(n,t,e,s)}}else if(\"mouseenter\"==e.type||\"mousemove\"==e.type||\"mouseleave\"==e.type){const h=null===(n=this._prev_move)||void 0===n?void 0:n.plot_view;if(null!=h&&(\"mouseleave\"==e.type||h!=a)){const{sx:t,sy:e}=_();this.__trigger(h,this.move_exit,{type:\"mouseleave\",sx:t,sy:e,shiftKey:!1,ctrlKey:!1},s)}if(null!=a&&(\"mouseenter\"==e.type||h!=a)){const{sx:t,sy:e}=_();this.__trigger(a,this.move_enter,{type:\"mouseenter\",sx:t,sy:e,shiftKey:!1,ctrlKey:!1},s)}if(null!=a&&\"mousemove\"==e.type){const e=_();this.__trigger(a,t,e,s)}this._prev_move={sx:i,sy:r,plot_view:a}}else if(null!=a){const e=_();this.__trigger(a,t,e,s)}}__trigger(t,e,s,n){var i,r,a;const _=t.model.toolbar.gestures,h=e.name.split(\":\")[0],o=this._hit_test_renderers(t,s.sx,s.sy),l=this._hit_test_canvas(t,s.sx,s.sy);switch(h){case\"move\":{const n=_.move.active;null!=n&&this.trigger(e,s,n.id);const r=t.model.toolbar.inspectors.filter((t=>t.active));let a=\"default\";null!=o?(a=null!==(i=o.cursor(s.sx,s.sy))&&void 0!==i?i:a,(0,p.is_empty)(r)||(e=this.move_exit)):this._hit_test_frame(t,s.sx,s.sy)&&((0,p.is_empty)(r)||(a=\"crosshair\")),this.set_cursor(a),t.set_toolbar_visibility(l),r.map((t=>this.trigger(e,s,t.id)));break}case\"tap\":{const{target:i}=n;if(null!=i&&i!=this.hit_area)return;if(null===(r=null==o?void 0:o.on_hit)||void 0===r||r.call(o,s.sx,s.sy),this._hit_test_frame(t,s.sx,s.sy)){const t=_.tap.active;null!=t&&this.trigger(e,s,t.id)}break}case\"doubletap\":if(this._hit_test_frame(t,s.sx,s.sy)){const t=null!==(a=_.doubletap.active)&&void 0!==a?a:_.tap.active;null!=t&&this.trigger(e,s,t.id)}break;case\"scroll\":{const t=_[v.is_mobile?\"pinch\":\"scroll\"].active;null!=t&&(n.preventDefault(),n.stopPropagation(),this.trigger(e,s,t.id));break}case\"pan\":{const t=_.pan.active;null!=t&&(n.preventDefault(),this.trigger(e,s,t.id));break}default:{const t=_[h].active;null!=t&&this.trigger(e,s,t.id)}}this._trigger_bokeh_event(t,s)}trigger(t,e,s=null){t.emit({id:s,e})}_trigger_bokeh_event(t,e){const s=(()=>{const{sx:s,sy:n}=e,i=t.frame.x_scale.invert(s),r=t.frame.y_scale.invert(n);switch(e.type){case\"wheel\":return new l.MouseWheel(s,n,i,r,e.delta);case\"mousemove\":return new l.MouseMove(s,n,i,r);case\"mouseenter\":return new l.MouseEnter(s,n,i,r);case\"mouseleave\":return new l.MouseLeave(s,n,i,r);case\"tap\":return new l.Tap(s,n,i,r);case\"doubletap\":return new l.DoubleTap(s,n,i,r);case\"press\":return new l.Press(s,n,i,r);case\"pressup\":return new l.PressUp(s,n,i,r);case\"pan\":return new l.Pan(s,n,i,r,e.deltaX,e.deltaY);case\"panstart\":return new l.PanStart(s,n,i,r);case\"panend\":return new l.PanEnd(s,n,i,r);case\"pinch\":return new l.Pinch(s,n,i,r,e.scale);case\"pinchstart\":return new l.PinchStart(s,n,i,r);case\"pinchend\":return new l.PinchEnd(s,n,i,r);case\"rotate\":return new l.Rotate(s,n,i,r,e.rotation);case\"rotatestart\":return new l.RotateStart(s,n,i,r);case\"rotateend\":return new l.RotateEnd(s,n,i,r);default:return}})();null!=s&&t.model.trigger_event(s)}_get_sxy(t){const{pageX:e,pageY:s}=function(t){return\"undefined\"!=typeof TouchEvent&&t instanceof TouchEvent}(t)?(0!=t.touches.length?t.touches:t.changedTouches)[0]:t,{left:n,top:i}=(0,o.offset)(this.hit_area);return{sx:e-n,sy:s-i}}_pan_event(t){return Object.assign(Object.assign({type:t.type},this._get_sxy(t.srcEvent)),{deltaX:t.deltaX,deltaY:t.deltaY,shiftKey:t.srcEvent.shiftKey,ctrlKey:t.srcEvent.ctrlKey})}_pinch_event(t){return Object.assign(Object.assign({type:t.type},this._get_sxy(t.srcEvent)),{scale:t.scale,shiftKey:t.srcEvent.shiftKey,ctrlKey:t.srcEvent.ctrlKey})}_rotate_event(t){return Object.assign(Object.assign({type:t.type},this._get_sxy(t.srcEvent)),{rotation:t.rotation,shiftKey:t.srcEvent.shiftKey,ctrlKey:t.srcEvent.ctrlKey})}_tap_event(t){return Object.assign(Object.assign({type:t.type},this._get_sxy(t.srcEvent)),{shiftKey:t.srcEvent.shiftKey,ctrlKey:t.srcEvent.ctrlKey})}_move_event(t){return Object.assign(Object.assign({type:t.type},this._get_sxy(t)),{shiftKey:t.shiftKey,ctrlKey:t.ctrlKey})}_scroll_event(t){return Object.assign(Object.assign({type:t.type},this._get_sxy(t)),{delta:(0,c.getDeltaY)(t),shiftKey:t.shiftKey,ctrlKey:t.ctrlKey})}_key_event(t){return{type:t.type,keyCode:t.keyCode}}_pan_start(t){const e=this._pan_event(t);e.sx-=t.deltaX,e.sy-=t.deltaY,this._trigger(this.pan_start,e,t.srcEvent)}_pan(t){this._trigger(this.pan,this._pan_event(t),t.srcEvent)}_pan_end(t){this._trigger(this.pan_end,this._pan_event(t),t.srcEvent)}_pinch_start(t){this._trigger(this.pinch_start,this._pinch_event(t),t.srcEvent)}_pinch(t){this._trigger(this.pinch,this._pinch_event(t),t.srcEvent)}_pinch_end(t){this._trigger(this.pinch_end,this._pinch_event(t),t.srcEvent)}_rotate_start(t){this._trigger(this.rotate_start,this._rotate_event(t),t.srcEvent)}_rotate(t){this._trigger(this.rotate,this._rotate_event(t),t.srcEvent)}_rotate_end(t){this._trigger(this.rotate_end,this._rotate_event(t),t.srcEvent)}_tap(t){this._trigger(this.tap,this._tap_event(t),t.srcEvent)}_doubletap(t){this._trigger(this.doubletap,this._tap_event(t),t.srcEvent)}_press(t){this._trigger(this.press,this._tap_event(t),t.srcEvent)}_pressup(t){this._trigger(this.pressup,this._tap_event(t),t.srcEvent)}_mouse_enter(t){this._trigger(this.move_enter,this._move_event(t),t)}_mouse_move(t){this._trigger(this.move,this._move_event(t),t)}_mouse_exit(t){this._trigger(this.move_exit,this._move_event(t),t)}_mouse_wheel(t){this._trigger(this.scroll,this._scroll_event(t),t)}_context_menu(t){!this.menu.is_open&&this.menu.can_open&&t.preventDefault();const{sx:e,sy:s}=this._get_sxy(t);this.menu.toggle({left:e,top:s})}_key_down(t){this.trigger(this.keydown,this._key_event(t))}_key_up(t){this.trigger(this.keyup,this._key_event(t))}}s.UIEventBus=g,g.__name__=\"UIEventBus\"},\n function _(e,t,s,n,_){n();var a=this&&this.__decorate||function(e,t,s,n){var _,a=arguments.length,o=a<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,s):n;if(\"object\"==typeof Reflect&&\"function\"==typeof Reflect.decorate)o=Reflect.decorate(e,t,s,n);else for(var r=e.length-1;r>=0;r--)(_=e[r])&&(o=(a<3?_(o):a>3?_(t,s,o):_(t,s))||o);return a>3&&o&&Object.defineProperty(t,s,o),o};function o(e){return function(t){t.prototype.event_name=e}}class r{to_json(){const{event_name:e}=this;return{event_name:e,event_values:this._to_json()}}}s.BokehEvent=r,r.__name__=\"BokehEvent\";class c extends r{constructor(){super(...arguments),this.origin=null}_to_json(){return{model:this.origin}}}s.ModelEvent=c,c.__name__=\"ModelEvent\";let l=class extends r{_to_json(){return{}}};s.DocumentReady=l,l.__name__=\"DocumentReady\",s.DocumentReady=l=a([o(\"document_ready\")],l);let i=class extends c{};s.ButtonClick=i,i.__name__=\"ButtonClick\",s.ButtonClick=i=a([o(\"button_click\")],i);let u=class extends c{constructor(e){super(),this.item=e}_to_json(){const{item:e}=this;return Object.assign(Object.assign({},super._to_json()),{item:e})}};s.MenuItemClick=u,u.__name__=\"MenuItemClick\",s.MenuItemClick=u=a([o(\"menu_item_click\")],u);class d extends c{}s.UIEvent=d,d.__name__=\"UIEvent\";let m=class extends d{};s.LODStart=m,m.__name__=\"LODStart\",s.LODStart=m=a([o(\"lodstart\")],m);let h=class extends d{};s.LODEnd=h,h.__name__=\"LODEnd\",s.LODEnd=h=a([o(\"lodend\")],h);let p=class extends d{constructor(e,t,s,n){super(),this.x0=e,this.x1=t,this.y0=s,this.y1=n}_to_json(){const{x0:e,x1:t,y0:s,y1:n}=this;return Object.assign(Object.assign({},super._to_json()),{x0:e,x1:t,y0:s,y1:n})}};s.RangesUpdate=p,p.__name__=\"RangesUpdate\",s.RangesUpdate=p=a([o(\"rangesupdate\")],p);let x=class extends d{constructor(e,t){super(),this.geometry=e,this.final=t}_to_json(){const{geometry:e,final:t}=this;return Object.assign(Object.assign({},super._to_json()),{geometry:e,final:t})}};s.SelectionGeometry=x,x.__name__=\"SelectionGeometry\",s.SelectionGeometry=x=a([o(\"selectiongeometry\")],x);let j=class extends d{};s.Reset=j,j.__name__=\"Reset\",s.Reset=j=a([o(\"reset\")],j);class y extends d{constructor(e,t,s,n){super(),this.sx=e,this.sy=t,this.x=s,this.y=n}_to_json(){const{sx:e,sy:t,x:s,y:n}=this;return Object.assign(Object.assign({},super._to_json()),{sx:e,sy:t,x:s,y:n})}}s.PointEvent=y,y.__name__=\"PointEvent\";let g=class extends y{constructor(e,t,s,n,_,a){super(e,t,s,n),this.delta_x=_,this.delta_y=a}_to_json(){const{delta_x:e,delta_y:t}=this;return Object.assign(Object.assign({},super._to_json()),{delta_x:e,delta_y:t})}};s.Pan=g,g.__name__=\"Pan\",s.Pan=g=a([o(\"pan\")],g);let P=class extends y{constructor(e,t,s,n,_){super(e,t,s,n),this.scale=_}_to_json(){const{scale:e}=this;return Object.assign(Object.assign({},super._to_json()),{scale:e})}};s.Pinch=P,P.__name__=\"Pinch\",s.Pinch=P=a([o(\"pinch\")],P);let O=class extends y{constructor(e,t,s,n,_){super(e,t,s,n),this.rotation=_}_to_json(){const{rotation:e}=this;return Object.assign(Object.assign({},super._to_json()),{rotation:e})}};s.Rotate=O,O.__name__=\"Rotate\",s.Rotate=O=a([o(\"rotate\")],O);let b=class extends y{constructor(e,t,s,n,_){super(e,t,s,n),this.delta=_}_to_json(){const{delta:e}=this;return Object.assign(Object.assign({},super._to_json()),{delta:e})}};s.MouseWheel=b,b.__name__=\"MouseWheel\",s.MouseWheel=b=a([o(\"wheel\")],b);let v=class extends y{};s.MouseMove=v,v.__name__=\"MouseMove\",s.MouseMove=v=a([o(\"mousemove\")],v);let E=class extends y{};s.MouseEnter=E,E.__name__=\"MouseEnter\",s.MouseEnter=E=a([o(\"mouseenter\")],E);let R=class extends y{};s.MouseLeave=R,R.__name__=\"MouseLeave\",s.MouseLeave=R=a([o(\"mouseleave\")],R);let M=class extends y{};s.Tap=M,M.__name__=\"Tap\",s.Tap=M=a([o(\"tap\")],M);let f=class extends y{};s.DoubleTap=f,f.__name__=\"DoubleTap\",s.DoubleTap=f=a([o(\"doubletap\")],f);let S=class extends y{};s.Press=S,S.__name__=\"Press\",s.Press=S=a([o(\"press\")],S);let D=class extends y{};s.PressUp=D,D.__name__=\"PressUp\",s.PressUp=D=a([o(\"pressup\")],D);let k=class extends y{};s.PanStart=k,k.__name__=\"PanStart\",s.PanStart=k=a([o(\"panstart\")],k);let L=class extends y{};s.PanEnd=L,L.__name__=\"PanEnd\",s.PanEnd=L=a([o(\"panend\")],L);let U=class extends y{};s.PinchStart=U,U.__name__=\"PinchStart\",s.PinchStart=U=a([o(\"pinchstart\")],U);let C=class extends y{};s.PinchEnd=C,C.__name__=\"PinchEnd\",s.PinchEnd=C=a([o(\"pinchend\")],C);let T=class extends y{};s.RotateStart=T,T.__name__=\"RotateStart\",s.RotateStart=T=a([o(\"rotatestart\")],T);let B=class extends y{};s.RotateEnd=B,B.__name__=\"RotateEnd\",s.RotateEnd=B=a([o(\"rotateend\")],B)},\n function _(t,e,n,l,o){\n /*!\n * jQuery Mousewheel 3.1.13\n *\n * Copyright jQuery Foundation and other contributors\n * Released under the MIT license\n * http://jquery.org/license\n */\n function u(t){const e=getComputedStyle(t).fontSize;return null!=e?parseInt(e,10):null}l(),n.getDeltaY=function(t){let e=-t.deltaY;if(t.target instanceof HTMLElement)switch(t.deltaMode){case t.DOM_DELTA_LINE:e*=(n=t.target,null!==(a=null!==(o=u(null!==(l=n.offsetParent)&&void 0!==l?l:document.body))&&void 0!==o?o:u(n))&&void 0!==a?a:16);break;case t.DOM_DELTA_PAGE:e*=function(t){return t.clientHeight}(t.target)}var n,l,o,a;return e}},\n function _(m,o,n,r,a){r(),a(\"Expression\",m(254).Expression),a(\"CustomJSExpr\",m(255).CustomJSExpr),a(\"Stack\",m(256).Stack),a(\"CumSum\",m(257).CumSum),a(\"ScalarExpression\",m(254).ScalarExpression),a(\"Minimum\",m(258).Minimum),a(\"Maximum\",m(259).Maximum);var s=m(260);a(\"XComponent\",s.XComponent),a(\"YComponent\",s.YComponent),a(\"PolarTransform\",m(261).PolarTransform)},\n function _(e,t,s,i,r){i();const n=e(53);class _ extends n.Model{constructor(e){super(e)}initialize(){super.initialize(),this._result=new Map}v_compute(e){let t=this._result.get(e);return(void 0===t||e.changed_for(this))&&(t=this._v_compute(e),this._result.set(e,t)),t}}s.Expression=_,_.__name__=\"Expression\";class o extends n.Model{constructor(e){super(e)}initialize(){super.initialize(),this._result=new Map}compute(e){let t=this._result.get(e);return(void 0===t||e.changed_for(this))&&(t=this._compute(e),this._result.set(e,t)),t}}s.ScalarExpression=o,o.__name__=\"ScalarExpression\"},\n function _(e,s,t,n,r){var a;n();const o=e(14),c=e(254),i=e(24),u=e(9),l=e(13),h=e(34),g=e(8);class p extends c.Expression{constructor(e){super(e)}connect_signals(){super.connect_signals();for(const e of(0,l.values)(this.args))e instanceof o.HasProps&&e.change.connect((()=>{this._result.clear(),this.change.emit()}))}get names(){return(0,l.keys)(this.args)}get values(){return(0,l.values)(this.args)}get func(){const e=(0,h.use_strict)(this.code);return new i.GeneratorFunction(...this.names,e)}_v_compute(e){const s=this.func.apply(e,this.values);let t=s.next();if(t.done&&void 0!==t.value){const{value:s}=t;return(0,g.isArray)(s)||(0,g.isTypedArray)(s)?s:(0,g.isIterable)(s)?[...s]:(0,u.repeat)(s,e.length)}{const e=[];do{e.push(t.value),t=s.next()}while(!t.done);return e}}}t.CustomJSExpr=p,a=p,p.__name__=\"CustomJSExpr\",a.define((({Unknown:e,String:s,Dict:t})=>({args:[t(e),{}],code:[s,\"\"]})))},\n function _(t,n,e,o,r){var s;o();const a=t(254);class c extends a.Expression{constructor(t){super(t)}_v_compute(t){var n;const e=null!==(n=t.get_length())&&void 0!==n?n:0,o=new Float64Array(e);for(const n of this.fields){const r=t.data[n];if(null!=r){const t=Math.min(e,r.length);for(let n=0;n({fields:[n(t),[]]})))},\n function _(e,n,t,o,r){var i;o();const l=e(254);class u extends l.Expression{constructor(e){super(e)}_v_compute(e){var n;const t=new Float64Array(null!==(n=e.get_length())&&void 0!==n?n:0),o=e.data[this.field],r=this.include_zero?1:0;t[0]=this.include_zero?0:o[0];for(let e=1;e({field:[n],include_zero:[e,!1]})))},\n function _(i,n,l,t,e){var a;t();const u=i(254),r=i(9);class s extends u.ScalarExpression{constructor(i){super(i)}_compute(i){var n,l;const t=null!==(n=i.data[this.field])&&void 0!==n?n:[];return Math.min(null!==(l=this.initial)&&void 0!==l?l:1/0,(0,r.min)(t))}}l.Minimum=s,a=s,s.__name__=\"Minimum\",a.define((({Number:i,String:n,Nullable:l})=>({field:[n],initial:[l(i),null]})))},\n function _(i,a,n,l,t){var e;l();const u=i(254),r=i(9);class s extends u.ScalarExpression{constructor(i){super(i)}_compute(i){var a,n;const l=null!==(a=i.data[this.field])&&void 0!==a?a:[];return Math.max(null!==(n=this.initial)&&void 0!==n?n:-1/0,(0,r.max)(l))}}n.Maximum=s,e=s,s.__name__=\"Maximum\",e.define((({Number:i,String:a,Nullable:n})=>({field:[a],initial:[n(i),null]})))},\n function _(n,e,t,o,r){var s;o();const _=n(254);class m extends _.Expression{constructor(n){super(n)}get x(){return new c({transform:this})}get y(){return new u({transform:this})}}t.CoordinateTransform=m,m.__name__=\"CoordinateTransform\";class a extends _.Expression{constructor(n){super(n)}}t.XYComponent=a,s=a,a.__name__=\"XYComponent\",s.define((({Ref:n})=>({transform:[n(m)]})));class c extends a{constructor(n){super(n)}_v_compute(n){return this.transform.v_compute(n).x}}t.XComponent=c,c.__name__=\"XComponent\";class u extends a{constructor(n){super(n)}_v_compute(n){return this.transform.v_compute(n).y}}t.YComponent=u,u.__name__=\"YComponent\"},\n function _(r,t,n,e,o){e();const i=r(1);var a;const s=r(260),c=r(20),l=(0,i.__importStar)(r(18));class d extends s.CoordinateTransform{constructor(r){super(r)}_v_compute(r){const t=this.properties.radius.uniform(r),n=this.properties.angle.uniform(r),e=\"anticlock\"==this.direction?-1:1,o=Math.min(t.length,n.length),i=new Float64Array(o),a=new Float64Array(o);for(let r=0;r({radius:[l.DistanceSpec,{field:\"radius\"}],angle:[l.AngleSpec,{field:\"angle\"}],direction:[c.Direction,\"anticlock\"]})))},\n function _(e,t,l,r,i){r(),i(\"BooleanFilter\",e(263).BooleanFilter),i(\"CustomJSFilter\",e(264).CustomJSFilter),i(\"Filter\",e(191).Filter),i(\"GroupFilter\",e(265).GroupFilter),i(\"IndexFilter\",e(266).IndexFilter)},\n function _(e,n,l,o,s){var t;o();const a=e(191),r=e(24);class c extends a.Filter{constructor(e){super(e)}compute_indices(e){const n=e.length,{booleans:l}=this;return null==l?r.Indices.all_set(n):r.Indices.from_booleans(n,l)}}l.BooleanFilter=c,t=c,c.__name__=\"BooleanFilter\",t.define((({Boolean:e,Array:n,Nullable:l})=>({booleans:[l(n(e)),null]})))},\n function _(e,n,r,s,t){var i;s();const o=e(191),c=e(24),u=e(13),a=e(8),l=e(34);class f extends o.Filter{constructor(e){super(e)}get names(){return(0,u.keys)(this.args)}get values(){return(0,u.values)(this.args)}get func(){const e=(0,l.use_strict)(this.code);return new Function(...this.names,\"source\",e)}compute_indices(e){const n=e.length,r=this.func(...this.values,e);if(null==r)return c.Indices.all_set(n);if((0,a.isArrayOf)(r,a.isInteger))return c.Indices.from_indices(n,r);if((0,a.isArrayOf)(r,a.isBoolean))return c.Indices.from_booleans(n,r);throw new Error(`expect an array of integers or booleans, or null, got ${r}`)}}r.CustomJSFilter=f,i=f,f.__name__=\"CustomJSFilter\",i.define((({Unknown:e,String:n,Dict:r})=>({args:[r(e),{}],code:[n,\"\"]})))},\n function _(n,e,t,o,r){var u;o();const s=n(191),c=n(24),i=n(19);class l extends s.Filter{constructor(n){super(n)}compute_indices(n){const e=n.get_column(this.column_name);if(null==e)return i.logger.warn(`${this}: groupby column '${this.column_name}' not found in the data source`),new c.Indices(n.length,1);{const t=new c.Indices(n.length);for(let n=0;n({column_name:[n],group:[n]})))},\n function _(e,n,i,s,t){var l;s();const c=e(191),r=e(24);class d extends c.Filter{constructor(e){super(e)}compute_indices(e){const n=e.length,{indices:i}=this;return null==i?r.Indices.all_set(n):r.Indices.from_indices(n,i)}}i.IndexFilter=d,l=d,d.__name__=\"IndexFilter\",l.define((({Int:e,Array:n,Nullable:i})=>({indices:[i(n(e)),null]})))},\n function _(e,a,l,i,t){i(),t(\"AnnularWedge\",e(268).AnnularWedge),t(\"Annulus\",e(269).Annulus),t(\"Arc\",e(270).Arc),t(\"Bezier\",e(271).Bezier),t(\"Circle\",e(272).Circle),t(\"Ellipse\",e(273).Ellipse),t(\"EllipseOval\",e(274).EllipseOval),t(\"Glyph\",e(179).Glyph),t(\"HArea\",e(187).HArea),t(\"HBar\",e(276).HBar),t(\"HexTile\",e(278).HexTile),t(\"Image\",e(279).Image),t(\"ImageRGBA\",e(281).ImageRGBA),t(\"ImageURL\",e(282).ImageURL),t(\"Line\",e(177).Line),t(\"MultiLine\",e(283).MultiLine),t(\"MultiPolygons\",e(284).MultiPolygons),t(\"Oval\",e(285).Oval),t(\"Patch\",e(186).Patch),t(\"Patches\",e(286).Patches),t(\"Quad\",e(287).Quad),t(\"Quadratic\",e(288).Quadratic),t(\"Ray\",e(289).Ray),t(\"Rect\",e(290).Rect),t(\"Scatter\",e(291).Scatter),t(\"Segment\",e(294).Segment),t(\"Spline\",e(295).Spline),t(\"Step\",e(297).Step),t(\"Text\",e(298).Text),t(\"VArea\",e(189).VArea),t(\"VBar\",e(299).VBar),t(\"Wedge\",e(300).Wedge)},\n function _(e,s,t,i,r){i();const n=e(1);var a;const _=e(178),o=e(184),d=e(48),u=e(24),h=e(20),c=(0,n.__importStar)(e(18)),l=e(10),g=e(72),p=e(12);class x extends _.XYGlyphView{_map_data(){\"data\"==this.model.properties.inner_radius.units?this.sinner_radius=this.sdist(this.renderer.xscale,this._x,this.inner_radius):this.sinner_radius=(0,u.to_screen)(this.inner_radius),\"data\"==this.model.properties.outer_radius.units?this.souter_radius=this.sdist(this.renderer.xscale,this._x,this.outer_radius):this.souter_radius=(0,u.to_screen)(this.outer_radius),this.max_souter_radius=(0,p.max)(this.souter_radius)}_render(e,s,t){const{sx:i,sy:r,start_angle:n,end_angle:a,sinner_radius:_,souter_radius:o}=null!=t?t:this,d=\"anticlock\"==this.model.direction;for(const t of s){const s=i[t],u=r[t],h=_[t],c=o[t],l=n.get(t),g=a.get(t);if(!isFinite(s+u+h+c+l+g))continue;const p=g-l;e.translate(s,u),e.rotate(l),e.beginPath(),e.moveTo(c,0),e.arc(0,0,c,0,p,d),e.rotate(p),e.lineTo(h,0),e.arc(0,0,h,0,-p,!d),e.closePath(),e.rotate(-p-l),e.translate(-s,-u),this.visuals.fill.apply(e,t),this.visuals.hatch.apply(e,t),this.visuals.line.apply(e,t)}}_hit_point(e){const{sx:s,sy:t}=e,i=this.renderer.xscale.invert(s),r=this.renderer.yscale.invert(t),n=s-this.max_souter_radius,a=s+this.max_souter_radius,[_,o]=this.renderer.xscale.r_invert(n,a),d=t-this.max_souter_radius,u=t+this.max_souter_radius,[h,c]=this.renderer.yscale.r_invert(d,u),p=[];for(const e of this.index.indices({x0:_,x1:o,y0:h,y1:c})){const s=this.souter_radius[e]**2,t=this.sinner_radius[e]**2,[n,a]=this.renderer.xscale.r_compute(i,this._x[e]),[_,o]=this.renderer.yscale.r_compute(r,this._y[e]),d=(n-a)**2+(_-o)**2;d<=s&&d>=t&&p.push(e)}const x=\"anticlock\"==this.model.direction,m=[];for(const e of p){const i=Math.atan2(t-this.sy[e],s-this.sx[e]);(0,l.angle_between)(-i,-this.start_angle.get(e),-this.end_angle.get(e),x)&&m.push(e)}return new g.Selection({indices:m})}draw_legend_for_index(e,s,t){(0,o.generic_area_vector_legend)(this.visuals,e,s,t)}scenterxy(e){const s=(this.sinner_radius[e]+this.souter_radius[e])/2,t=(this.start_angle.get(e)+this.end_angle.get(e))/2;return[this.sx[e]+s*Math.cos(t),this.sy[e]+s*Math.sin(t)]}}t.AnnularWedgeView=x,x.__name__=\"AnnularWedgeView\";class m extends _.XYGlyph{constructor(e){super(e)}}t.AnnularWedge=m,a=m,m.__name__=\"AnnularWedge\",a.prototype.default_view=x,a.mixins([d.LineVector,d.FillVector,d.HatchVector]),a.define((({})=>({direction:[h.Direction,\"anticlock\"],inner_radius:[c.DistanceSpec,{field:\"inner_radius\"}],outer_radius:[c.DistanceSpec,{field:\"outer_radius\"}],start_angle:[c.AngleSpec,{field:\"start_angle\"}],end_angle:[c.AngleSpec,{field:\"end_angle\"}]})))},\n function _(s,e,i,r,t){r();const n=s(1);var a;const u=s(178),o=s(24),_=s(48),d=(0,n.__importStar)(s(18)),h=s(27),c=s(72);class l extends u.XYGlyphView{_map_data(){\"data\"==this.model.properties.inner_radius.units?this.sinner_radius=this.sdist(this.renderer.xscale,this._x,this.inner_radius):this.sinner_radius=(0,o.to_screen)(this.inner_radius),\"data\"==this.model.properties.outer_radius.units?this.souter_radius=this.sdist(this.renderer.xscale,this._x,this.outer_radius):this.souter_radius=(0,o.to_screen)(this.outer_radius)}_render(s,e,i){const{sx:r,sy:t,sinner_radius:n,souter_radius:a}=null!=i?i:this;for(const i of e){const e=r[i],u=t[i],o=n[i],_=a[i];if(isFinite(e+u+o+_)){if(s.beginPath(),h.is_ie)for(const i of[!1,!0])s.moveTo(e,u),s.arc(e,u,o,0,Math.PI,i),s.moveTo(e+_,u),s.arc(e,u,_,Math.PI,0,!i);else s.arc(e,u,o,0,2*Math.PI,!0),s.moveTo(e+_,u),s.arc(e,u,_,2*Math.PI,0,!1);this.visuals.fill.apply(s,i),this.visuals.hatch.apply(s,i),this.visuals.line.apply(s,i)}}}_hit_point(s){const{sx:e,sy:i}=s,r=this.renderer.xscale.invert(e),t=this.renderer.yscale.invert(i);let n,a,u,o;if(\"data\"==this.model.properties.outer_radius.units)n=r-this.max_outer_radius,u=r+this.max_outer_radius,a=t-this.max_outer_radius,o=t+this.max_outer_radius;else{const s=e-this.max_outer_radius,r=e+this.max_outer_radius;[n,u]=this.renderer.xscale.r_invert(s,r);const t=i-this.max_outer_radius,_=i+this.max_outer_radius;[a,o]=this.renderer.yscale.r_invert(t,_)}const _=[];for(const s of this.index.indices({x0:n,x1:u,y0:a,y1:o})){const e=this.souter_radius[s]**2,i=this.sinner_radius[s]**2,[n,a]=this.renderer.xscale.r_compute(r,this._x[s]),[u,o]=this.renderer.yscale.r_compute(t,this._y[s]),d=(n-a)**2+(u-o)**2;d<=e&&d>=i&&_.push(s)}return new c.Selection({indices:_})}draw_legend_for_index(s,{x0:e,y0:i,x1:r,y1:t},n){const a=n+1,u=new Array(a);u[n]=(e+r)/2;const o=new Array(a);o[n]=(i+t)/2;const _=.5*Math.min(Math.abs(r-e),Math.abs(t-i)),d=new Array(a);d[n]=.4*_;const h=new Array(a);h[n]=.8*_,this._render(s,[n],{sx:u,sy:o,sinner_radius:d,souter_radius:h})}}i.AnnulusView=l,l.__name__=\"AnnulusView\";class x extends u.XYGlyph{constructor(s){super(s)}}i.Annulus=x,a=x,x.__name__=\"Annulus\",a.prototype.default_view=l,a.mixins([_.LineVector,_.FillVector,_.HatchVector]),a.define((({})=>({inner_radius:[d.DistanceSpec,{field:\"inner_radius\"}],outer_radius:[d.DistanceSpec,{field:\"outer_radius\"}]})))},\n function _(e,i,s,t,n){t();const r=e(1);var a;const c=e(178),d=e(184),l=e(48),_=e(24),o=e(20),u=(0,r.__importStar)(e(18));class h extends c.XYGlyphView{_map_data(){\"data\"==this.model.properties.radius.units?this.sradius=this.sdist(this.renderer.xscale,this._x,this.radius):this.sradius=(0,_.to_screen)(this.radius)}_render(e,i,s){if(this.visuals.line.doit){const{sx:t,sy:n,sradius:r,start_angle:a,end_angle:c}=null!=s?s:this,d=\"anticlock\"==this.model.direction;for(const s of i){const i=t[s],l=n[s],_=r[s],o=a.get(s),u=c.get(s);isFinite(i+l+_+o+u)&&(e.beginPath(),e.arc(i,l,_,o,u,d),this.visuals.line.set_vectorize(e,s),e.stroke())}}}draw_legend_for_index(e,i,s){(0,d.generic_line_vector_legend)(this.visuals,e,i,s)}}s.ArcView=h,h.__name__=\"ArcView\";class g extends c.XYGlyph{constructor(e){super(e)}}s.Arc=g,a=g,g.__name__=\"Arc\",a.prototype.default_view=h,a.mixins(l.LineVector),a.define((({})=>({direction:[o.Direction,\"anticlock\"],radius:[u.DistanceSpec,{field:\"radius\"}],start_angle:[u.AngleSpec,{field:\"start_angle\"}],end_angle:[u.AngleSpec,{field:\"end_angle\"}]})))},\n function _(e,t,i,n,s){n();const o=e(1);var c;const r=e(48),a=e(179),_=e(184),d=e(78),l=(0,o.__importStar)(e(18));function x(e,t,i,n,s,o,c,r){const a=[],_=[[],[]];for(let _=0;_<=2;_++){let d,l,x;if(0===_?(l=6*e-12*i+6*s,d=-3*e+9*i-9*s+3*c,x=3*i-3*e):(l=6*t-12*n+6*o,d=-3*t+9*n-9*o+3*r,x=3*n-3*t),Math.abs(d)<1e-12){if(Math.abs(l)<1e-12)continue;const e=-x/l;0({x0:[l.XCoordinateSpec,{field:\"x0\"}],y0:[l.YCoordinateSpec,{field:\"y0\"}],x1:[l.XCoordinateSpec,{field:\"x1\"}],y1:[l.YCoordinateSpec,{field:\"y1\"}],cx0:[l.XCoordinateSpec,{field:\"cx0\"}],cy0:[l.YCoordinateSpec,{field:\"cy0\"}],cx1:[l.XCoordinateSpec,{field:\"cx1\"}],cy1:[l.YCoordinateSpec,{field:\"cy1\"}]}))),c.mixins(r.LineVector)},\n function _(s,i,e,t,r){t();const a=s(1);var n;const h=s(178),d=s(48),l=s(24),_=s(20),c=(0,a.__importStar)(s(185)),u=(0,a.__importStar)(s(18)),o=s(9),x=s(12),m=s(72);class p extends h.XYGlyphView{async lazy_initialize(){await super.lazy_initialize();const{webgl:i}=this.renderer.plot_view.canvas_view;if(null!=i&&i.regl_wrapper.has_webgl){const{CircleGL:e}=await Promise.resolve().then((()=>(0,a.__importStar)(s(423))));this.glglyph=new e(i.regl_wrapper,this)}}get use_radius(){return!(this.radius.is_Scalar()&&isNaN(this.radius.value))}_set_data(s){super._set_data(s);const i=(()=>{if(this.use_radius)return 2*this.max_radius;{const{size:s}=this;return s.is_Scalar()?s.value:(0,x.max)(s.array)}})();this._configure(\"max_size\",{value:i})}_map_data(){if(this.use_radius)if(\"data\"==this.model.properties.radius.units)switch(this.model.radius_dimension){case\"x\":this.sradius=this.sdist(this.renderer.xscale,this._x,this.radius);break;case\"y\":this.sradius=this.sdist(this.renderer.yscale,this._y,this.radius);break;case\"max\":{const s=this.sdist(this.renderer.xscale,this._x,this.radius),i=this.sdist(this.renderer.yscale,this._y,this.radius);this.sradius=(0,x.map)(s,((s,e)=>Math.max(s,i[e])));break}case\"min\":{const s=this.sdist(this.renderer.xscale,this._x,this.radius),i=this.sdist(this.renderer.yscale,this._y,this.radius);this.sradius=(0,x.map)(s,((s,e)=>Math.min(s,i[e])));break}}else this.sradius=(0,l.to_screen)(this.radius);else{const s=l.ScreenArray.from(this.size);this.sradius=(0,x.map)(s,(s=>s/2))}}_mask_data(){const{frame:s}=this.renderer.plot_view,i=s.x_target,e=s.y_target;let t,r;return this.use_radius&&\"data\"==this.model.properties.radius.units?(t=i.map((s=>this.renderer.xscale.invert(s))).widen(this.max_radius),r=e.map((s=>this.renderer.yscale.invert(s))).widen(this.max_radius)):(t=i.widen(this.max_size).map((s=>this.renderer.xscale.invert(s))),r=e.widen(this.max_size).map((s=>this.renderer.yscale.invert(s)))),this.index.indices({x0:t.start,x1:t.end,y0:r.start,y1:r.end})}_render(s,i,e){const{sx:t,sy:r,sradius:a}=null!=e?e:this;for(const e of i){const i=t[e],n=r[e],h=a[e];isFinite(i+n+h)&&(s.beginPath(),s.arc(i,n,h,0,2*Math.PI,!1),this.visuals.fill.apply(s,e),this.visuals.hatch.apply(s,e),this.visuals.line.apply(s,e))}}_hit_point(s){const{sx:i,sy:e}=s,t=this.renderer.xscale.invert(i),r=this.renderer.yscale.invert(e),{hit_dilation:a}=this.model;let n,h,d,l;if(this.use_radius&&\"data\"==this.model.properties.radius.units)n=t-this.max_radius*a,h=t+this.max_radius*a,d=r-this.max_radius*a,l=r+this.max_radius*a;else{const s=i-this.max_size*a,t=i+this.max_size*a;[n,h]=this.renderer.xscale.r_invert(s,t);const r=e-this.max_size*a,_=e+this.max_size*a;[d,l]=this.renderer.yscale.r_invert(r,_)}const _=this.index.indices({x0:n,x1:h,y0:d,y1:l}),c=[];if(this.use_radius&&\"data\"==this.model.properties.radius.units)for(const s of _){const i=(this.sradius[s]*a)**2,[e,n]=this.renderer.xscale.r_compute(t,this._x[s]),[h,d]=this.renderer.yscale.r_compute(r,this._y[s]);(e-n)**2+(h-d)**2<=i&&c.push(s)}else for(const s of _){const t=(this.sradius[s]*a)**2;(this.sx[s]-i)**2+(this.sy[s]-e)**2<=t&&c.push(s)}return new m.Selection({indices:c})}_hit_span(s){const{sx:i,sy:e}=s,t=this.bounds();let r,a,n,h;if(\"h\"==s.direction){let s,e;if(n=t.y0,h=t.y1,this.use_radius&&\"data\"==this.model.properties.radius.units)s=i-this.max_radius,e=i+this.max_radius,[r,a]=this.renderer.xscale.r_invert(s,e);else{const t=this.max_size/2;s=i-t,e=i+t,[r,a]=this.renderer.xscale.r_invert(s,e)}}else{let s,i;if(r=t.x0,a=t.x1,this.use_radius&&\"data\"==this.model.properties.radius.units)s=e-this.max_radius,i=e+this.max_radius,[n,h]=this.renderer.yscale.r_invert(s,i);else{const t=this.max_size/2;s=e-t,i=e+t,[n,h]=this.renderer.yscale.r_invert(s,i)}}const d=[...this.index.indices({x0:r,x1:a,y0:n,y1:h})];return new m.Selection({indices:d})}_hit_rect(s){const{sx0:i,sx1:e,sy0:t,sy1:r}=s,[a,n]=this.renderer.xscale.r_invert(i,e),[h,d]=this.renderer.yscale.r_invert(t,r),l=[...this.index.indices({x0:a,x1:n,y0:h,y1:d})];return new m.Selection({indices:l})}_hit_poly(s){const{sx:i,sy:e}=s,t=(0,o.range)(0,this.sx.length),r=[];for(let s=0,a=t.length;s({angle:[u.AngleSpec,0],size:[u.ScreenSizeSpec,{value:4}],radius:[u.NullDistanceSpec,null],radius_dimension:[_.RadiusDimension,\"x\"],hit_dilation:[s,1]})))},\n function _(e,l,s,i,_){var p;i();const t=e(274);class a extends t.EllipseOvalView{}s.EllipseView=a,a.__name__=\"EllipseView\";class n extends t.EllipseOval{constructor(e){super(e)}}s.Ellipse=n,p=n,n.__name__=\"Ellipse\",p.prototype.default_view=a},\n function _(t,s,e,i,h){i();const n=t(1),r=t(275),a=(0,n.__importStar)(t(185)),l=t(24),_=t(72),o=(0,n.__importStar)(t(18));class d extends r.CenterRotatableView{_map_data(){\"data\"==this.model.properties.width.units?this.sw=this.sdist(this.renderer.xscale,this._x,this.width,\"center\"):this.sw=(0,l.to_screen)(this.width),\"data\"==this.model.properties.height.units?this.sh=this.sdist(this.renderer.yscale,this._y,this.height,\"center\"):this.sh=(0,l.to_screen)(this.height)}_render(t,s,e){const{sx:i,sy:h,sw:n,sh:r,angle:a}=null!=e?e:this;for(const e of s){const s=i[e],l=h[e],_=n[e],o=r[e],d=a.get(e);isFinite(s+l+_+o+d)&&(t.beginPath(),t.ellipse(s,l,_/2,o/2,d,0,2*Math.PI),this.visuals.fill.apply(t,e),this.visuals.hatch.apply(t,e),this.visuals.line.apply(t,e))}}_hit_point(t){let s,e,i,h,n,r,l,o,d;const{sx:c,sy:p}=t,w=this.renderer.xscale.invert(c),x=this.renderer.yscale.invert(p);\"data\"==this.model.properties.width.units?(s=w-this.max_width,e=w+this.max_width):(r=c-this.max_width,l=c+this.max_width,[s,e]=this.renderer.xscale.r_invert(r,l)),\"data\"==this.model.properties.height.units?(i=x-this.max_height,h=x+this.max_height):(o=p-this.max_height,d=p+this.max_height,[i,h]=this.renderer.yscale.r_invert(o,d));const m=this.index.indices({x0:s,x1:e,y0:i,y1:h}),y=[];for(const t of m)n=a.point_in_ellipse(c,p,this.angle.get(t),this.sh[t]/2,this.sw[t]/2,this.sx[t],this.sy[t]),n&&y.push(t);return new _.Selection({indices:y})}draw_legend_for_index(t,{x0:s,y0:e,x1:i,y1:h},n){const r=n+1,a=new Array(r);a[n]=(s+i)/2;const l=new Array(r);l[n]=(e+h)/2;const _=this.sw[n]/this.sh[n],d=.8*Math.min(Math.abs(i-s),Math.abs(h-e)),c=new Array(r),p=new Array(r);_>1?(c[n]=d,p[n]=d/_):(c[n]=d*_,p[n]=d);const w=new o.UniformScalar(0,r);this._render(t,[n],{sx:a,sy:l,sw:c,sh:p,angle:w})}}e.EllipseOvalView=d,d.__name__=\"EllipseOvalView\";class c extends r.CenterRotatable{constructor(t){super(t)}}e.EllipseOval=c,c.__name__=\"EllipseOval\"},\n function _(e,t,i,a,n){a();const s=e(1);var r;const h=e(178),o=e(48),_=(0,s.__importStar)(e(18));class c extends h.XYGlyphView{get max_w2(){return\"data\"==this.model.properties.width.units?this.max_width/2:0}get max_h2(){return\"data\"==this.model.properties.height.units?this.max_height/2:0}_bounds({x0:e,x1:t,y0:i,y1:a}){const{max_w2:n,max_h2:s}=this;return{x0:e-n,x1:t+n,y0:i-s,y1:a+s}}}i.CenterRotatableView=c,c.__name__=\"CenterRotatableView\";class l extends h.XYGlyph{constructor(e){super(e)}}i.CenterRotatable=l,r=l,l.__name__=\"CenterRotatable\",r.mixins([o.LineVector,o.FillVector,o.HatchVector]),r.define((({})=>({angle:[_.AngleSpec,0],width:[_.DistanceSpec,{field:\"width\"}],height:[_.DistanceSpec,{field:\"height\"}]})))},\n function _(t,e,s,i,r){i();const h=t(1);var a;const n=t(277),_=t(24),o=(0,h.__importStar)(t(18));class l extends n.BoxView{async lazy_initialize(){await super.lazy_initialize();const{webgl:e}=this.renderer.plot_view.canvas_view;if(null!=e&&e.regl_wrapper.has_webgl){const{LRTBGL:s}=await Promise.resolve().then((()=>(0,h.__importStar)(t(427))));this.glglyph=new s(e.regl_wrapper,this)}}scenterxy(t){return[(this.sleft[t]+this.sright[t])/2,this.sy[t]]}_lrtb(t){const e=this._left[t],s=this._right[t],i=this._y[t],r=this.height.get(t)/2;return[Math.min(e,s),Math.max(e,s),i+r,i-r]}_map_data(){this.sy=this.renderer.yscale.v_compute(this._y),this.sh=this.sdist(this.renderer.yscale,this._y,this.height,\"center\"),this.sleft=this.renderer.xscale.v_compute(this._left),this.sright=this.renderer.xscale.v_compute(this._right);const t=this.sy.length;this.stop=new _.ScreenArray(t),this.sbottom=new _.ScreenArray(t);for(let e=0;e({left:[o.XCoordinateSpec,{value:0}],y:[o.YCoordinateSpec,{field:\"y\"}],height:[o.NumberSpec,{value:1}],right:[o.XCoordinateSpec,{field:\"right\"}]})))},\n function _(t,e,s,r,i){var n;r();const a=t(48),h=t(179),o=t(184),c=t(72);class _ extends h.GlyphView{get_anchor_point(t,e,s){const r=Math.min(this.sleft[e],this.sright[e]),i=Math.max(this.sright[e],this.sleft[e]),n=Math.min(this.stop[e],this.sbottom[e]),a=Math.max(this.sbottom[e],this.stop[e]);switch(t){case\"top_left\":return{x:r,y:n};case\"top\":case\"top_center\":return{x:(r+i)/2,y:n};case\"top_right\":return{x:i,y:n};case\"bottom_left\":return{x:r,y:a};case\"bottom\":case\"bottom_center\":return{x:(r+i)/2,y:a};case\"bottom_right\":return{x:i,y:a};case\"left\":case\"center_left\":return{x:r,y:(n+a)/2};case\"center\":case\"center_center\":return{x:(r+i)/2,y:(n+a)/2};case\"right\":case\"center_right\":return{x:i,y:(n+a)/2}}}_index_data(t){const{min:e,max:s}=Math,{data_size:r}=this;for(let i=0;i(0,n.__importStar)(e(425))));this.glglyph=new s(t.regl_wrapper,this)}}scenterxy(e){return[this.sx[e],this.sy[e]]}_set_data(){const{orientation:e,size:t,aspect_scale:s}=this.model,{q:i,r}=this,n=this.q.length;this._x=new Float64Array(n),this._y=new Float64Array(n);const{_x:a,_y:l}=this,o=Math.sqrt(3);if(\"pointytop\"==e)for(let e=0;e({r:[c.NumberSpec,{field:\"r\"}],q:[c.NumberSpec,{field:\"q\"}],scale:[c.NumberSpec,1],size:[e,1],aspect_scale:[e,1],orientation:[_.HexTileOrientation,\"pointytop\"]}))),a.override({line_color:null})},\n function _(e,a,t,_,r){var n;_();const s=e(280),o=e(173),i=e(201);class p extends s.ImageBaseView{connect_signals(){super.connect_signals(),this.connect(this.model.color_mapper.change,(()=>this._update_image()))}_update_image(){null!=this.image_data&&(this._set_data(null),this.renderer.request_render())}_flat_img_to_buf8(e){return this.model.color_mapper.rgba_mapper.v_compute(e)}}t.ImageView=p,p.__name__=\"ImageView\";class m extends s.ImageBase{constructor(e){super(e)}}t.Image=m,n=m,m.__name__=\"Image\",n.prototype.default_view=p,n.define((({Ref:e})=>({color_mapper:[e(o.ColorMapper),()=>new i.LinearColorMapper({palette:[\"#000000\",\"#252525\",\"#525252\",\"#737373\",\"#969696\",\"#bdbdbd\",\"#d9d9d9\",\"#f0f0f0\",\"#ffffff\"]})]})))},\n function _(e,t,i,s,a){s();const h=e(1);var n;const r=e(178),_=e(24),d=(0,h.__importStar)(e(18)),l=e(72),g=e(9),o=e(29),c=e(11);class m extends r.XYGlyphView{connect_signals(){super.connect_signals(),this.connect(this.model.properties.global_alpha.change,(()=>this.renderer.request_render()))}_render(e,t,i){const{image_data:s,sx:a,sy:h,sw:n,sh:r,global_alpha:_}=null!=i?i:this,d=e.getImageSmoothingEnabled();e.setImageSmoothingEnabled(!1);const l=_.is_Scalar();l&&(e.globalAlpha=_.value);for(const i of t){const t=s[i],_=a[i],d=h[i],g=n[i],o=r[i],c=this.global_alpha.get(i);if(null==t||!isFinite(_+d+g+o+c))continue;l||(e.globalAlpha=c);const m=d;e.translate(0,m),e.scale(1,-1),e.translate(0,-m),e.drawImage(t,0|_,0|d,g,o),e.translate(0,m),e.scale(1,-1),e.translate(0,-m)}e.setImageSmoothingEnabled(d)}_set_data(e){this._set_width_heigh_data();for(let t=0,i=this.image.length;t({image:[d.NDArraySpec,{field:\"image\"}],dw:[d.DistanceSpec,{field:\"dw\"}],dh:[d.DistanceSpec,{field:\"dh\"}],global_alpha:[d.NumberSpec,{value:1}],dilate:[e,!1]})))},\n function _(e,a,t,r,_){var n;r();const s=e(280),m=e(8);class i extends s.ImageBaseView{_flat_img_to_buf8(e){let a;return a=(0,m.isArray)(e)?new Uint32Array(e):e,new Uint8ClampedArray(a.buffer)}}t.ImageRGBAView=i,i.__name__=\"ImageRGBAView\";class g extends s.ImageBase{constructor(e){super(e)}}t.ImageRGBA=g,n=g,g.__name__=\"ImageRGBA\",n.prototype.default_view=i},\n function _(e,t,s,r,a){r();const i=e(1);var n;const o=e(178),c=e(24),_=e(20),h=(0,i.__importStar)(e(18)),l=e(12),d=e(136);class m extends o.XYGlyphView{constructor(){super(...arguments),this._images_rendered=!1,this._set_data_iteration=0}connect_signals(){super.connect_signals(),this.connect(this.model.properties.global_alpha.change,(()=>this.renderer.request_render()))}_index_data(e){const{data_size:t}=this;for(let s=0;s{this._set_data_iteration==r&&(this.image[a]=e,this.renderer.request_render())},attempts:t+1,timeout:s})}const a=\"data\"==this.model.properties.w.units,i=\"data\"==this.model.properties.h.units,n=this._x.length,o=new c.ScreenArray(a?2*n:n),_=new c.ScreenArray(i?2*n:n),{anchor:h}=this.model;function m(e,t){switch(h){case\"top_left\":case\"bottom_left\":case\"left\":case\"center_left\":return[e,e+t];case\"top\":case\"top_center\":case\"bottom\":case\"bottom_center\":case\"center\":case\"center_center\":return[e-t/2,e+t/2];case\"top_right\":case\"bottom_right\":case\"right\":case\"center_right\":return[e-t,e]}}function g(e,t){switch(h){case\"top_left\":case\"top\":case\"top_center\":case\"top_right\":return[e,e-t];case\"bottom_left\":case\"bottom\":case\"bottom_center\":case\"bottom_right\":return[e+t,e];case\"left\":case\"center_left\":case\"center\":case\"center_center\":case\"right\":case\"center_right\":return[e+t/2,e-t/2]}}if(a)for(let e=0;e({url:[h.StringSpec,{field:\"url\"}],anchor:[_.Anchor,\"top_left\"],global_alpha:[h.NumberSpec,{value:1}],angle:[h.AngleSpec,0],w:[h.NullDistanceSpec,null],h:[h.NullDistanceSpec,null],dilate:[e,!1],retry_attempts:[t,0],retry_timeout:[t,0]})))},\n function _(e,t,s,i,n){i();const o=e(1);var r;const l=e(78),_=e(48),c=(0,o.__importStar)(e(185)),h=(0,o.__importStar)(e(18)),a=e(12),d=e(13),x=e(179),y=e(184),g=e(72);class p extends x.GlyphView{_project_data(){l.inplace.project_xy(this._xs.array,this._ys.array)}_index_data(e){const{data_size:t}=this;for(let s=0;s0&&o.set(e,s)}return new g.Selection({indices:[...o.keys()],multiline_indices:(0,d.to_object)(o)})}get_interpolation_hit(e,t,s){const i=this._xs.get(e),n=this._ys.get(e),o=i[t],r=n[t],l=i[t+1],_=n[t+1];return(0,y.line_interpolation)(this.renderer,s,o,r,l,_)}draw_legend_for_index(e,t,s){(0,y.generic_line_vector_legend)(this.visuals,e,t,s)}scenterxy(){throw new Error(`${this}.scenterxy() is not implemented`)}}s.MultiLineView=p,p.__name__=\"MultiLineView\";class u extends x.Glyph{constructor(e){super(e)}}s.MultiLine=u,r=u,u.__name__=\"MultiLine\",r.prototype.default_view=p,r.define((({})=>({xs:[h.XCoordinateSeqSpec,{field:\"xs\"}],ys:[h.YCoordinateSeqSpec,{field:\"ys\"}]}))),r.mixins(_.LineVector)},\n function _(t,e,s,n,i){n();const o=t(1);var r;const l=t(181),h=t(179),a=t(184),_=t(12),c=t(12),d=t(48),x=(0,o.__importStar)(t(185)),y=(0,o.__importStar)(t(18)),f=t(72),g=t(11);class p extends h.GlyphView{_project_data(){}_index_data(t){const{min:e,max:s}=Math,{data_size:n}=this;for(let i=0;i1&&c.length>1)for(let s=1,n=i.length;s1){let r=!1;for(let t=1;t({xs:[y.XCoordinateSeqSeqSeqSpec,{field:\"xs\"}],ys:[y.YCoordinateSeqSeqSeqSpec,{field:\"ys\"}]}))),r.mixins([d.LineVector,d.FillVector,d.HatchVector])},\n function _(a,e,l,s,_){var t;s();const i=a(274),n=a(12);class p extends i.EllipseOvalView{_map_data(){super._map_data(),(0,n.mul)(this.sw,.75)}}l.OvalView=p,p.__name__=\"OvalView\";class v extends i.EllipseOval{constructor(a){super(a)}}l.Oval=v,t=v,v.__name__=\"Oval\",t.prototype.default_view=p},\n function _(e,t,s,i,n){i();const r=e(1);var a;const o=e(179),c=e(184),_=e(12),h=e(48),l=(0,r.__importStar)(e(185)),d=(0,r.__importStar)(e(18)),y=e(72),p=e(11),x=e(78);class f extends o.GlyphView{_project_data(){x.inplace.project_xy(this._xs.array,this._ys.array)}_index_data(e){const{data_size:t}=this;for(let s=0;s({xs:[d.XCoordinateSeqSpec,{field:\"xs\"}],ys:[d.YCoordinateSeqSpec,{field:\"ys\"}]}))),a.mixins([h.LineVector,h.FillVector,h.HatchVector])},\n function _(t,e,i,o,r){o();const s=t(1);var a;const n=t(277),l=(0,s.__importStar)(t(18));class _ extends n.BoxView{async lazy_initialize(){await super.lazy_initialize();const{webgl:e}=this.renderer.plot_view.canvas_view;if(null!=e&&e.regl_wrapper.has_webgl){const{LRTBGL:i}=await Promise.resolve().then((()=>(0,s.__importStar)(t(427))));this.glglyph=new i(e.regl_wrapper,this)}}scenterxy(t){return[this.sleft[t]/2+this.sright[t]/2,this.stop[t]/2+this.sbottom[t]/2]}_lrtb(t){return[this._left[t],this._right[t],this._top[t],this._bottom[t]]}}i.QuadView=_,_.__name__=\"QuadView\";class p extends n.Box{constructor(t){super(t)}}i.Quad=p,a=p,p.__name__=\"Quad\",a.prototype.default_view=_,a.define((({})=>({right:[l.XCoordinateSpec,{field:\"right\"}],bottom:[l.YCoordinateSpec,{field:\"bottom\"}],left:[l.XCoordinateSpec,{field:\"left\"}],top:[l.YCoordinateSpec,{field:\"top\"}]})))},\n function _(e,t,i,n,s){n();const c=e(1);var o;const r=e(48),a=e(78),_=e(179),d=e(184),l=(0,c.__importStar)(e(18));function x(e,t,i){if(t==(e+i)/2)return[e,i];{const n=(e-t)/(e-2*t+i),s=e*(1-n)**2+2*t*(1-n)*n+i*n**2;return[Math.min(e,i,s),Math.max(e,i,s)]}}class y extends _.GlyphView{_project_data(){a.inplace.project_xy(this._x0,this._y0),a.inplace.project_xy(this._x1,this._y1)}_index_data(e){const{_x0:t,_x1:i,_y0:n,_y1:s,_cx:c,_cy:o,data_size:r}=this;for(let a=0;a({x0:[l.XCoordinateSpec,{field:\"x0\"}],y0:[l.YCoordinateSpec,{field:\"y0\"}],x1:[l.XCoordinateSpec,{field:\"x1\"}],y1:[l.YCoordinateSpec,{field:\"y1\"}],cx:[l.XCoordinateSpec,{field:\"cx\"}],cy:[l.YCoordinateSpec,{field:\"cy\"}]}))),o.mixins(r.LineVector)},\n function _(e,t,s,i,n){i();const l=e(1);var a;const r=e(178),o=e(184),h=e(48),_=e(24),c=(0,l.__importStar)(e(18));class g extends r.XYGlyphView{_map_data(){\"data\"==this.model.properties.length.units?this.slength=this.sdist(this.renderer.xscale,this._x,this.length):this.slength=(0,_.to_screen)(this.length);const{width:e,height:t}=this.renderer.plot_view.frame.bbox,s=2*(e+t),{slength:i}=this;for(let e=0,t=i.length;e({length:[c.DistanceSpec,0],angle:[c.AngleSpec,0]})))},\n function _(t,e,s,i,r){var n,h=this&&this.__createBinding||(Object.create?function(t,e,s,i){void 0===i&&(i=s),Object.defineProperty(t,i,{enumerable:!0,get:function(){return e[s]}})}:function(t,e,s,i){void 0===i&&(i=s),t[i]=e[s]}),a=this&&this.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,\"default\",{enumerable:!0,value:e})}:function(t,e){t.default=e}),l=this&&this.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var s in t)\"default\"!==s&&Object.prototype.hasOwnProperty.call(t,s)&&h(e,t,s);return a(e,t),e};i();const o=t(275),c=t(184),_=t(24),d=t(12),f=t(72);class y extends o.CenterRotatableView{async lazy_initialize(){await super.lazy_initialize();const{webgl:e}=this.renderer.plot_view.canvas_view;if(null==e?void 0:e.regl_wrapper.has_webgl){const{RectGL:s}=await Promise.resolve().then((()=>l(t(429))));this.glglyph=new s(e.regl_wrapper,this)}}_map_data(){if(\"data\"==this.model.properties.width.units)[this.sw,this.sx0]=this._map_dist_corner_for_data_side_length(this._x,this.width,this.renderer.xscale);else{this.sw=(0,_.to_screen)(this.width);const t=this.sx.length;this.sx0=new _.ScreenArray(t);for(let e=0;e({dilate:[t,!1]})))},\n function _(e,t,r,a,s){a();const i=e(1);var n;const l=e(292),_=e(293),c=(0,i.__importStar)(e(18));class o extends l.MarkerView{async lazy_initialize(){await super.lazy_initialize();const{webgl:t}=this.renderer.plot_view.canvas_view;if(null!=t&&t.regl_wrapper.has_webgl){const{MultiMarkerGL:r}=await Promise.resolve().then((()=>(0,i.__importStar)(e(428))));this.glglyph=new r(t.regl_wrapper,this)}}_render(e,t,r){const{sx:a,sy:s,size:i,angle:n,marker:l}=null!=r?r:this;for(const r of t){const t=a[r],c=s[r],o=i.get(r),g=n.get(r),w=l.get(r);if(!isFinite(t+c+o+g)||null==w)continue;const p=o/2;e.beginPath(),e.translate(t,c),g&&e.rotate(g),_.marker_funcs[w](e,r,p,this.visuals),g&&e.rotate(-g),e.translate(-t,-c)}}draw_legend_for_index(e,{x0:t,x1:r,y0:a,y1:s},i){const n=i+1,l=this.marker.get(i),_=Object.assign(Object.assign({},this._get_legend_args({x0:t,x1:r,y0:a,y1:s},i)),{marker:new c.UniformScalar(l,n)});this._render(e,[i],_)}}r.ScatterView=o,o.__name__=\"ScatterView\";class g extends l.Marker{constructor(e){super(e)}}r.Scatter=g,n=g,g.__name__=\"Scatter\",n.prototype.default_view=o,n.define((()=>({marker:[c.MarkerSpec,{value:\"circle\"}]})))},\n function _(e,t,s,n,i){n();const r=e(1);var a;const c=e(178),o=e(48),_=(0,r.__importStar)(e(185)),h=(0,r.__importStar)(e(18)),l=e(9),x=e(72);class d extends c.XYGlyphView{_render(e,t,s){const{sx:n,sy:i,size:r,angle:a}=null!=s?s:this;for(const s of t){const t=n[s],c=i[s],o=r.get(s),_=a.get(s);if(!isFinite(t+c+o+_))continue;const h=o/2;e.beginPath(),e.translate(t,c),_&&e.rotate(_),this._render_one(e,s,h,this.visuals),_&&e.rotate(-_),e.translate(-t,-c)}}_mask_data(){const{x_target:e,y_target:t}=this.renderer.plot_view.frame,s=e.widen(this.max_size).map((e=>this.renderer.xscale.invert(e))),n=t.widen(this.max_size).map((e=>this.renderer.yscale.invert(e)));return this.index.indices({x0:s.start,x1:s.end,y0:n.start,y1:n.end})}_hit_point(e){const{sx:t,sy:s}=e,{max_size:n}=this,{hit_dilation:i}=this.model,r=t-n*i,a=t+n*i,[c,o]=this.renderer.xscale.r_invert(r,a),_=s-n*i,h=s+n*i,[l,d]=this.renderer.yscale.r_invert(_,h),y=this.index.indices({x0:c,x1:o,y0:l,y1:d}),g=[];for(const e of y){const n=this.size.get(e)/2*i;Math.abs(this.sx[e]-t)<=n&&Math.abs(this.sy[e]-s)<=n&&g.push(e)}return new x.Selection({indices:g})}_hit_span(e){const{sx:t,sy:s}=e,n=this.bounds(),i=this.max_size/2;let r,a,c,o;if(\"h\"==e.direction){c=n.y0,o=n.y1;const e=t-i,s=t+i;[r,a]=this.renderer.xscale.r_invert(e,s)}else{r=n.x0,a=n.x1;const e=s-i,t=s+i;[c,o]=this.renderer.yscale.r_invert(e,t)}const _=[...this.index.indices({x0:r,x1:a,y0:c,y1:o})];return new x.Selection({indices:_})}_hit_rect(e){const{sx0:t,sx1:s,sy0:n,sy1:i}=e,[r,a]=this.renderer.xscale.r_invert(t,s),[c,o]=this.renderer.yscale.r_invert(n,i),_=[...this.index.indices({x0:r,x1:a,y0:c,y1:o})];return new x.Selection({indices:_})}_hit_poly(e){const{sx:t,sy:s}=e,n=(0,l.range)(0,this.sx.length),i=[];for(let e=0,r=n.length;e({size:[h.ScreenSizeSpec,{value:4}],angle:[h.AngleSpec,0],hit_dilation:[e,1]})))},\n function _(l,o,n,t,i){t();const e=Math.sqrt(3),a=Math.sqrt(5),c=(a+1)/4,p=Math.sqrt((5-a)/8),r=(a-1)/4,h=Math.sqrt((5+a)/8);function u(l,o){l.rotate(Math.PI/4),s(l,o),l.rotate(-Math.PI/4)}function f(l,o){const n=o*e,t=n/3;l.moveTo(-n/2,-t),l.lineTo(0,0),l.lineTo(n/2,-t),l.lineTo(0,0),l.lineTo(0,o)}function s(l,o){l.moveTo(0,o),l.lineTo(0,-o),l.moveTo(-o,0),l.lineTo(o,0)}function T(l,o){l.moveTo(0,o),l.lineTo(o/1.5,0),l.lineTo(0,-o),l.lineTo(-o/1.5,0),l.closePath()}function y(l,o){const n=o*e,t=n/3;l.moveTo(-o,t),l.lineTo(o,t),l.lineTo(0,t-n),l.closePath()}function v(l,o,n,t){l.arc(0,0,n,0,2*Math.PI,!1),t.fill.apply(l,o),t.hatch.apply(l,o),t.line.apply(l,o)}function d(l,o,n,t){T(l,n),t.fill.apply(l,o),t.hatch.apply(l,o),t.line.apply(l,o)}function _(l,o,n,t){!function(l,o){l.beginPath(),l.arc(0,0,o/4,0,2*Math.PI,!1),l.closePath()}(l,n),t.line.set_vectorize(l,o),l.fillStyle=l.strokeStyle,l.fill()}function P(l,o,n,t){!function(l,o){const n=o/2,t=e*n;l.moveTo(o,0),l.lineTo(n,-t),l.lineTo(-n,-t),l.lineTo(-o,0),l.lineTo(-n,t),l.lineTo(n,t),l.closePath()}(l,n),t.fill.apply(l,o),t.hatch.apply(l,o),t.line.apply(l,o)}function m(l,o,n,t){const i=2*n;l.rect(-n,-n,i,i),t.fill.apply(l,o),t.hatch.apply(l,o),t.line.apply(l,o)}function q(l,o,n,t){!function(l,o){const n=Math.sqrt(5-2*a)*o;l.moveTo(0,-o),l.lineTo(n*r,n*h-o),l.lineTo(n*(1+r),n*h-o),l.lineTo(n*(1+r-c),n*(h+p)-o),l.lineTo(n*(1+2*r-c),n*(2*h+p)-o),l.lineTo(0,2*n*h-o),l.lineTo(-n*(1+2*r-c),n*(2*h+p)-o),l.lineTo(-n*(1+r-c),n*(h+p)-o),l.lineTo(-n*(1+r),n*h-o),l.lineTo(-n*r,n*h-o),l.closePath()}(l,n),t.fill.apply(l,o),t.hatch.apply(l,o),t.line.apply(l,o)}function M(l,o,n,t){y(l,n),t.fill.apply(l,o),t.hatch.apply(l,o),t.line.apply(l,o)}n.marker_funcs={asterisk:function(l,o,n,t){s(l,n),u(l,n),t.line.apply(l,o)},circle:v,circle_cross:function(l,o,n,t){l.arc(0,0,n,0,2*Math.PI,!1),t.fill.apply(l,o),t.hatch.apply(l,o),t.line.doit&&(t.line.set_vectorize(l,o),s(l,n),l.stroke())},circle_dot:function(l,o,n,t){v(l,o,n,t),_(l,o,n,t)},circle_y:function(l,o,n,t){l.arc(0,0,n,0,2*Math.PI,!1),t.fill.apply(l,o),t.hatch.apply(l,o),t.line.doit&&(t.line.set_vectorize(l,o),f(l,n),l.stroke())},circle_x:function(l,o,n,t){l.arc(0,0,n,0,2*Math.PI,!1),t.fill.apply(l,o),t.hatch.apply(l,o),t.line.doit&&(t.line.set_vectorize(l,o),u(l,n),l.stroke())},cross:function(l,o,n,t){s(l,n),t.line.apply(l,o)},diamond:d,diamond_dot:function(l,o,n,t){d(l,o,n,t),_(l,o,n,t)},diamond_cross:function(l,o,n,t){T(l,n),t.fill.apply(l,o),t.hatch.apply(l,o),t.line.doit&&(t.line.set_vectorize(l,o),l.moveTo(0,n),l.lineTo(0,-n),l.moveTo(-n/1.5,0),l.lineTo(n/1.5,0),l.stroke())},dot:_,hex:P,hex_dot:function(l,o,n,t){P(l,o,n,t),_(l,o,n,t)},inverted_triangle:function(l,o,n,t){l.rotate(Math.PI),y(l,n),l.rotate(-Math.PI),t.fill.apply(l,o),t.hatch.apply(l,o),t.line.apply(l,o)},plus:function(l,o,n,t){const i=3*n/8,e=[i,i,n,n,i,i,-i,-i,-n,-n,-i,-i],a=[n,i,i,-i,-i,-n,-n,-i,-i,i,i,n];l.beginPath();for(let o=0;o<12;o++)l.lineTo(e[o],a[o]);l.closePath(),t.fill.apply(l,o),t.hatch.apply(l,o),t.line.apply(l,o)},square:m,square_cross:function(l,o,n,t){const i=2*n;l.rect(-n,-n,i,i),t.fill.apply(l,o),t.hatch.apply(l,o),t.line.doit&&(t.line.set_vectorize(l,o),s(l,n),l.stroke())},square_dot:function(l,o,n,t){m(l,o,n,t),_(l,o,n,t)},square_pin:function(l,o,n,t){const i=3*n/8;l.moveTo(-n,-n),l.quadraticCurveTo(0,-i,n,-n),l.quadraticCurveTo(i,0,n,n),l.quadraticCurveTo(0,i,-n,n),l.quadraticCurveTo(-i,0,-n,-n),l.closePath(),t.fill.apply(l,o),t.hatch.apply(l,o),t.line.apply(l,o)},square_x:function(l,o,n,t){const i=2*n;l.rect(-n,-n,i,i),t.fill.apply(l,o),t.hatch.apply(l,o),t.line.doit&&(t.line.set_vectorize(l,o),l.moveTo(-n,n),l.lineTo(n,-n),l.moveTo(-n,-n),l.lineTo(n,n),l.stroke())},star:q,star_dot:function(l,o,n,t){q(l,o,n,t),_(l,o,n,t)},triangle:M,triangle_dot:function(l,o,n,t){M(l,o,n,t),_(l,o,n,t)},triangle_pin:function(l,o,n,t){const i=n*e,a=i/3,c=3*a/8;l.moveTo(-n,a),l.quadraticCurveTo(0,c,n,a),l.quadraticCurveTo(e*c/2,c/2,0,a-i),l.quadraticCurveTo(-e*c/2,c/2,-n,a),l.closePath(),t.fill.apply(l,o),t.hatch.apply(l,o),t.line.apply(l,o)},dash:function(l,o,n,t){!function(l,o){l.moveTo(-o,0),l.lineTo(o,0)}(l,n),t.line.apply(l,o)},x:function(l,o,n,t){u(l,n),t.line.apply(l,o)},y:function(l,o,n,t){f(l,n),t.line.apply(l,o)}}},\n function _(e,t,s,i,n){i();const r=e(1);var o;const _=(0,r.__importStar)(e(185)),h=(0,r.__importStar)(e(18)),c=e(48),a=e(78),d=e(179),x=e(184),l=e(72);class y extends d.GlyphView{_project_data(){a.inplace.project_xy(this._x0,this._y0),a.inplace.project_xy(this._x1,this._y1)}_index_data(e){const{min:t,max:s}=Math,{_x0:i,_x1:n,_y0:r,_y1:o,data_size:_}=this;for(let h=0;h<_;h++){const _=i[h],c=n[h],a=r[h],d=o[h];e.add_rect(t(_,c),t(a,d),s(_,c),s(a,d))}}_render(e,t,s){if(this.visuals.line.doit){const{sx0:i,sy0:n,sx1:r,sy1:o}=null!=s?s:this;for(const s of t){const t=i[s],_=n[s],h=r[s],c=o[s];isFinite(t+_+h+c)&&(e.beginPath(),e.moveTo(t,_),e.lineTo(h,c),this.visuals.line.set_vectorize(e,s),e.stroke())}}}_hit_point(e){const{sx:t,sy:s}=e,i={x:t,y:s},[n,r]=this.renderer.xscale.r_invert(t-2,t+2),[o,h]=this.renderer.yscale.r_invert(s-2,s+2),c=this.index.indices({x0:n,y0:o,x1:r,y1:h}),a=[];for(const e of c){const t=Math.max(2,this.line_width.get(e)/2)**2,s={x:this.sx0[e],y:this.sy0[e]},n={x:this.sx1[e],y:this.sy1[e]};_.dist_to_segment_squared(i,s,n)({x0:[h.XCoordinateSpec,{field:\"x0\"}],y0:[h.YCoordinateSpec,{field:\"y0\"}],x1:[h.XCoordinateSpec,{field:\"x1\"}],y1:[h.YCoordinateSpec,{field:\"y1\"}]}))),o.mixins(c.LineVector)},\n function _(t,e,s,i,n){i();const o=t(1);var _;const l=t(178),a=(0,o.__importStar)(t(48)),c=t(296);class r extends l.XYGlyphView{_set_data(){const{tension:t,closed:e}=this.model;[this._xt,this._yt]=(0,c.catmullrom_spline)(this._x,this._y,20,t,e)}_map_data(){const{x_scale:t,y_scale:e}=this.renderer.coordinates;this.sxt=t.v_compute(this._xt),this.syt=e.v_compute(this._yt)}_render(t,e,s){const{sxt:i,syt:n}=null!=s?s:this;let o=!0;t.beginPath();const _=i.length;for(let e=0;e<_;e++){const s=i[e],_=n[e];isFinite(s+_)?o?(t.moveTo(s,_),o=!1):t.lineTo(s,_):o=!0}this.visuals.line.set_value(t),t.stroke()}}s.SplineView=r,r.__name__=\"SplineView\";class h extends l.XYGlyph{constructor(t){super(t)}}s.Spline=h,_=h,h.__name__=\"Spline\",_.prototype.default_view=r,_.mixins(a.LineScalar),_.define((({Boolean:t,Number:e})=>({tension:[e,.5],closed:[t,!1]})))},\n function _(n,t,e,o,s){o();const c=n(24),l=n(11);e.catmullrom_spline=function(n,t,e=10,o=.5,s=!1){(0,l.assert)(n.length==t.length);const r=n.length,f=s?r+1:r,w=(0,c.infer_type)(n,t),i=new w(f+2),u=new w(f+2);i.set(n,1),u.set(t,1),s?(i[0]=n[r-1],u[0]=t[r-1],i[f]=n[0],u[f]=t[0],i[f+1]=n[1],u[f+1]=t[1]):(i[0]=n[0],u[0]=t[0],i[f+1]=n[r-1],u[f+1]=t[r-1]);const g=new w(4*(e+1));for(let n=0,t=0;n<=e;n++){const o=n/e,s=o**2,c=o*s;g[t++]=2*c-3*s+1,g[t++]=-2*c+3*s,g[t++]=c-2*s+o,g[t++]=c-s}const h=new w((f-1)*(e+1)),_=new w((f-1)*(e+1));for(let n=1,t=0;n1&&(e.stroke(),o=!1)}o?(e.lineTo(t,r),e.lineTo(a,c)):(e.beginPath(),e.moveTo(s[n],i[n]),o=!0),l=n}e.lineTo(s[a-1],i[a-1]),e.stroke()}}draw_legend_for_index(e,t,n){(0,r.generic_line_scalar_legend)(this.visuals,e,t)}}n.StepView=f,f.__name__=\"StepView\";class u extends a.XYGlyph{constructor(e){super(e)}}n.Step=u,l=u,u.__name__=\"Step\",l.prototype.default_view=f,l.mixins(c.LineScalar),l.define((()=>({mode:[_.StepMode,\"before\"]})))},\n function _(t,e,s,i,n){i();const o=t(1);var _;const h=t(178),l=t(48),r=(0,o.__importStar)(t(185)),a=(0,o.__importStar)(t(18)),c=t(121),x=t(11),u=t(72);class f extends h.XYGlyphView{_rotate_point(t,e,s,i,n){return[(t-s)*Math.cos(n)-(e-i)*Math.sin(n)+s,(t-s)*Math.sin(n)+(e-i)*Math.cos(n)+i]}_text_bounds(t,e,s,i){return[[t,t+s,t+s,t,t],[e,e,e-i,e-i,e]]}_render(t,e,s){const{sx:i,sy:n,x_offset:o,y_offset:_,angle:h,text:l}=null!=s?s:this;this._sys=[],this._sxs=[];for(const s of e){const e=this._sxs[s]=[],r=this._sys[s]=[],a=i[s],x=n[s],u=o.get(s),f=_.get(s),p=h.get(s),g=l.get(s);if(isFinite(a+x+u+f+p)&&null!=g&&this.visuals.text.doit){const i=`${g}`;t.save(),t.translate(a+u,x+f),t.rotate(p),this.visuals.text.set_vectorize(t,s);const n=this.visuals.text.font_value(s),{height:o}=(0,c.font_metrics)(n),_=this.text_line_height.get(s)*o;if(-1==i.indexOf(\"\\n\")){t.fillText(i,0,0);const s=a+u,n=x+f,o=t.measureText(i).width,[h,l]=this._text_bounds(s,n,o,_);e.push(h),r.push(l)}else{const n=i.split(\"\\n\"),o=_*n.length,h=this.text_baseline.get(s);let l;switch(h){case\"top\":l=0;break;case\"middle\":l=-o/2+_/2;break;case\"bottom\":l=-o+_;break;default:l=0,console.warn(`'${h}' baseline not supported with multi line text`)}for(const s of n){t.fillText(s,0,l);const i=a+u,n=l+x+f,o=t.measureText(s).width,[h,c]=this._text_bounds(i,n,o,_);e.push(h),r.push(c),l+=_}}t.restore()}}}_hit_point(t){const{sx:e,sy:s}=t,i=[];for(let t=0;t({text:[a.NullStringSpec,{field:\"text\"}],angle:[a.AngleSpec,0],x_offset:[a.NumberSpec,0],y_offset:[a.NumberSpec,0]})))},\n function _(t,e,s,i,r){i();const h=t(1);var o;const a=t(277),n=t(24),_=(0,h.__importStar)(t(18));class l extends a.BoxView{async lazy_initialize(){await super.lazy_initialize();const{webgl:e}=this.renderer.plot_view.canvas_view;if(null!=e&&e.regl_wrapper.has_webgl){const{LRTBGL:s}=await Promise.resolve().then((()=>(0,h.__importStar)(t(427))));this.glglyph=new s(e.regl_wrapper,this)}}scenterxy(t){return[this.sx[t],(this.stop[t]+this.sbottom[t])/2]}_lrtb(t){const e=this.width.get(t)/2,s=this._x[t],i=this._top[t],r=this._bottom[t];return[s-e,s+e,Math.max(i,r),Math.min(i,r)]}_map_data(){this.sx=this.renderer.xscale.v_compute(this._x),this.sw=this.sdist(this.renderer.xscale,this._x,this.width,\"center\"),this.stop=this.renderer.yscale.v_compute(this._top),this.sbottom=this.renderer.yscale.v_compute(this._bottom);const t=this.sx.length;this.sleft=new n.ScreenArray(t),this.sright=new n.ScreenArray(t);for(let e=0;e({x:[_.XCoordinateSpec,{field:\"x\"}],bottom:[_.YCoordinateSpec,{value:0}],width:[_.NumberSpec,{value:1}],top:[_.YCoordinateSpec,{field:\"top\"}]})))},\n function _(e,s,t,i,n){i();const r=e(1);var a;const c=e(178),d=e(184),l=e(48),h=e(24),o=e(20),_=(0,r.__importStar)(e(18)),u=e(10),g=e(72),x=e(12);class p extends c.XYGlyphView{_map_data(){\"data\"==this.model.properties.radius.units?this.sradius=this.sdist(this.renderer.xscale,this._x,this.radius):this.sradius=(0,h.to_screen)(this.radius),this.max_sradius=(0,x.max)(this.sradius)}_render(e,s,t){const{sx:i,sy:n,sradius:r,start_angle:a,end_angle:c}=null!=t?t:this,d=\"anticlock\"==this.model.direction;for(const t of s){const s=i[t],l=n[t],h=r[t],o=a.get(t),_=c.get(t);isFinite(s+l+h+o+_)&&(e.beginPath(),e.arc(s,l,h,o,_,d),e.lineTo(s,l),e.closePath(),this.visuals.fill.apply(e,t),this.visuals.hatch.apply(e,t),this.visuals.line.apply(e,t))}}_hit_point(e){let s,t,i,n,r;const{sx:a,sy:c}=e,d=this.renderer.xscale.invert(a),l=this.renderer.yscale.invert(c);t=a-this.max_sradius,i=a+this.max_sradius;const[h,o]=this.renderer.xscale.r_invert(t,i);n=c-this.max_sradius,r=c+this.max_sradius;const[_,x]=this.renderer.yscale.r_invert(n,r),p=[];for(const e of this.index.indices({x0:h,x1:o,y0:_,y1:x})){const a=this.sradius[e]**2;[t,i]=this.renderer.xscale.r_compute(d,this._x[e]),[n,r]=this.renderer.yscale.r_compute(l,this._y[e]),s=(t-i)**2+(n-r)**2,s<=a&&p.push(e)}const y=\"anticlock\"==this.model.direction,m=[];for(const e of p){const s=Math.atan2(c-this.sy[e],a-this.sx[e]);(0,u.angle_between)(-s,-this.start_angle.get(e),-this.end_angle.get(e),y)&&m.push(e)}return new g.Selection({indices:m})}draw_legend_for_index(e,s,t){(0,d.generic_area_vector_legend)(this.visuals,e,s,t)}scenterxy(e){const s=this.sradius[e]/2,t=(this.start_angle.get(e)+this.end_angle.get(e))/2;return[this.sx[e]+s*Math.cos(t),this.sy[e]+s*Math.sin(t)]}}t.WedgeView=p,p.__name__=\"WedgeView\";class y extends c.XYGlyph{constructor(e){super(e)}}t.Wedge=y,a=y,y.__name__=\"Wedge\",a.prototype.default_view=p,a.mixins([l.LineVector,l.FillVector,l.HatchVector]),a.define((({})=>({direction:[o.Direction,\"anticlock\"],radius:[_.DistanceSpec,{field:\"radius\"}],start_angle:[_.AngleSpec,{field:\"start_angle\"}],end_angle:[_.AngleSpec,{field:\"end_angle\"}]})))},\n function _(t,_,r,o,a){o();const e=t(1);(0,e.__exportStar)(t(302),r),(0,e.__exportStar)(t(303),r),(0,e.__exportStar)(t(304),r)},\n function _(e,t,d,n,s){n();const o=e(53),r=e(12),_=e(9),i=e(72);class c extends o.Model{constructor(e){super(e)}_hit_test(e,t,d){if(!t.model.visible)return null;const n=d.glyph.hit_test(e);return null==n?null:d.model.view.convert_selection_from_subset(n)}}d.GraphHitTestPolicy=c,c.__name__=\"GraphHitTestPolicy\";class a extends c{constructor(e){super(e)}hit_test(e,t){return this._hit_test(e,t,t.edge_view)}do_selection(e,t,d,n){if(null==e)return!1;const s=t.edge_renderer.data_source.selected;return s.update(e,d,n),t.edge_renderer.data_source._select.emit(),!s.is_empty()}do_inspection(e,t,d,n,s){if(null==e)return!1;const{edge_renderer:o}=d.model,r=o.get_selection_manager().get_or_create_inspector(d.edge_view.model);return r.update(e,n,s),d.edge_view.model.data_source.setv({inspected:r},{silent:!0}),d.edge_view.model.data_source.inspect.emit([d.edge_view.model,{geometry:t}]),!r.is_empty()}}d.EdgesOnly=a,a.__name__=\"EdgesOnly\";class l extends c{constructor(e){super(e)}hit_test(e,t){return this._hit_test(e,t,t.node_view)}do_selection(e,t,d,n){if(null==e)return!1;const s=t.node_renderer.data_source.selected;return s.update(e,d,n),t.node_renderer.data_source._select.emit(),!s.is_empty()}do_inspection(e,t,d,n,s){if(null==e)return!1;const{node_renderer:o}=d.model,r=o.get_selection_manager().get_or_create_inspector(d.node_view.model);return r.update(e,n,s),d.node_view.model.data_source.setv({inspected:r},{silent:!0}),d.node_view.model.data_source.inspect.emit([d.node_view.model,{geometry:t}]),!r.is_empty()}}d.NodesOnly=l,l.__name__=\"NodesOnly\";class u extends c{constructor(e){super(e)}hit_test(e,t){return this._hit_test(e,t,t.node_view)}get_linked_edges(e,t,d){let n=[];\"selection\"==d?n=e.selected.indices.map((t=>e.data.index[t])):\"inspection\"==d&&(n=e.inspected.indices.map((t=>e.data.index[t])));const s=[];for(let e=0;e(0,r.indexOf)(e.data.index,t)));return new i.Selection({indices:o})}do_selection(e,t,d,n){if(null==e)return!1;const s=t.edge_renderer.data_source.selected;s.update(e,d,n);const o=t.node_renderer.data_source.selected,r=this.get_linked_nodes(t.node_renderer.data_source,t.edge_renderer.data_source,\"selection\");return o.update(r,d,n),t.edge_renderer.data_source._select.emit(),!s.is_empty()}do_inspection(e,t,d,n,s){if(null==e)return!1;const o=d.edge_view.model.data_source.selection_manager.get_or_create_inspector(d.edge_view.model);o.update(e,n,s),d.edge_view.model.data_source.setv({inspected:o},{silent:!0});const r=d.node_view.model.data_source.selection_manager.get_or_create_inspector(d.node_view.model),_=this.get_linked_nodes(d.node_view.model.data_source,d.edge_view.model.data_source,\"inspection\");return r.update(_,n,s),d.node_view.model.data_source.setv({inspected:r},{silent:!0}),d.edge_view.model.data_source.inspect.emit([d.edge_view.model,{geometry:t}]),!o.is_empty()}}d.EdgesAndLinkedNodes=m,m.__name__=\"EdgesAndLinkedNodes\"},\n function _(e,o,t,r,n){var s;r();const a=e(53),d=e(260);class _ extends a.Model{constructor(e){super(e)}get node_coordinates(){return new u({layout:this})}get edge_coordinates(){return new i({layout:this})}}t.LayoutProvider=_,_.__name__=\"LayoutProvider\";class c extends d.CoordinateTransform{constructor(e){super(e)}}t.GraphCoordinates=c,s=c,c.__name__=\"GraphCoordinates\",s.define((({Ref:e})=>({layout:[e(_)]})));class u extends c{constructor(e){super(e)}_v_compute(e){const[o,t]=this.layout.get_node_coordinates(e);return{x:o,y:t}}}t.NodeCoordinates=u,u.__name__=\"NodeCoordinates\";class i extends c{constructor(e){super(e)}_v_compute(e){const[o,t]=this.layout.get_edge_coordinates(e);return{x:o,y:t}}}t.EdgeCoordinates=i,i.__name__=\"EdgeCoordinates\"},\n function _(t,a,l,e,n){var o;e();const r=t(303);class u extends r.LayoutProvider{constructor(t){super(t)}get_node_coordinates(t){var a;const l=null!==(a=t.data.index)&&void 0!==a?a:[],e=l.length,n=new Float64Array(e),o=new Float64Array(e);for(let t=0;t({graph_layout:[l(a(t,t)),{}]})))},\n function _(i,d,n,r,G){r(),G(\"Grid\",i(306).Grid)},\n function _(i,e,n,s,t){s();const r=i(1);var o;const d=i(127),_=i(129),a=i(130),l=(0,r.__importStar)(i(48)),h=i(8);class c extends _.GuideRendererView{_render(){const i=this.layer.ctx;i.save(),this._draw_regions(i),this._draw_minor_grids(i),this._draw_grids(i),i.restore()}connect_signals(){super.connect_signals(),this.connect(this.model.change,(()=>this.request_render()))}_draw_regions(i){if(!this.visuals.band_fill.doit&&!this.visuals.band_hatch.doit)return;const[e,n]=this.grid_coords(\"major\",!1);for(let s=0;sn[1]&&(t=n[1]);else{[s,t]=n;for(const i of this.plot_view.axis_views)i.dimension==this.model.dimension&&i.model.x_range_name==this.model.x_range_name&&i.model.y_range_name==this.model.y_range_name&&([s,t]=i.computed_bounds)}return[s,t]}grid_coords(i,e=!0){const n=this.model.dimension,s=(n+1)%2,[t,r]=this.ranges();let[o,d]=this.computed_bounds();[o,d]=[Math.min(o,d),Math.max(o,d)];const _=[[],[]],a=this.model.get_ticker();if(null==a)return _;const l=a.get_ticks(o,d,t,r.min)[i],h=t.min,c=t.max,u=r.min,m=r.max;e||(l[0]!=h&&l.splice(0,0,h),l[l.length-1]!=c&&l.push(c));for(let i=0;i({bounds:[r(t(i,i),e),\"auto\"],dimension:[n(0,1),0],axis:[o(s(d.Axis)),null],ticker:[o(s(a.Ticker)),null]}))),o.override({level:\"underlay\",band_fill_color:null,band_fill_alpha:0,grid_line_color:\"#e5e5e5\",minor_grid_line_color:null})},\n function _(o,a,x,B,e){B(),e(\"Box\",o(308).Box),e(\"Column\",o(310).Column),e(\"GridBox\",o(311).GridBox),e(\"HTMLBox\",o(312).HTMLBox),e(\"LayoutDOM\",o(309).LayoutDOM),e(\"Panel\",o(313).Panel),e(\"Row\",o(314).Row),e(\"Spacer\",o(315).Spacer),e(\"Tabs\",o(316).Tabs),e(\"WidgetBox\",o(319).WidgetBox)},\n function _(e,n,s,t,c){var i;t();const o=e(309);class r extends o.LayoutDOMView{connect_signals(){super.connect_signals(),this.connect(this.model.properties.children.change,(()=>this.rebuild()))}get child_models(){return this.model.children}}s.BoxView=r,r.__name__=\"BoxView\";class a extends o.LayoutDOM{constructor(e){super(e)}}s.Box=a,i=a,a.__name__=\"Box\",i.define((({Number:e,Array:n,Ref:s})=>({children:[n(s(o.LayoutDOM)),[]],spacing:[e,0]})))},\n function _(t,i,e,s,o){var l;s();const n=t(53),h=t(20),a=t(43),r=t(19),_=t(8),c=t(22),u=t(121),d=t(113),p=t(226),m=t(207),g=t(44),w=t(235);class f extends p.DOMView{constructor(){super(...arguments),this._offset_parent=null,this._viewport={}}get is_layout_root(){return this.is_root||!(this.parent instanceof f)}get base_font_size(){const t=getComputedStyle(this.el).fontSize,i=(0,u.parse_css_font_size)(t);if(null!=i){const{value:t,unit:e}=i;if(\"px\"==e)return t}return null}initialize(){super.initialize(),this.el.style.position=this.is_layout_root?\"relative\":\"absolute\",this._child_views=new Map}async lazy_initialize(){await super.lazy_initialize(),await this.build_child_views()}remove(){for(const t of this.child_views)t.remove();this._child_views.clear(),super.remove()}connect_signals(){super.connect_signals(),this.is_layout_root&&(this._on_resize=()=>this.resize_layout(),window.addEventListener(\"resize\",this._on_resize),this._parent_observer=setInterval((()=>{const t=this.el.offsetParent;this._offset_parent!=t&&(this._offset_parent=t,null!=t&&(this.compute_viewport(),this.invalidate_layout()))}),250));const t=this.model.properties;this.on_change([t.width,t.height,t.min_width,t.min_height,t.max_width,t.max_height,t.margin,t.width_policy,t.height_policy,t.sizing_mode,t.aspect_ratio,t.visible],(()=>this.invalidate_layout())),this.on_change([t.background,t.css_classes],(()=>this.invalidate_render()))}disconnect_signals(){null!=this._parent_observer&&clearTimeout(this._parent_observer),null!=this._on_resize&&window.removeEventListener(\"resize\",this._on_resize),super.disconnect_signals()}css_classes(){return super.css_classes().concat(this.model.css_classes)}get child_views(){return this.child_models.map((t=>this._child_views.get(t)))}async build_child_views(){await(0,d.build_views)(this._child_views,this.child_models,{parent:this})}render(){super.render(),(0,a.empty)(this.el);const{background:t}=this.model;this.el.style.backgroundColor=null!=t?(0,c.color2css)(t):\"\",(0,a.classes)(this.el).clear().add(...this.css_classes());for(const t of this.child_views)this.el.appendChild(t.el),t.render()}update_layout(){for(const t of this.child_views)t.update_layout();this._update_layout()}update_position(){this.el.style.display=this.model.visible?\"block\":\"none\";const t=this.is_layout_root?this.layout.sizing.margin:void 0;(0,a.position)(this.el,this.layout.bbox,t);for(const t of this.child_views)t.update_position()}after_layout(){for(const t of this.child_views)t.after_layout();this._has_finished=!0}compute_viewport(){this._viewport=this._viewport_size()}renderTo(t){t.appendChild(this.el),this._offset_parent=this.el.offsetParent,this.compute_viewport(),this.build(),this.notify_finished()}build(){if(!this.is_layout_root)throw new Error(`${this.toString()} is not a root layout`);return this.render(),this.update_layout(),this.compute_layout(),this}async rebuild(){await this.build_child_views(),this.invalidate_render()}compute_layout(){const t=Date.now();this.layout.compute(this._viewport),this.update_position(),this.after_layout(),r.logger.debug(`layout computed in ${Date.now()-t} ms`)}resize_layout(){this.root.compute_viewport(),this.root.compute_layout()}invalidate_layout(){this.root.update_layout(),this.root.compute_layout()}invalidate_render(){this.render(),this.invalidate_layout()}has_finished(){if(!super.has_finished())return!1;for(const t of this.child_views)if(!t.has_finished())return!1;return!0}_width_policy(){return null!=this.model.width?\"fixed\":\"fit\"}_height_policy(){return null!=this.model.height?\"fixed\":\"fit\"}box_sizing(){let{width_policy:t,height_policy:i,aspect_ratio:e}=this.model;\"auto\"==t&&(t=this._width_policy()),\"auto\"==i&&(i=this._height_policy());const{sizing_mode:s}=this.model;if(null!=s)if(\"fixed\"==s)t=i=\"fixed\";else if(\"stretch_both\"==s)t=i=\"max\";else if(\"stretch_width\"==s)t=\"max\";else if(\"stretch_height\"==s)i=\"max\";else switch(null==e&&(e=\"auto\"),s){case\"scale_width\":t=\"max\",i=\"min\";break;case\"scale_height\":t=\"min\",i=\"max\";break;case\"scale_both\":t=\"max\",i=\"max\"}const o={width_policy:t,height_policy:i},{min_width:l,min_height:n}=this.model;null!=l&&(o.min_width=l),null!=n&&(o.min_height=n);const{width:h,height:a}=this.model;null!=h&&(o.width=h),null!=a&&(o.height=a);const{max_width:r,max_height:c}=this.model;null!=r&&(o.max_width=r),null!=c&&(o.max_height=c),\"auto\"==e&&null!=h&&null!=a?o.aspect=h/a:(0,_.isNumber)(e)&&(o.aspect=e);const{margin:u}=this.model;if(null!=u)if((0,_.isNumber)(u))o.margin={top:u,right:u,bottom:u,left:u};else if(2==u.length){const[t,i]=u;o.margin={top:t,right:i,bottom:t,left:i}}else{const[t,i,e,s]=u;o.margin={top:t,right:i,bottom:e,left:s}}o.visible=this.model.visible;const{align:d}=this.model;return(0,_.isArray)(d)?[o.halign,o.valign]=d:o.halign=o.valign=d,o}_viewport_size(){return(0,a.undisplayed)(this.el,(()=>{let t=this.el;for(;t=t.parentElement;){if(t.classList.contains(g.root))continue;if(t==document.body){const{margin:{left:t,right:i,top:e,bottom:s}}=(0,a.extents)(document.body);return{width:Math.ceil(document.documentElement.clientWidth-t-i),height:Math.ceil(document.documentElement.clientHeight-e-s)}}const{padding:{left:i,right:e,top:s,bottom:o}}=(0,a.extents)(t),{width:l,height:n}=t.getBoundingClientRect(),h=Math.ceil(l-i-e),r=Math.ceil(n-s-o);if(h>0||r>0)return{width:h>0?h:void 0,height:r>0?r:void 0}}return{}}))}export(t,i=!0){const e=\"png\"==t?\"canvas\":\"svg\",s=new w.CanvasLayer(e,i),{width:o,height:l}=this.layout.bbox;s.resize(o,l);for(const e of this.child_views){const o=e.export(t,i),{x:l,y:n}=e.layout.bbox;s.ctx.drawImage(o.canvas,l,n)}return s}serializable_state(){return Object.assign(Object.assign({},super.serializable_state()),{bbox:this.layout.bbox.box,children:this.child_views.map((t=>t.serializable_state()))})}}e.LayoutDOMView=f,f.__name__=\"LayoutDOMView\";class y extends n.Model{constructor(t){super(t)}}e.LayoutDOM=y,l=y,y.__name__=\"LayoutDOM\",l.define((t=>{const{Boolean:i,Number:e,String:s,Auto:o,Color:l,Array:n,Tuple:a,Or:r,Null:_,Nullable:c}=t,u=a(e,e),d=a(e,e,e,e);return{width:[c(e),null],height:[c(e),null],min_width:[c(e),null],min_height:[c(e),null],max_width:[c(e),null],max_height:[c(e),null],margin:[c(r(e,u,d)),[0,0,0,0]],width_policy:[r(m.SizingPolicy,o),\"auto\"],height_policy:[r(m.SizingPolicy,o),\"auto\"],aspect_ratio:[r(e,o,_),null],sizing_mode:[c(h.SizingMode),null],visible:[i,!0],disabled:[i,!1],align:[r(h.Align,a(h.Align,h.Align)),\"start\"],background:[c(l),null],css_classes:[n(s),[]]}}))},\n function _(o,s,t,i,e){var n;i();const a=o(308),l=o(209);class u extends a.BoxView{_update_layout(){const o=this.child_views.map((o=>o.layout));this.layout=new l.Column(o),this.layout.rows=this.model.rows,this.layout.spacing=[this.model.spacing,0],this.layout.set_sizing(this.box_sizing())}}t.ColumnView=u,u.__name__=\"ColumnView\";class _ extends a.Box{constructor(o){super(o)}}t.Column=_,n=_,_.__name__=\"Column\",n.prototype.default_view=u,n.define((({Any:o})=>({rows:[o,\"auto\"]})))},\n function _(s,o,t,i,e){var n;i();const l=s(309),a=s(209);class r extends l.LayoutDOMView{connect_signals(){super.connect_signals();const{children:s,rows:o,cols:t,spacing:i}=this.model.properties;this.on_change([s,o,t,i],(()=>this.rebuild()))}get child_models(){return this.model.children.map((([s])=>s))}_update_layout(){this.layout=new a.Grid,this.layout.rows=this.model.rows,this.layout.cols=this.model.cols,this.layout.spacing=this.model.spacing;for(const[s,o,t,i,e]of this.model.children){const n=this._child_views.get(s);this.layout.items.push({layout:n.layout,row:o,col:t,row_span:i,col_span:e})}this.layout.set_sizing(this.box_sizing())}}t.GridBoxView=r,r.__name__=\"GridBoxView\";class c extends l.LayoutDOM{constructor(s){super(s)}}t.GridBox=c,n=c,c.__name__=\"GridBox\",n.prototype.default_view=r,n.define((({Any:s,Int:o,Number:t,Tuple:i,Array:e,Ref:n,Or:a,Opt:r})=>({children:[e(i(n(l.LayoutDOM),o,o,r(o),r(o))),[]],rows:[s,\"auto\"],cols:[s,\"auto\"],spacing:[a(t,i(t,t)),0]})))},\n function _(t,e,o,s,n){s();const _=t(309),i=t(207);class a extends _.LayoutDOMView{get child_models(){return[]}_update_layout(){this.layout=new i.ContentBox(this.el),this.layout.set_sizing(this.box_sizing())}}o.HTMLBoxView=a,a.__name__=\"HTMLBoxView\";class u extends _.LayoutDOM{constructor(t){super(t)}}o.HTMLBox=u,u.__name__=\"HTMLBox\"},\n function _(e,n,l,a,o){var t;a();const s=e(53),c=e(309);class d extends s.Model{constructor(e){super(e)}}l.Panel=d,t=d,d.__name__=\"Panel\",t.define((({Boolean:e,String:n,Ref:l})=>({title:[n,\"\"],child:[l(c.LayoutDOM)],closable:[e,!1],disabled:[e,!1]})))},\n function _(o,s,t,i,e){var a;i();const n=o(308),l=o(209);class _ extends n.BoxView{_update_layout(){const o=this.child_views.map((o=>o.layout));this.layout=new l.Row(o),this.layout.cols=this.model.cols,this.layout.spacing=[0,this.model.spacing],this.layout.set_sizing(this.box_sizing())}}t.RowView=_,_.__name__=\"RowView\";class c extends n.Box{constructor(o){super(o)}}t.Row=c,a=c,c.__name__=\"Row\",a.prototype.default_view=_,a.define((({Any:o})=>({cols:[o,\"auto\"]})))},\n function _(e,t,a,s,_){var o;s();const i=e(309),n=e(207);class u extends i.LayoutDOMView{get child_models(){return[]}_update_layout(){this.layout=new n.LayoutItem,this.layout.set_sizing(this.box_sizing())}}a.SpacerView=u,u.__name__=\"SpacerView\";class c extends i.LayoutDOM{constructor(e){super(e)}}a.Spacer=c,o=c,c.__name__=\"Spacer\",o.prototype.default_view=u},\n function _(e,t,s,i,l){i();const h=e(1);var a;const o=e(207),d=e(43),r=e(9),c=e(10),n=e(20),_=e(309),p=e(313),b=(0,h.__importStar)(e(317)),m=b,u=(0,h.__importStar)(e(318)),g=u,v=(0,h.__importStar)(e(229)),w=v;class f extends _.LayoutDOMView{constructor(){super(...arguments),this._scroll_index=0}connect_signals(){super.connect_signals(),this.connect(this.model.properties.tabs.change,(()=>this.rebuild())),this.connect(this.model.properties.active.change,(()=>this.on_active_change()))}styles(){return[...super.styles(),u.default,v.default,b.default]}get child_models(){return this.model.tabs.map((e=>e.child))}_update_layout(){const e=this.model.tabs_location,t=\"above\"==e||\"below\"==e,{scroll_el:s,headers_el:i}=this;this.header=new class extends o.ContentBox{_measure(e){const l=(0,d.size)(s),h=(0,d.children)(i).slice(0,3).map((e=>(0,d.size)(e))),{width:a,height:o}=super._measure(e);if(t){const t=l.width+(0,r.sum)(h.map((e=>e.width)));return{width:e.width!=1/0?e.width:t,height:o}}{const t=l.height+(0,r.sum)(h.map((e=>e.height)));return{width:a,height:e.height!=1/0?e.height:t}}}}(this.header_el),t?this.header.set_sizing({width_policy:\"fit\",height_policy:\"fixed\"}):this.header.set_sizing({width_policy:\"fixed\",height_policy:\"fit\"});let l=1,h=1;switch(e){case\"above\":l-=1;break;case\"below\":l+=1;break;case\"left\":h-=1;break;case\"right\":h+=1}const a={layout:this.header,row:l,col:h},c=this.child_views.map((e=>({layout:e.layout,row:1,col:1})));this.layout=new o.Grid([a,...c]),this.layout.set_sizing(this.box_sizing())}update_position(){super.update_position(),this.header_el.style.position=\"absolute\",(0,d.position)(this.header_el,this.header.bbox);const e=this.model.tabs_location,t=\"above\"==e||\"below\"==e,s=(0,d.size)(this.scroll_el),i=(0,d.scroll_size)(this.headers_el);if(t){const{width:e}=this.header.bbox;i.width>e?(this.wrapper_el.style.maxWidth=e-s.width+\"px\",(0,d.display)(this.scroll_el),this.do_scroll(this.model.active)):(this.wrapper_el.style.maxWidth=\"\",(0,d.undisplay)(this.scroll_el))}else{const{height:e}=this.header.bbox;i.height>e?(this.wrapper_el.style.maxHeight=e-s.height+\"px\",(0,d.display)(this.scroll_el),this.do_scroll(this.model.active)):(this.wrapper_el.style.maxHeight=\"\",(0,d.undisplay)(this.scroll_el))}const{child_views:l}=this;for(const e of l)(0,d.hide)(e.el);const h=l[this.model.active];null!=h&&(0,d.show)(h.el)}render(){super.render();const{active:e}=this.model,t=this.model.tabs.map(((t,s)=>{const i=(0,d.div)({class:[m.tab,s==e?m.active:null]},t.title);if(i.addEventListener(\"click\",(e=>{this.model.disabled||e.target==e.currentTarget&&this.change_active(s)})),t.closable){const e=(0,d.div)({class:m.close});e.addEventListener(\"click\",(e=>{if(e.target==e.currentTarget){this.model.tabs=(0,r.remove_at)(this.model.tabs,s);const e=this.model.tabs.length;this.model.active>e-1&&(this.model.active=e-1)}})),i.appendChild(e)}return(this.model.disabled||t.disabled)&&i.classList.add(m.disabled),i}));this.headers_el=(0,d.div)({class:[m.headers]},t),this.wrapper_el=(0,d.div)({class:m.headers_wrapper},this.headers_el),this.left_el=(0,d.div)({class:[g.btn,g.btn_default],disabled:\"\"},(0,d.div)({class:[w.caret,m.left]})),this.right_el=(0,d.div)({class:[g.btn,g.btn_default]},(0,d.div)({class:[w.caret,m.right]})),this.left_el.addEventListener(\"click\",(()=>this.do_scroll(\"left\"))),this.right_el.addEventListener(\"click\",(()=>this.do_scroll(\"right\"))),this.scroll_el=(0,d.div)({class:g.btn_group},this.left_el,this.right_el);const s=this.model.tabs_location;this.header_el=(0,d.div)({class:[m.tabs_header,m[s]]},this.scroll_el,this.wrapper_el),this.el.appendChild(this.header_el)}do_scroll(e){const t=this.model.tabs.length;\"left\"==e?this._scroll_index-=1:\"right\"==e?this._scroll_index+=1:this._scroll_index=e,this._scroll_index=(0,c.clamp)(this._scroll_index,0,t-1),0==this._scroll_index?this.left_el.setAttribute(\"disabled\",\"\"):this.left_el.removeAttribute(\"disabled\"),this._scroll_index==t-1?this.right_el.setAttribute(\"disabled\",\"\"):this.right_el.removeAttribute(\"disabled\");const s=(0,d.children)(this.headers_el).slice(0,this._scroll_index).map((e=>e.getBoundingClientRect())),i=this.model.tabs_location;if(\"above\"==i||\"below\"==i){const e=-(0,r.sum)(s.map((e=>e.width)));this.headers_el.style.left=`${e}px`}else{const e=-(0,r.sum)(s.map((e=>e.height)));this.headers_el.style.top=`${e}px`}}change_active(e){e!=this.model.active&&(this.model.active=e)}on_active_change(){const e=this.model.active,t=(0,d.children)(this.headers_el);for(const e of t)e.classList.remove(m.active);t[e].classList.add(m.active);const{child_views:s}=this;for(const e of s)(0,d.hide)(e.el);(0,d.show)(s[e].el)}}s.TabsView=f,f.__name__=\"TabsView\";class x extends _.LayoutDOM{constructor(e){super(e)}}s.Tabs=x,a=x,x.__name__=\"Tabs\",a.prototype.default_view=f,a.define((({Int:e,Array:t,Ref:s})=>({tabs:[t(s(p.Panel)),[]],tabs_location:[n.Location,\"above\"],active:[e,0]})))},\n function _(e,r,b,o,t){o(),b.root=\"bk-root\",b.tabs_header=\"bk-tabs-header\",b.btn_group=\"bk-btn-group\",b.btn=\"bk-btn\",b.headers_wrapper=\"bk-headers-wrapper\",b.above=\"bk-above\",b.right=\"bk-right\",b.below=\"bk-below\",b.left=\"bk-left\",b.headers=\"bk-headers\",b.tab=\"bk-tab\",b.active=\"bk-active\",b.close=\"bk-close\",b.disabled=\"bk-disabled\",b.default='.bk-root .bk-tabs-header{display:flex;flex-wrap:nowrap;align-items:center;overflow:hidden;user-select:none;-ms-user-select:none;-moz-user-select:none;-webkit-user-select:none;}.bk-root .bk-tabs-header .bk-btn-group{height:auto;margin-right:5px;}.bk-root .bk-tabs-header .bk-btn-group > .bk-btn{flex-grow:0;height:auto;padding:4px 4px;}.bk-root .bk-tabs-header .bk-headers-wrapper{flex-grow:1;overflow:hidden;color:#666666;}.bk-root .bk-tabs-header.bk-above .bk-headers-wrapper{border-bottom:1px solid #e6e6e6;}.bk-root .bk-tabs-header.bk-right .bk-headers-wrapper{border-left:1px solid #e6e6e6;}.bk-root .bk-tabs-header.bk-below .bk-headers-wrapper{border-top:1px solid #e6e6e6;}.bk-root .bk-tabs-header.bk-left .bk-headers-wrapper{border-right:1px solid #e6e6e6;}.bk-root .bk-tabs-header.bk-above,.bk-root .bk-tabs-header.bk-below{flex-direction:row;}.bk-root .bk-tabs-header.bk-above .bk-headers,.bk-root .bk-tabs-header.bk-below .bk-headers{flex-direction:row;}.bk-root .bk-tabs-header.bk-left,.bk-root .bk-tabs-header.bk-right{flex-direction:column;}.bk-root .bk-tabs-header.bk-left .bk-headers,.bk-root .bk-tabs-header.bk-right .bk-headers{flex-direction:column;}.bk-root .bk-tabs-header .bk-headers{position:relative;display:flex;flex-wrap:nowrap;align-items:center;}.bk-root .bk-tabs-header .bk-tab{padding:4px 8px;border:solid transparent;white-space:nowrap;cursor:pointer;}.bk-root .bk-tabs-header .bk-tab:hover{background-color:#f2f2f2;}.bk-root .bk-tabs-header .bk-tab.bk-active{color:#4d4d4d;background-color:white;border-color:#e6e6e6;}.bk-root .bk-tabs-header .bk-tab .bk-close{margin-left:10px;}.bk-root .bk-tabs-header .bk-tab.bk-disabled{cursor:not-allowed;pointer-events:none;opacity:0.65;}.bk-root .bk-tabs-header.bk-above .bk-tab{border-width:3px 1px 0px 1px;border-radius:4px 4px 0 0;}.bk-root .bk-tabs-header.bk-right .bk-tab{border-width:1px 3px 1px 0px;border-radius:0 4px 4px 0;}.bk-root .bk-tabs-header.bk-below .bk-tab{border-width:0px 1px 3px 1px;border-radius:0 0 4px 4px;}.bk-root .bk-tabs-header.bk-left .bk-tab{border-width:1px 0px 1px 3px;border-radius:4px 0 0 4px;}.bk-root .bk-close{display:inline-block;width:10px;height:10px;vertical-align:middle;background-image:url(\\'data:image/svg+xml;utf8, \\');}.bk-root .bk-close:hover{background-image:url(\\'data:image/svg+xml;utf8, \\');}'},\n function _(o,b,r,t,e){t(),r.root=\"bk-root\",r.btn=\"bk-btn\",r.active=\"bk-active\",r.btn_default=\"bk-btn-default\",r.btn_primary=\"bk-btn-primary\",r.btn_success=\"bk-btn-success\",r.btn_warning=\"bk-btn-warning\",r.btn_danger=\"bk-btn-danger\",r.btn_light=\"bk-btn-light\",r.btn_group=\"bk-btn-group\",r.vertical=\"bk-vertical\",r.horizontal=\"bk-horizontal\",r.dropdown_toggle=\"bk-dropdown-toggle\",r.default=\".bk-root .bk-btn{height:100%;display:inline-block;text-align:center;vertical-align:middle;white-space:nowrap;cursor:pointer;padding:6px 12px;font-size:12px;border:1px solid transparent;border-radius:4px;outline:0;user-select:none;-ms-user-select:none;-moz-user-select:none;-webkit-user-select:none;}.bk-root .bk-btn:hover,.bk-root .bk-btn:focus{text-decoration:none;}.bk-root .bk-btn:active,.bk-root .bk-btn.bk-active{background-image:none;box-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);}.bk-root .bk-btn[disabled]{cursor:not-allowed;pointer-events:none;opacity:0.65;box-shadow:none;}.bk-root .bk-btn-default{color:#333;background-color:#fff;border-color:#ccc;}.bk-root .bk-btn-default:hover{background-color:#f5f5f5;border-color:#b8b8b8;}.bk-root .bk-btn-default.bk-active{background-color:#ebebeb;border-color:#adadad;}.bk-root .bk-btn-default[disabled],.bk-root .bk-btn-default[disabled]:hover,.bk-root .bk-btn-default[disabled]:focus,.bk-root .bk-btn-default[disabled]:active,.bk-root .bk-btn-default[disabled].bk-active{background-color:#e6e6e6;border-color:#ccc;}.bk-root .bk-btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd;}.bk-root .bk-btn-primary:hover{background-color:#3681c1;border-color:#2c699e;}.bk-root .bk-btn-primary.bk-active{background-color:#3276b1;border-color:#285e8e;}.bk-root .bk-btn-primary[disabled],.bk-root .bk-btn-primary[disabled]:hover,.bk-root .bk-btn-primary[disabled]:focus,.bk-root .bk-btn-primary[disabled]:active,.bk-root .bk-btn-primary[disabled].bk-active{background-color:#506f89;border-color:#357ebd;}.bk-root .bk-btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c;}.bk-root .bk-btn-success:hover{background-color:#4eb24e;border-color:#409240;}.bk-root .bk-btn-success.bk-active{background-color:#47a447;border-color:#398439;}.bk-root .bk-btn-success[disabled],.bk-root .bk-btn-success[disabled]:hover,.bk-root .bk-btn-success[disabled]:focus,.bk-root .bk-btn-success[disabled]:active,.bk-root .bk-btn-success[disabled].bk-active{background-color:#667b66;border-color:#4cae4c;}.bk-root .bk-btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236;}.bk-root .bk-btn-warning:hover{background-color:#eea43b;border-color:#e89014;}.bk-root .bk-btn-warning.bk-active{background-color:#ed9c28;border-color:#d58512;}.bk-root .bk-btn-warning[disabled],.bk-root .bk-btn-warning[disabled]:hover,.bk-root .bk-btn-warning[disabled]:focus,.bk-root .bk-btn-warning[disabled]:active,.bk-root .bk-btn-warning[disabled].bk-active{background-color:#c89143;border-color:#eea236;}.bk-root .bk-btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a;}.bk-root .bk-btn-danger:hover{background-color:#d5433e;border-color:#bd2d29;}.bk-root .bk-btn-danger.bk-active{background-color:#d2322d;border-color:#ac2925;}.bk-root .bk-btn-danger[disabled],.bk-root .bk-btn-danger[disabled]:hover,.bk-root .bk-btn-danger[disabled]:focus,.bk-root .bk-btn-danger[disabled]:active,.bk-root .bk-btn-danger[disabled].bk-active{background-color:#a55350;border-color:#d43f3a;}.bk-root .bk-btn-light{color:#333;background-color:#fff;border-color:#ccc;border-color:transparent;}.bk-root .bk-btn-light:hover{background-color:#f5f5f5;border-color:#b8b8b8;}.bk-root .bk-btn-light.bk-active{background-color:#ebebeb;border-color:#adadad;}.bk-root .bk-btn-light[disabled],.bk-root .bk-btn-light[disabled]:hover,.bk-root .bk-btn-light[disabled]:focus,.bk-root .bk-btn-light[disabled]:active,.bk-root .bk-btn-light[disabled].bk-active{background-color:#e6e6e6;border-color:#ccc;}.bk-root .bk-btn-group{height:100%;display:flex;flex-wrap:nowrap;align-items:center;}.bk-root .bk-btn-group:not(.bk-vertical),.bk-root .bk-btn-group.bk-horizontal{flex-direction:row;}.bk-root .bk-btn-group.bk-vertical{flex-direction:column;}.bk-root .bk-btn-group > .bk-btn{flex-grow:1;}.bk-root .bk-btn-group:not(.bk-vertical) > .bk-btn + .bk-btn{margin-left:-1px;}.bk-root .bk-btn-group.bk-vertical > .bk-btn + .bk-btn{margin-top:-1px;}.bk-root .bk-btn-group:not(.bk-vertical) > .bk-btn:first-child:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0;}.bk-root .bk-btn-group.bk-vertical > .bk-btn:first-child:not(:last-child){border-bottom-left-radius:0;border-bottom-right-radius:0;}.bk-root .bk-btn-group:not(.bk-vertical) > .bk-btn:not(:first-child):last-child{border-bottom-left-radius:0;border-top-left-radius:0;}.bk-root .bk-btn-group.bk-vertical > .bk-btn:not(:first-child):last-child{border-top-left-radius:0;border-top-right-radius:0;}.bk-root .bk-btn-group > .bk-btn:not(:first-child):not(:last-child){border-radius:0;}.bk-root .bk-btn-group.bk-vertical > .bk-btn{width:100%;}.bk-root .bk-btn-group .bk-dropdown-toggle{flex:0 0 0;padding:6px 6px;}\"},\n function _(e,t,o,n,_){var i;n();const s=e(310);class d extends s.ColumnView{}o.WidgetBoxView=d,d.__name__=\"WidgetBoxView\";class a extends s.Column{constructor(e){super(e)}}o.WidgetBox=a,i=a,a.__name__=\"WidgetBox\",i.prototype.default_view=d},\n function _(t,a,i,e,M){e();var T=t(135);M(\"MathText\",T.MathText),M(\"Ascii\",T.Ascii),M(\"MathML\",T.MathML),M(\"TeX\",T.TeX),M(\"PlainText\",t(139).PlainText)},\n function _(r,o,t,e,n){e(),n(\"CustomJSTransform\",r(322).CustomJSTransform),n(\"Dodge\",r(323).Dodge),n(\"Interpolator\",r(325).Interpolator),n(\"Jitter\",r(326).Jitter),n(\"LinearInterpolator\",r(327).LinearInterpolator),n(\"StepInterpolator\",r(328).StepInterpolator),n(\"Transform\",r(56).Transform)},\n function _(r,t,s,n,e){var a;n();const u=r(56),o=r(13),m=r(34);class _ extends u.Transform{constructor(r){super(r)}get names(){return(0,o.keys)(this.args)}get values(){return(0,o.values)(this.args)}_make_transform(r,t){return new Function(...this.names,r,(0,m.use_strict)(t))}get scalar_transform(){return this._make_transform(\"x\",this.func)}get vector_transform(){return this._make_transform(\"xs\",this.v_func)}compute(r){return this.scalar_transform(...this.values,r)}v_compute(r){return this.vector_transform(...this.values,r)}}s.CustomJSTransform=_,a=_,_.__name__=\"CustomJSTransform\",a.define((({Unknown:r,String:t,Dict:s})=>({args:[s(r),{}],func:[t,\"\"],v_func:[t,\"\"]})))},\n function _(e,n,r,o,s){var t;o();const u=e(324);class a extends u.RangeTransform{constructor(e){super(e)}_compute(e){return e+this.value}}r.Dodge=a,t=a,a.__name__=\"Dodge\",t.define((({Number:e})=>({value:[e,0]})))},\n function _(e,n,t,r,a){var s;r();const c=e(56),o=e(57),i=e(67),u=e(24),h=e(8),l=e(11);class g extends c.Transform{constructor(e){super(e)}v_compute(e){let n;this.range instanceof i.FactorRange?n=this.range.v_synthetic(e):(0,h.isArrayableOf)(e,h.isNumber)?n=e:(0,l.unreachable)();const t=new((0,u.infer_type)(n))(n.length);for(let e=0;e({range:[n(e(o.Range)),null]})))},\n function _(t,e,r,n,s){var o;n();const i=t(56),a=t(70),h=t(24),l=t(9),d=t(8);class c extends i.Transform{constructor(t){super(t),this._sorted_dirty=!0}connect_signals(){super.connect_signals(),this.connect(this.change,(()=>this._sorted_dirty=!0))}v_compute(t){const e=new((0,h.infer_type)(t))(t.length);for(let r=0;ro*(e[t]-e[r]))),this._x_sorted=new((0,h.infer_type)(e))(n),this._y_sorted=new((0,h.infer_type)(r))(n);for(let t=0;t({x:[o(r,s(e))],y:[o(r,s(e))],data:[i(n(a.ColumnarDataSource)),null],clip:[t,!0]})))},\n function _(t,s,e,i,r){i();const n=t(1);var o;const a=t(324),u=t(67),h=t(20),c=t(8),m=t(12),f=(0,n.__importStar)(t(10)),_=t(11);class p extends a.RangeTransform{constructor(t){super(t)}v_compute(t){var s;let e;this.range instanceof u.FactorRange?e=this.range.v_synthetic(t):(0,c.isArrayableOf)(t,c.isNumber)?e=t:(0,_.unreachable)();const i=e.length;(null===(s=this.previous_offsets)||void 0===s?void 0:s.length)!=i&&(this.previous_offsets=new Array(i),this.previous_offsets=(0,m.map)(this.previous_offsets,(()=>this._compute())));const r=this.previous_offsets;return(0,m.map)(e,((t,s)=>r[s]+t))}_compute(){switch(this.distribution){case\"uniform\":return this.mean+(f.random()-.5)*this.width;case\"normal\":return f.rnorm(this.mean,this.width)}}}e.Jitter=p,o=p,p.__name__=\"Jitter\",o.define((({Number:t})=>({mean:[t,0],width:[t,1],distribution:[h.Distribution,\"uniform\"]})))},\n function _(t,s,_,r,e){r();const i=t(9),o=t(325);class n extends o.Interpolator{constructor(t){super(t)}compute(t){if(this.sort(!1),this.clip){if(tthis._x_sorted[this._x_sorted.length-1])return NaN}else{if(tthis._x_sorted[this._x_sorted.length-1])return this._y_sorted[this._y_sorted.length-1]}if(t==this._x_sorted[0])return this._y_sorted[0];const s=(0,i.find_last_index)(this._x_sorted,(s=>sthis._x_sorted[this._x_sorted.length-1])return NaN}else{if(tthis._x_sorted[this._x_sorted.length-1])return this._y_sorted[this._y_sorted.length-1]}let e;switch(this.mode){case\"after\":e=(0,d.find_last_index)(this._x_sorted,(e=>t>=e));break;case\"before\":e=(0,d.find_index)(this._x_sorted,(e=>t<=e));break;case\"center\":{const s=(0,d.map)(this._x_sorted,(e=>Math.abs(e-t))),r=(0,d.min)(s);e=(0,d.find_index)(s,(t=>r===t));break}default:throw new Error(`unknown mode: ${this.mode}`)}return-1!=e?this._y_sorted[e]:NaN}}s.StepInterpolator=h,_=h,h.__name__=\"StepInterpolator\",_.define((()=>({mode:[n.StepMode,\"after\"]})))},\n function _(p,o,t,a,n){a(),n(\"MapOptions\",p(330).MapOptions),n(\"GMapOptions\",p(330).GMapOptions),n(\"GMapPlot\",p(330).GMapPlot),n(\"Plot\",p(331).Plot)},\n function _(e,t,n,o,a){var s,p,_;o();const i=e(331),r=e(53),l=e(58),c=e(336);a(\"GMapPlotView\",c.GMapPlotView);class d extends r.Model{constructor(e){super(e)}}n.MapOptions=d,s=d,d.__name__=\"MapOptions\",s.define((({Int:e,Number:t})=>({lat:[t],lng:[t],zoom:[e,12]})));class u extends d{constructor(e){super(e)}}n.GMapOptions=u,p=u,u.__name__=\"GMapOptions\",p.define((({Boolean:e,Int:t,String:n})=>({map_type:[n,\"roadmap\"],scale_control:[e,!1],styles:[n],tilt:[t,45]})));class M extends i.Plot{constructor(e){super(e),this.use_map=!0}}n.GMapPlot=M,_=M,M.__name__=\"GMapPlot\",_.prototype.default_view=c.GMapPlotView,_.define((({String:e,Ref:t})=>({map_options:[t(u)],api_key:[e],api_version:[e,\"weekly\"]}))),_.override({x_range:()=>new l.Range1d,y_range:()=>new l.Range1d})},\n function _(e,t,r,n,i){n();const o=e(1);var a;const s=(0,o.__importStar)(e(48)),l=(0,o.__importStar)(e(18)),_=e(15),c=e(20),h=e(9),d=e(13),u=e(8),g=e(309),p=e(128),f=e(306),b=e(40),w=e(118),y=e(59),m=e(221),x=e(57),v=e(55),A=e(75),S=e(41),R=e(176),D=e(175),L=e(63),P=e(332);i(\"PlotView\",P.PlotView);class k extends g.LayoutDOM{constructor(e){super(e),this.use_map=!1}_doc_attached(){super._doc_attached(),this._push_changes([[this.properties.inner_height,null,this.inner_height],[this.properties.inner_width,null,this.inner_width]])}initialize(){super.initialize(),this.reset=new _.Signal0(this,\"reset\");for(const e of(0,d.values)(this.extra_x_ranges).concat(this.x_range)){let t=e.plots;(0,u.isArray)(t)&&(t=t.concat(this),e.setv({plots:t},{silent:!0}))}for(const e of(0,d.values)(this.extra_y_ranges).concat(this.y_range)){let t=e.plots;(0,u.isArray)(t)&&(t=t.concat(this),e.setv({plots:t},{silent:!0}))}}add_layout(e,t=\"center\"){const r=this.properties[t].get_value();this.setv({[t]:[...r,e]})}remove_layout(e){const t=t=>{(0,h.remove_by)(t,(t=>t==e))};t(this.left),t(this.right),t(this.above),t(this.below),t(this.center)}get data_renderers(){return this.renderers.filter((e=>e instanceof R.DataRenderer))}add_renderers(...e){this.renderers=this.renderers.concat(e)}add_glyph(e,t=new A.ColumnDataSource,r={}){const n=new D.GlyphRenderer(Object.assign(Object.assign({},r),{data_source:t,glyph:e}));return this.add_renderers(n),n}add_tools(...e){this.toolbar.tools=this.toolbar.tools.concat(e)}get panels(){return[...this.side_panels,...this.center]}get side_panels(){const{above:e,below:t,left:r,right:n}=this;return(0,h.concat)([e,t,r,n])}}r.Plot=k,a=k,k.__name__=\"Plot\",a.prototype.default_view=P.PlotView,a.mixins([[\"outline_\",s.Line],[\"background_\",s.Fill],[\"border_\",s.Fill]]),a.define((({Boolean:e,Number:t,String:r,Array:n,Dict:i,Or:o,Ref:a,Null:s,Nullable:_})=>({toolbar:[a(m.Toolbar),()=>new m.Toolbar],toolbar_location:[_(c.Location),\"right\"],toolbar_sticky:[e,!0],plot_width:[l.Alias(\"width\")],plot_height:[l.Alias(\"height\")],frame_width:[_(t),null],frame_height:[_(t),null],title:[o(a(w.Title),r,s),\"\",{convert:e=>(0,u.isString)(e)?new w.Title({text:e}):e}],title_location:[_(c.Location),\"above\"],above:[n(o(a(b.Annotation),a(p.Axis))),[]],below:[n(o(a(b.Annotation),a(p.Axis))),[]],left:[n(o(a(b.Annotation),a(p.Axis))),[]],right:[n(o(a(b.Annotation),a(p.Axis))),[]],center:[n(o(a(b.Annotation),a(f.Grid))),[]],renderers:[n(a(S.Renderer)),[]],x_range:[a(x.Range),()=>new L.DataRange1d],y_range:[a(x.Range),()=>new L.DataRange1d],x_scale:[a(v.Scale),()=>new y.LinearScale],y_scale:[a(v.Scale),()=>new y.LinearScale],extra_x_ranges:[i(a(x.Range)),{}],extra_y_ranges:[i(a(x.Range)),{}],extra_x_scales:[i(a(v.Scale)),{}],extra_y_scales:[i(a(v.Scale)),{}],lod_factor:[t,10],lod_interval:[t,300],lod_threshold:[_(t),2e3],lod_timeout:[t,500],hidpi:[e,!0],output_backend:[c.OutputBackend,\"canvas\"],min_border:[_(t),5],min_border_top:[_(t),null],min_border_left:[_(t),null],min_border_bottom:[_(t),null],min_border_right:[_(t),null],inner_width:[t,0],inner_height:[t,0],outer_width:[t,0],outer_height:[t,0],match_aspect:[e,!1],aspect_scale:[t,1],reset_policy:[c.ResetPolicy,\"standard\"]}))),a.override({width:600,height:600,outline_line_color:\"#e5e5e5\",border_fill_color:\"#ffffff\",background_fill_color:\"#ffffff\"})},\n function _(e,t,i,s,a){s();const n=e(1),o=e(126),l=e(249),r=e(309),_=e(40),h=e(118),d=e(128),u=e(220),c=e(251),p=e(113),v=e(45),g=e(19),b=e(251),m=e(333),y=e(8),w=e(9),f=e(235),x=e(208),z=e(211),k=e(209),q=e(123),M=e(65),R=e(334),V=e(335),S=e(28);class O extends r.LayoutDOMView{constructor(){super(...arguments),this._outer_bbox=new M.BBox,this._inner_bbox=new M.BBox,this._needs_paint=!0,this._needs_layout=!1,this._invalidated_painters=new Set,this._invalidate_all=!0,this._needs_notify=!1}get canvas(){return this.canvas_view}get state(){return this._state_manager}set invalidate_dataranges(e){this._range_manager.invalidate_dataranges=e}renderer_view(e){const t=this.renderer_views.get(e);if(null==t)for(const[,t]of this.renderer_views){const i=t.renderer_view(e);if(null!=i)return i}return t}get is_paused(){return null!=this._is_paused&&0!==this._is_paused}get child_models(){return[]}pause(){null==this._is_paused?this._is_paused=1:this._is_paused+=1}unpause(e=!1){if(null==this._is_paused)throw new Error(\"wasn't paused\");this._is_paused-=1,0!=this._is_paused||e||this.request_paint(\"everything\")}notify_finished_after_paint(){this._needs_notify=!0}request_render(){this.request_paint(\"everything\")}request_paint(e){this.invalidate_painters(e),this.schedule_paint()}invalidate_painters(e){if(\"everything\"==e)this._invalidate_all=!0;else if((0,y.isArray)(e))for(const t of e)this._invalidated_painters.add(t);else this._invalidated_painters.add(e)}schedule_paint(){if(!this.is_paused){const e=this.throttled_paint();this._ready=this._ready.then((()=>e))}}request_layout(){this._needs_layout=!0,this.request_paint(\"everything\")}reset(){\"standard\"==this.model.reset_policy&&(this.state.clear(),this.reset_range(),this.reset_selection()),this.model.trigger_event(new c.Reset)}remove(){(0,p.remove_views)(this.renderer_views),(0,p.remove_views)(this.tool_views),this.canvas_view.remove(),super.remove()}render(){super.render(),this.el.appendChild(this.canvas_view.el),this.canvas_view.render()}initialize(){this.pause(),super.initialize(),this.lod_started=!1,this.visuals=new v.Visuals(this),this._initial_state={selection:new Map,dimensions:{width:0,height:0}},this.visibility_callbacks=[],this.renderer_views=new Map,this.tool_views=new Map,this.frame=new o.CartesianFrame(this.model.x_scale,this.model.y_scale,this.model.x_range,this.model.y_range,this.model.extra_x_ranges,this.model.extra_y_ranges,this.model.extra_x_scales,this.model.extra_y_scales),this._range_manager=new R.RangeManager(this),this._state_manager=new V.StateManager(this,this._initial_state),this.throttled_paint=(0,m.throttle)((()=>this.repaint()),1e3/60);const{title_location:e,title:t}=this.model;null!=e&&null!=t&&(this._title=t instanceof h.Title?t:new h.Title({text:t}));const{toolbar_location:i,toolbar:s}=this.model;null!=i&&null!=s&&(this._toolbar=new u.ToolbarPanel({toolbar:s}),s.toolbar_location=i)}async lazy_initialize(){await super.lazy_initialize();const{hidpi:e,output_backend:t}=this.model,i=new l.Canvas({hidpi:e,output_backend:t});this.canvas_view=await(0,p.build_view)(i,{parent:this}),this.canvas_view.plot_views=[this],await this.build_renderer_views(),await this.build_tool_views(),this._range_manager.update_dataranges(),this.unpause(!0),g.logger.debug(\"PlotView initialized\")}_width_policy(){return null==this.model.frame_width?super._width_policy():\"min\"}_height_policy(){return null==this.model.frame_height?super._height_policy():\"min\"}_update_layout(){var e,t,i,s,a;this.layout=new z.BorderLayout,this.layout.set_sizing(this.box_sizing());const n=(0,w.copy)(this.model.above),o=(0,w.copy)(this.model.below),l=(0,w.copy)(this.model.left),r=(0,w.copy)(this.model.right),d=e=>{switch(e){case\"above\":return n;case\"below\":return o;case\"left\":return l;case\"right\":return r}},{title_location:c,title:p}=this.model;null!=c&&null!=p&&d(c).push(this._title);const{toolbar_location:v,toolbar:g}=this.model;if(null!=v&&null!=g){const e=d(v);let t=!0;if(this.model.toolbar_sticky)for(let i=0;i{var i;const s=this.renderer_view(t);return s.panel=new q.Panel(e),null===(i=s.update_layout)||void 0===i||i.call(s),s.layout},m=(e,t)=>{const i=\"above\"==e||\"below\"==e,s=[];for(const a of t)if((0,y.isArray)(a)){const t=a.map((t=>{const s=b(e,t);if(t instanceof u.ToolbarPanel){const e=i?\"width_policy\":\"height_policy\";s.set_sizing(Object.assign(Object.assign({},s.sizing),{[e]:\"min\"}))}return s}));let n;i?(n=new k.Row(t),n.set_sizing({width_policy:\"max\",height_policy:\"min\"})):(n=new k.Column(t),n.set_sizing({width_policy:\"min\",height_policy:\"max\"})),n.absolute=!0,s.push(n)}else s.push(b(e,a));return s},f=null!==(e=this.model.min_border)&&void 0!==e?e:0;this.layout.min_border={left:null!==(t=this.model.min_border_left)&&void 0!==t?t:f,top:null!==(i=this.model.min_border_top)&&void 0!==i?i:f,right:null!==(s=this.model.min_border_right)&&void 0!==s?s:f,bottom:null!==(a=this.model.min_border_bottom)&&void 0!==a?a:f};const M=new x.NodeLayout,R=new x.VStack,V=new x.VStack,S=new x.HStack,O=new x.HStack;M.absolute=!0,R.absolute=!0,V.absolute=!0,S.absolute=!0,O.absolute=!0,M.children=this.model.center.filter((e=>e instanceof _.Annotation)).map((e=>{var t;const i=this.renderer_view(e);return null===(t=i.update_layout)||void 0===t||t.call(i),i.layout})).filter((e=>null!=e));const{frame_width:P,frame_height:j}=this.model;M.set_sizing(Object.assign(Object.assign({},null!=P?{width_policy:\"fixed\",width:P}:{width_policy:\"fit\"}),null!=j?{height_policy:\"fixed\",height:j}:{height_policy:\"fit\"})),M.on_resize((e=>this.frame.set_geometry(e))),R.children=(0,w.reversed)(m(\"above\",n)),V.children=m(\"below\",o),S.children=(0,w.reversed)(m(\"left\",l)),O.children=m(\"right\",r),R.set_sizing({width_policy:\"fit\",height_policy:\"min\"}),V.set_sizing({width_policy:\"fit\",height_policy:\"min\"}),S.set_sizing({width_policy:\"min\",height_policy:\"fit\"}),O.set_sizing({width_policy:\"min\",height_policy:\"fit\"}),this.layout.center_panel=M,this.layout.top_panel=R,this.layout.bottom_panel=V,this.layout.left_panel=S,this.layout.right_panel=O}get axis_views(){const e=[];for(const[,t]of this.renderer_views)t instanceof d.AxisView&&e.push(t);return e}set_toolbar_visibility(e){for(const t of this.visibility_callbacks)t(e)}update_range(e,t){this.pause(),this._range_manager.update(e,t),this.unpause()}reset_range(){this.update_range(null),this.trigger_ranges_update_event()}trigger_ranges_update_event(){const{x_range:e,y_range:t}=this.model;this.model.trigger_event(new b.RangesUpdate(e.start,e.end,t.start,t.end))}get_selection(){const e=new Map;for(const t of this.model.data_renderers){const{selected:i}=t.selection_manager.source;e.set(t,i)}return e}update_selection(e){for(const t of this.model.data_renderers){const i=t.selection_manager.source;if(null!=e){const s=e.get(t);null!=s&&i.selected.update(s,!0)}else i.selection_manager.clear()}}reset_selection(){this.update_selection(null)}_invalidate_layout(){(()=>{var e;for(const t of this.model.side_panels){const i=this.renderer_views.get(t);if(null===(e=i.layout)||void 0===e?void 0:e.has_size_changed())return this.invalidate_painters(i),!0}return!1})()&&this.root.compute_layout()}get_renderer_views(){return this.computed_renderers.map((e=>this.renderer_views.get(e)))}*_compute_renderers(){const{above:e,below:t,left:i,right:s,center:a,renderers:n}=this.model;yield*n,yield*e,yield*t,yield*i,yield*s,yield*a,null!=this._title&&(yield this._title),null!=this._toolbar&&(yield this._toolbar);for(const e of this.model.toolbar.tools)null!=e.overlay&&(yield e.overlay),yield*e.synthetic_renderers}async build_renderer_views(){this.computed_renderers=[...this._compute_renderers()],await(0,p.build_views)(this.renderer_views,this.computed_renderers,{parent:this})}async build_tool_views(){const e=this.model.toolbar.tools;(await(0,p.build_views)(this.tool_views,e,{parent:this})).map((e=>this.canvas_view.ui_event_bus.register_tool(e)))}connect_signals(){super.connect_signals();const{x_ranges:e,y_ranges:t}=this.frame;for(const[,t]of e)this.connect(t.change,(()=>{this._needs_layout=!0,this.request_paint(\"everything\")}));for(const[,e]of t)this.connect(e.change,(()=>{this._needs_layout=!0,this.request_paint(\"everything\")}));const{above:i,below:s,left:a,right:n,center:o,renderers:l}=this.model.properties;this.on_change([i,s,a,n,o,l],(async()=>await this.build_renderer_views())),this.connect(this.model.toolbar.properties.tools.change,(async()=>{await this.build_renderer_views(),await this.build_tool_views()})),this.connect(this.model.change,(()=>this.request_paint(\"everything\"))),this.connect(this.model.reset,(()=>this.reset()))}has_finished(){if(!super.has_finished())return!1;if(this.model.visible)for(const[,e]of this.renderer_views)if(!e.has_finished())return!1;return!0}after_layout(){var e;super.after_layout();for(const[,t]of this.renderer_views)t instanceof _.AnnotationView&&(null===(e=t.after_layout)||void 0===e||e.call(t));if(this._needs_layout=!1,this.model.setv({inner_width:Math.round(this.frame.bbox.width),inner_height:Math.round(this.frame.bbox.height),outer_width:Math.round(this.layout.bbox.width),outer_height:Math.round(this.layout.bbox.height)},{no_change:!0}),!1!==this.model.match_aspect&&(this.pause(),this._range_manager.update_dataranges(),this.unpause(!0)),!this._outer_bbox.equals(this.layout.bbox)){const{width:e,height:t}=this.layout.bbox;this.canvas_view.resize(e,t),this._outer_bbox=this.layout.bbox,this._invalidate_all=!0,this._needs_paint=!0}const{inner_bbox:t}=this.layout;this._inner_bbox.equals(t)||(this._inner_bbox=t,this._needs_paint=!0),this._needs_paint&&this.paint()}repaint(){this._needs_layout&&this._invalidate_layout(),this.paint()}paint(){this.is_paused||(this.model.visible&&(g.logger.trace(`${this.toString()}.paint()`),this._actual_paint()),this._needs_notify&&(this._needs_notify=!1,this.notify_finished()))}_actual_paint(){var e;const{document:t}=this.model;if(null!=t){const e=t.interactive_duration();e>=0&&e{t.interactive_duration()>this.model.lod_timeout&&t.interactive_stop(),this.request_paint(\"everything\")}),this.model.lod_timeout):t.interactive_stop()}this._range_manager.invalidate_dataranges&&(this._range_manager.update_dataranges(),this._invalidate_layout());let i=!1,s=!1;if(this._invalidate_all)i=!0,s=!0;else for(const e of this._invalidated_painters){const{level:t}=e.model;if(\"overlay\"!=t?i=!0:s=!0,i&&s)break}this._invalidated_painters.clear(),this._invalidate_all=!1;const a=[this.frame.bbox.left,this.frame.bbox.top,this.frame.bbox.width,this.frame.bbox.height],{primary:n,overlays:o}=this.canvas_view;i&&(n.prepare(),this.canvas_view.prepare_webgl(a),this._map_hook(n.ctx,a),this._paint_empty(n.ctx,a),this._paint_outline(n.ctx,a),this._paint_levels(n.ctx,\"image\",a,!0),this._paint_levels(n.ctx,\"underlay\",a,!0),this._paint_levels(n.ctx,\"glyph\",a,!0),this._paint_levels(n.ctx,\"guide\",a,!1),this._paint_levels(n.ctx,\"annotation\",a,!1),n.finish()),(s||S.settings.wireframe)&&(o.prepare(),this._paint_levels(o.ctx,\"overlay\",a,!1),S.settings.wireframe&&this._paint_layout(o.ctx,this.layout),o.finish()),null==this._initial_state.range&&(this._initial_state.range=null!==(e=this._range_manager.compute_initial())&&void 0!==e?e:void 0),this._needs_paint=!1}_paint_levels(e,t,i,s){for(const a of this.computed_renderers){if(a.level!=t)continue;const n=this.renderer_views.get(a);e.save(),(s||n.needs_clip)&&(e.beginPath(),e.rect(...i),e.clip()),n.render(),e.restore(),n.has_webgl&&n.needs_webgl_blit&&this.canvas_view.blit_webgl(e)}}_paint_layout(e,t){const{x:i,y:s,width:a,height:n}=t.bbox;e.strokeStyle=\"blue\",e.strokeRect(i,s,a,n);for(const a of t)e.save(),t.absolute||e.translate(i,s),this._paint_layout(e,a),e.restore()}_map_hook(e,t){}_paint_empty(e,t){const[i,s,a,n]=[0,0,this.layout.bbox.width,this.layout.bbox.height],[o,l,r,_]=t;this.visuals.border_fill.doit&&(this.visuals.border_fill.set_value(e),e.fillRect(i,s,a,n),e.clearRect(o,l,r,_)),this.visuals.background_fill.doit&&(this.visuals.background_fill.set_value(e),e.fillRect(o,l,r,_))}_paint_outline(e,t){if(this.visuals.outline_line.doit){e.save(),this.visuals.outline_line.set_value(e);let[i,s,a,n]=t;i+a==this.layout.bbox.width&&(a-=1),s+n==this.layout.bbox.height&&(n-=1),e.strokeRect(i,s,a,n),e.restore()}}to_blob(){return this.canvas_view.to_blob()}export(e,t=!0){const i=\"png\"==e?\"canvas\":\"svg\",s=new f.CanvasLayer(i,t),{width:a,height:n}=this.layout.bbox;s.resize(a,n);const{canvas:o}=this.canvas_view.compose();return s.ctx.drawImage(o,0,0),s}serializable_state(){const e=super.serializable_state(),{children:t}=e,i=(0,n.__rest)(e,[\"children\"]),s=this.get_renderer_views().map((e=>e.serializable_state())).filter((e=>null!=e.bbox));return Object.assign(Object.assign({},i),{children:[...null!=t?t:[],...s]})}}i.PlotView=O,O.__name__=\"PlotView\"},\n function _(t,n,e,o,u){o(),e.throttle=function(t,n){let e=null,o=0,u=!1;return function(){return new Promise(((r,i)=>{const l=function(){o=Date.now(),e=null,u=!1;try{t(),r()}catch(t){i(t)}},a=Date.now(),c=n-(a-o);c<=0&&!u?(null!=e&&clearTimeout(e),u=!0,requestAnimationFrame(l)):e||u?r():e=setTimeout((()=>requestAnimationFrame(l)),c)}))}}},\n function _(t,n,e,a,s){a();const o=t(63),r=t(19);class l{constructor(t){this.parent=t,this.invalidate_dataranges=!0}get frame(){return this.parent.frame}update(t,n){const{x_ranges:e,y_ranges:a}=this.frame;if(null==t){for(const[,t]of e)t.reset();for(const[,t]of a)t.reset();this.update_dataranges()}else{const s=[];for(const[n,a]of e)s.push([a,t.xrs.get(n)]);for(const[n,e]of a)s.push([e,t.yrs.get(n)]);(null==n?void 0:n.scrolling)&&this._update_ranges_together(s),this._update_ranges_individually(s,n)}}reset(){this.update(null)}_update_dataranges(t){const n=new Map,e=new Map;let a=!1;for(const[,n]of t.x_ranges)n instanceof o.DataRange1d&&\"log\"==n.scale_hint&&(a=!0);for(const[,n]of t.y_ranges)n instanceof o.DataRange1d&&\"log\"==n.scale_hint&&(a=!0);for(const t of this.parent.model.data_renderers){const s=this.parent.renderer_view(t);if(null==s)continue;const o=s.glyph_view.bounds();if(null!=o&&n.set(t,o),a){const n=s.glyph_view.log_bounds();null!=n&&e.set(t,n)}}let s=!1,l=!1;const i=t.x_target.span,d=t.y_target.span;let u;!1!==this.parent.model.match_aspect&&0!=i&&0!=d&&(u=1/this.parent.model.aspect_scale*(i/d));for(const[,a]of t.x_ranges){if(a instanceof o.DataRange1d){const t=\"log\"==a.scale_hint?e:n;a.update(t,0,this.parent.model,u),a.follow&&(s=!0)}null!=a.bounds&&(l=!0)}for(const[,a]of t.y_ranges){if(a instanceof o.DataRange1d){const t=\"log\"==a.scale_hint?e:n;a.update(t,1,this.parent.model,u),a.follow&&(s=!0)}null!=a.bounds&&(l=!0)}if(s&&l){r.logger.warn(\"Follow enabled so bounds are unset.\");for(const[,n]of t.x_ranges)n.bounds=null;for(const[,n]of t.y_ranges)n.bounds=null}}update_dataranges(){this._update_dataranges(this.frame);for(const t of this.parent.model.renderers){const{coordinates:n}=t;null!=n&&this._update_dataranges(n)}null!=this.compute_initial()&&(this.invalidate_dataranges=!1)}compute_initial(){let t=!0;const{x_ranges:n,y_ranges:e}=this.frame,a=new Map,s=new Map;for(const[e,s]of n){const{start:n,end:o}=s;if(null==n||null==o||isNaN(n+o)){t=!1;break}a.set(e,{start:n,end:o})}if(t)for(const[n,a]of e){const{start:e,end:o}=a;if(null==e||null==o||isNaN(e+o)){t=!1;break}s.set(n,{start:e,end:o})}return t?{xrs:a,yrs:s}:(r.logger.warn(\"could not set initial ranges\"),null)}_update_ranges_together(t){let n=1;for(const[e,a]of t)n=Math.min(n,this._get_weight_to_constrain_interval(e,a));if(n<1)for(const[e,a]of t)a.start=n*a.start+(1-n)*e.start,a.end=n*a.end+(1-n)*e.end}_update_ranges_individually(t,n){const e=!!(null==n?void 0:n.panning),a=!!(null==n?void 0:n.scrolling);let s=!1;for(const[n,o]of t){if(!a){const t=this._get_weight_to_constrain_interval(n,o);t<1&&(o.start=t*o.start+(1-t)*n.start,o.end=t*o.end+(1-t)*n.end)}if(null!=n.bounds&&\"auto\"!=n.bounds){const[t,r]=n.bounds,l=Math.abs(o.end-o.start);n.is_reversed?(null!=t&&t>o.end&&(s=!0,o.end=t,(e||a)&&(o.start=t+l)),null!=r&&ro.start&&(s=!0,o.start=t,(e||a)&&(o.end=t+l)),null!=r&&r0&&r0&&r>a&&(s=(a-o)/(r-o)),s=Math.max(0,Math.min(1,s))}return s}}e.RangeManager=l,l.__name__=\"RangeManager\"},\n function _(t,i,s,e,n){e();const h=t(15);class a{constructor(t,i){this.parent=t,this.initial_state=i,this.changed=new h.Signal0(this.parent,\"state_changed\"),this.history=[],this.index=-1}_do_state_change(t){const i=null!=this.history[t]?this.history[t].state:this.initial_state;return null!=i.range&&this.parent.update_range(i.range),null!=i.selection&&this.parent.update_selection(i.selection),i}push(t,i){const{history:s,index:e}=this,n=null!=s[e]?s[e].state:{},h=Object.assign(Object.assign(Object.assign({},this.initial_state),n),i);this.history=this.history.slice(0,this.index+1),this.history.push({type:t,state:h}),this.index=this.history.length-1,this.changed.emit()}clear(){this.history=[],this.index=-1,this.changed.emit()}undo(){if(this.can_undo){this.index-=1;const t=this._do_state_change(this.index);return this.changed.emit(),t}return null}redo(){if(this.can_redo){this.index+=1;const t=this._do_state_change(this.index);return this.changed.emit(),t}return null}get can_undo(){return this.index>=0}get can_redo(){return this.indexm.emit();const s=encodeURIComponent,o=document.createElement(\"script\");o.type=\"text/javascript\",o.src=`https://maps.googleapis.com/maps/api/js?v=${s(e)}&key=${s(t)}&callback=_bokeh_gmaps_callback`,document.body.appendChild(o)}(t,e)}m.connect((()=>this.request_paint(\"everything\")))}this.unpause()}remove(){(0,p.remove)(this.map_el),super.remove()}update_range(t,e){var s,o;if(null==t)this.map.setCenter({lat:this.initial_lat,lng:this.initial_lng}),this.map.setOptions({zoom:this.initial_zoom}),super.update_range(null,e);else if(null!=t.sdx||null!=t.sdy)this.map.panBy(null!==(s=t.sdx)&&void 0!==s?s:0,null!==(o=t.sdy)&&void 0!==o?o:0),super.update_range(t,e);else if(null!=t.factor){if(10!==this.zoom_count)return void(this.zoom_count+=1);this.zoom_count=0,this.pause(),super.update_range(t,e);const s=t.factor<0?-1:1,o=this.map.getZoom();if(null!=o){const t=o+s;if(t>=2){this.map.setZoom(t);const[e,s]=this._get_projected_bounds();s-e<0&&this.map.setZoom(o)}}this.unpause()}this._set_bokeh_ranges()}_build_map(){const{maps:t}=google;this.map_types={satellite:t.MapTypeId.SATELLITE,terrain:t.MapTypeId.TERRAIN,roadmap:t.MapTypeId.ROADMAP,hybrid:t.MapTypeId.HYBRID};const e=this.model.map_options,s={center:new t.LatLng(e.lat,e.lng),zoom:e.zoom,disableDefaultUI:!0,mapTypeId:this.map_types[e.map_type],scaleControl:e.scale_control,tilt:e.tilt};null!=e.styles&&(s.styles=JSON.parse(e.styles)),this.map_el=(0,p.div)({style:{position:\"absolute\"}}),this.canvas_view.add_underlay(this.map_el),this.map=new t.Map(this.map_el,s),t.event.addListener(this.map,\"idle\",(()=>this._set_bokeh_ranges())),t.event.addListener(this.map,\"bounds_changed\",(()=>this._set_bokeh_ranges())),t.event.addListenerOnce(this.map,\"tilesloaded\",(()=>this._render_finished())),this.connect(this.model.properties.map_options.change,(()=>this._update_options())),this.connect(this.model.map_options.properties.styles.change,(()=>this._update_styles())),this.connect(this.model.map_options.properties.lat.change,(()=>this._update_center(\"lat\"))),this.connect(this.model.map_options.properties.lng.change,(()=>this._update_center(\"lng\"))),this.connect(this.model.map_options.properties.zoom.change,(()=>this._update_zoom())),this.connect(this.model.map_options.properties.map_type.change,(()=>this._update_map_type())),this.connect(this.model.map_options.properties.scale_control.change,(()=>this._update_scale_control())),this.connect(this.model.map_options.properties.tilt.change,(()=>this._update_tilt()))}_render_finished(){this._tiles_loaded=!0,this.notify_finished()}has_finished(){return super.has_finished()&&!0===this._tiles_loaded}_get_latlon_bounds(){const t=this.map.getBounds(),e=t.getNorthEast(),s=t.getSouthWest();return[s.lng(),e.lng(),s.lat(),e.lat()]}_get_projected_bounds(){const[t,e,s,o]=this._get_latlon_bounds(),[i,a]=l.wgs84_mercator.compute(t,s),[n,p]=l.wgs84_mercator.compute(e,o);return[i,n,a,p]}_set_bokeh_ranges(){const[t,e,s,o]=this._get_projected_bounds();this.frame.x_range.setv({start:t,end:e}),this.frame.y_range.setv({start:s,end:o})}_update_center(t){var e;const s=null===(e=this.map.getCenter())||void 0===e?void 0:e.toJSON();null!=s&&(s[t]=this.model.map_options[t],this.map.setCenter(s),this._set_bokeh_ranges())}_update_map_type(){this.map.setOptions({mapTypeId:this.map_types[this.model.map_options.map_type]})}_update_scale_control(){this.map.setOptions({scaleControl:this.model.map_options.scale_control})}_update_tilt(){this.map.setOptions({tilt:this.model.map_options.tilt})}_update_options(){this._update_styles(),this._update_center(\"lat\"),this._update_center(\"lng\"),this._update_zoom(),this._update_map_type()}_update_styles(){this.map.setOptions({styles:JSON.parse(this.model.map_options.styles)})}_update_zoom(){this.map.setOptions({zoom:this.model.map_options.zoom}),this._set_bokeh_ranges()}_map_hook(t,e){if(null==this.map&&\"undefined\"!=typeof google&&null!=google.maps&&this._build_map(),null!=this.map_el){const[t,s,o,i]=e;this.map_el.style.top=`${s}px`,this.map_el.style.left=`${t}px`,this.map_el.style.width=`${o}px`,this.map_el.style.height=`${i}px`}}_paint_empty(t,e){const s=this.layout.bbox.width,o=this.layout.bbox.height,[i,a,n,p]=e;t.clearRect(0,0,s,o),t.beginPath(),t.moveTo(0,0),t.lineTo(0,o),t.lineTo(s,o),t.lineTo(s,0),t.lineTo(0,0),t.moveTo(i,a),t.lineTo(i+n,a),t.lineTo(i+n,a+p),t.lineTo(i,a+p),t.lineTo(i,a),t.closePath(),null!=this.model.border_fill_color&&(t.fillStyle=(0,_.color2css)(this.model.border_fill_color),t.fill())}}s.GMapPlotView=d,d.__name__=\"GMapPlotView\"},\n function _(t,_,n,o,r){o();(0,t(1).__exportStar)(t(132),n)},\n function _(e,r,d,n,R){n(),R(\"GlyphRenderer\",e(175).GlyphRenderer),R(\"GraphRenderer\",e(339).GraphRenderer),R(\"GuideRenderer\",e(129).GuideRenderer);var G=e(41);R(\"Renderer\",G.Renderer),R(\"RendererGroup\",G.RendererGroup)},\n function _(e,r,i,n,t){var o;n();const s=e(176),d=e(175),a=e(303),p=e(302),l=e(113),_=e(178),h=e(283),y=e(286);class c extends s.DataRendererView{get glyph_view(){return this.node_view.glyph}async lazy_initialize(){await super.lazy_initialize(),this.apply_coordinates();const{parent:e}=this,{edge_renderer:r,node_renderer:i}=this.model;this.edge_view=await(0,l.build_view)(r,{parent:e}),this.node_view=await(0,l.build_view)(i,{parent:e})}connect_signals(){super.connect_signals(),this.connect(this.model.layout_provider.change,(()=>{this.apply_coordinates(),this.edge_view.set_data(),this.node_view.set_data(),this.request_render()}))}apply_coordinates(){const{edge_renderer:e,node_renderer:r}=this.model;if(!(e.glyph instanceof h.MultiLine||e.glyph instanceof y.Patches))throw new Error(`${this}.edge_renderer.glyph must be a MultiLine glyph`);if(!(r.glyph instanceof _.XYGlyph))throw new Error(`${this}.node_renderer.glyph must be a XYGlyph glyph`);const i=this.model.layout_provider.edge_coordinates,n=this.model.layout_provider.node_coordinates;e.glyph.properties.xs.internal=!0,e.glyph.properties.ys.internal=!0,r.glyph.properties.x.internal=!0,r.glyph.properties.y.internal=!0,e.glyph.xs={expr:i.x},e.glyph.ys={expr:i.y},r.glyph.x={expr:n.x},r.glyph.y={expr:n.y}}remove(){this.edge_view.remove(),this.node_view.remove(),super.remove()}_render(){this.edge_view.render(),this.node_view.render()}renderer_view(e){if(e instanceof d.GlyphRenderer){if(e==this.edge_view.model)return this.edge_view;if(e==this.node_view.model)return this.node_view}return super.renderer_view(e)}}i.GraphRendererView=c,c.__name__=\"GraphRendererView\";class g extends s.DataRenderer{constructor(e){super(e)}get_selection_manager(){return this.node_renderer.data_source.selection_manager}}i.GraphRenderer=g,o=g,g.__name__=\"GraphRenderer\",o.prototype.default_view=c,o.define((({Ref:e})=>({layout_provider:[e(a.LayoutProvider)],node_renderer:[e(d.GlyphRenderer)],edge_renderer:[e(d.GlyphRenderer)],selection_policy:[e(p.GraphHitTestPolicy),()=>new p.NodesOnly],inspection_policy:[e(p.GraphHitTestPolicy),()=>new p.NodesOnly]})))},\n function _(e,t,n,o,c){o();(0,e(1).__exportStar)(e(74),n),c(\"Selection\",e(72).Selection)},\n function _(a,e,S,o,r){o(),r(\"ServerSentDataSource\",a(342).ServerSentDataSource),r(\"AjaxDataSource\",a(344).AjaxDataSource),r(\"ColumnDataSource\",a(75).ColumnDataSource),r(\"ColumnarDataSource\",a(70).ColumnarDataSource),r(\"CDSView\",a(190).CDSView),r(\"DataSource\",a(71).DataSource),r(\"GeoJSONDataSource\",a(345).GeoJSONDataSource),r(\"WebDataSource\",a(343).WebDataSource)},\n function _(e,t,i,a,s){a();const n=e(343);class r extends n.WebDataSource{constructor(e){super(e),this.initialized=!1}setup(){if(!this.initialized){this.initialized=!0;new EventSource(this.data_url).onmessage=e=>{var t;this.load_data(JSON.parse(e.data),this.mode,null!==(t=this.max_size)&&void 0!==t?t:void 0)}}}}i.ServerSentDataSource=r,r.__name__=\"ServerSentDataSource\"},\n function _(e,t,a,n,r){var s;n();const l=e(75),o=e(20);class c extends l.ColumnDataSource{constructor(e){super(e)}get_column(e){const t=this.data[e];return null!=t?t:[]}get_length(){var e;return null!==(e=super.get_length())&&void 0!==e?e:0}initialize(){super.initialize(),this.setup()}load_data(e,t,a){const{adapter:n}=this;let r;switch(r=null!=n?n.execute(this,{response:e}):e,t){case\"replace\":this.data=r;break;case\"append\":{const e=this.data;for(const t of this.columns()){const n=Array.from(e[t]),s=Array.from(r[t]),l=n.concat(s);r[t]=null!=a?l.slice(-a):l}this.data=r;break}}}}a.WebDataSource=c,s=c,c.__name__=\"WebDataSource\",s.define((({Any:e,Int:t,String:a,Nullable:n})=>({max_size:[n(t),null],mode:[o.UpdateMode,\"replace\"],adapter:[n(e),null],data_url:[a]})))},\n function _(t,e,i,s,a){var n;s();const r=t(343),o=t(20),l=t(19),d=t(13);class h extends r.WebDataSource{constructor(t){super(t),this.interval=null,this.initialized=!1}destroy(){null!=this.interval&&clearInterval(this.interval),super.destroy()}setup(){if(!this.initialized&&(this.initialized=!0,this.get_data(this.mode),null!=this.polling_interval)){const t=()=>this.get_data(this.mode,this.max_size,this.if_modified);this.interval=setInterval(t,this.polling_interval)}}get_data(t,e=null,i=!1){const s=this.prepare_request();s.addEventListener(\"load\",(()=>this.do_load(s,t,null!=e?e:void 0))),s.addEventListener(\"error\",(()=>this.do_error(s))),s.send()}prepare_request(){const t=new XMLHttpRequest;t.open(this.method,this.data_url,!0),t.withCredentials=!1,t.setRequestHeader(\"Content-Type\",this.content_type);const e=this.http_headers;for(const[i,s]of(0,d.entries)(e))t.setRequestHeader(i,s);return t}do_load(t,e,i){if(200===t.status){const s=JSON.parse(t.responseText);this.load_data(s,e,i)}}do_error(t){l.logger.error(`Failed to fetch JSON from ${this.data_url} with code ${t.status}`)}}i.AjaxDataSource=h,n=h,h.__name__=\"AjaxDataSource\",n.define((({Boolean:t,Int:e,String:i,Dict:s,Nullable:a})=>({polling_interval:[a(e),null],content_type:[i,\"application/json\"],http_headers:[s(i),{}],method:[o.HTTPMethod,\"POST\"],if_modified:[t,!1]})))},\n function _(e,t,o,r,n){var s;r();const a=e(70),i=e(19),l=e(9),c=e(13);function _(e){return null!=e?e:NaN}const{hasOwnProperty:g}=Object.prototype;class u extends a.ColumnarDataSource{constructor(e){super(e)}initialize(){super.initialize(),this._update_data()}connect_signals(){super.connect_signals(),this.connect(this.properties.geojson.change,(()=>this._update_data()))}_update_data(){this.data=this.geojson_to_column_data()}_get_new_list_array(e){return(0,l.range)(0,e).map((e=>[]))}_get_new_nan_array(e){return(0,l.range)(0,e).map((e=>NaN))}_add_properties(e,t,o,r){var n;const s=null!==(n=e.properties)&&void 0!==n?n:{};for(const[e,n]of(0,c.entries)(s))g.call(t,e)||(t[e]=this._get_new_nan_array(r)),t[e][o]=_(n)}_add_geometry(e,t,o){function r(e,t){return e.concat([[NaN,NaN,NaN]]).concat(t)}switch(e.type){case\"Point\":{const[r,n,s]=e.coordinates;t.x[o]=r,t.y[o]=n,t.z[o]=_(s);break}case\"LineString\":{const{coordinates:r}=e;for(let e=0;e1&&i.logger.warn(\"Bokeh does not support Polygons with holes in, only exterior ring used.\");const r=e.coordinates[0];for(let e=0;e1&&i.logger.warn(\"Bokeh does not support Polygons with holes in, only exterior ring used.\"),n.push(t[0]);const s=n.reduce(r);for(let e=0;e({geojson:[e]}))),s.internal((({Dict:e,Arrayable:t})=>({data:[e(t),{}]})))},\n function _(e,r,T,o,S){o(),S(\"BBoxTileSource\",e(347).BBoxTileSource),S(\"MercatorTileSource\",e(348).MercatorTileSource),S(\"QUADKEYTileSource\",e(351).QUADKEYTileSource),S(\"TileRenderer\",e(352).TileRenderer),S(\"TileSource\",e(349).TileSource),S(\"TMSTileSource\",e(355).TMSTileSource),S(\"WMTSTileSource\",e(353).WMTSTileSource)},\n function _(e,t,r,o,l){var i;o();const n=e(348);class s extends n.MercatorTileSource{constructor(e){super(e)}get_image_url(e,t,r){const o=this.string_lookup_replace(this.url,this.extra_url_vars);let l,i,n,s;return this.use_latlon?[i,s,l,n]=this.get_tile_geographic_bounds(e,t,r):[i,s,l,n]=this.get_tile_meter_bounds(e,t,r),o.replace(\"{XMIN}\",i.toString()).replace(\"{YMIN}\",s.toString()).replace(\"{XMAX}\",l.toString()).replace(\"{YMAX}\",n.toString())}}r.BBoxTileSource=s,i=s,s.__name__=\"BBoxTileSource\",i.define((({Boolean:e})=>({use_latlon:[e,!1]})))},\n function _(t,e,i,_,s){var r;_();const o=t(349),n=t(9),l=t(350);class u extends o.TileSource{constructor(t){super(t)}initialize(){super.initialize(),this._resolutions=(0,n.range)(this.min_zoom,this.max_zoom+1).map((t=>this.get_resolution(t)))}_computed_initial_resolution(){return null!=this.initial_resolution?this.initial_resolution:2*Math.PI*6378137/this.tile_size}is_valid_tile(t,e,i){return!(!this.wrap_around&&(t<0||t>=2**i))&&!(e<0||e>=2**i)}parent_by_tile_xyz(t,e,i){const _=this.tile_xyz_to_quadkey(t,e,i),s=_.substring(0,_.length-1);return this.quadkey_to_tile_xyz(s)}get_resolution(t){return this._computed_initial_resolution()/2**t}get_resolution_by_extent(t,e,i){return[(t[2]-t[0])/i,(t[3]-t[1])/e]}get_level_by_extent(t,e,i){const _=(t[2]-t[0])/i,s=(t[3]-t[1])/e,r=Math.max(_,s);let o=0;for(const t of this._resolutions){if(r>t){if(0==o)return 0;if(o>0)return o-1}o+=1}return o-1}get_closest_level_by_extent(t,e,i){const _=(t[2]-t[0])/i,s=(t[3]-t[1])/e,r=Math.max(_,s),o=this._resolutions.reduce((function(t,e){return Math.abs(e-r)e?(u=o-s,a*=t):(u*=e,a=n-r)}const h=(u-(o-s))/2,c=(a-(n-r))/2;return[s-h,r-c,o+h,n+c]}tms_to_wmts(t,e,i){return[t,2**i-1-e,i]}wmts_to_tms(t,e,i){return[t,2**i-1-e,i]}pixels_to_meters(t,e,i){const _=this.get_resolution(i);return[t*_-this.x_origin_offset,e*_-this.y_origin_offset]}meters_to_pixels(t,e,i){const _=this.get_resolution(i);return[(t+this.x_origin_offset)/_,(e+this.y_origin_offset)/_]}pixels_to_tile(t,e){let i=Math.ceil(t/this.tile_size);i=0===i?i:i-1;return[i,Math.max(Math.ceil(e/this.tile_size)-1,0)]}pixels_to_raster(t,e,i){return[t,(this.tile_size<=l;t--)for(let i=n;i<=u;i++)this.is_valid_tile(i,t,e)&&h.push([i,t,e,this.get_tile_meter_bounds(i,t,e)]);return this.sort_tiles_from_center(h,[n,l,u,a]),h}quadkey_to_tile_xyz(t){let e=0,i=0;const _=t.length;for(let s=_;s>0;s--){const r=1<0;s--){const i=1<0;)if(s=s.substring(0,s.length-1),[t,e,i]=this.quadkey_to_tile_xyz(s),[t,e,i]=this.denormalize_xyz(t,e,i,_),this.tiles.has(this.tile_xyz_to_key(t,e,i)))return[t,e,i];return[0,0,0]}normalize_xyz(t,e,i){if(this.wrap_around){const _=2**i;return[(t%_+_)%_,e,i]}return[t,e,i]}denormalize_xyz(t,e,i,_){return[t+_*2**i,e,i]}denormalize_meters(t,e,i,_){return[t+2*_*Math.PI*6378137,e]}calculate_world_x_by_tile_xyz(t,e,i){return Math.floor(t/2**i)}}i.MercatorTileSource=u,r=u,u.__name__=\"MercatorTileSource\",r.define((({Boolean:t})=>({snap_to_zoom:[t,!1],wrap_around:[t,!0]}))),r.override({x_origin_offset:20037508.34,y_origin_offset:20037508.34,initial_resolution:156543.03392804097})},\n function _(e,t,r,i,n){var l;i();const a=e(53),s=e(13);class c extends a.Model{constructor(e){super(e)}initialize(){super.initialize(),this.tiles=new Map,this._normalize_case()}connect_signals(){super.connect_signals(),this.connect(this.change,(()=>this._clear_cache()))}string_lookup_replace(e,t){let r=e;for(const[e,i]of(0,s.entries)(t))r=r.replace(`{${e}}`,i);return r}_normalize_case(){const e=this.url.replace(\"{x}\",\"{X}\").replace(\"{y}\",\"{Y}\").replace(\"{z}\",\"{Z}\").replace(\"{q}\",\"{Q}\").replace(\"{xmin}\",\"{XMIN}\").replace(\"{ymin}\",\"{YMIN}\").replace(\"{xmax}\",\"{XMAX}\").replace(\"{ymax}\",\"{YMAX}\");this.url=e}_clear_cache(){this.tiles=new Map}tile_xyz_to_key(e,t,r){return`${e}:${t}:${r}`}key_to_tile_xyz(e){const[t,r,i]=e.split(\":\").map((e=>parseInt(e)));return[t,r,i]}sort_tiles_from_center(e,t){const[r,i,n,l]=t,a=(n-r)/2+r,s=(l-i)/2+i;e.sort((function(e,t){return Math.sqrt((a-e[0])**2+(s-e[1])**2)-Math.sqrt((a-t[0])**2+(s-t[1])**2)}))}get_image_url(e,t,r){return this.string_lookup_replace(this.url,this.extra_url_vars).replace(\"{X}\",e.toString()).replace(\"{Y}\",t.toString()).replace(\"{Z}\",r.toString())}}r.TileSource=c,l=c,c.__name__=\"TileSource\",l.define((({Number:e,String:t,Dict:r,Nullable:i})=>({url:[t,\"\"],tile_size:[e,256],max_zoom:[e,30],min_zoom:[e,0],extra_url_vars:[r(t),{}],attribution:[t,\"\"],x_origin_offset:[e],y_origin_offset:[e],initial_resolution:[i(e),null]})))},\n function _(t,e,r,n,o){n();const c=t(78);function _(t,e){return c.wgs84_mercator.compute(t,e)}function g(t,e){return c.wgs84_mercator.invert(t,e)}r.geographic_to_meters=_,r.meters_to_geographic=g,r.geographic_extent_to_meters=function(t){const[e,r,n,o]=t,[c,g]=_(e,r),[i,u]=_(n,o);return[c,g,i,u]},r.meters_extent_to_geographic=function(t){const[e,r,n,o]=t,[c,_]=g(e,r),[i,u]=g(n,o);return[c,_,i,u]}},\n function _(e,t,r,s,_){s();const o=e(348);class c extends o.MercatorTileSource{constructor(e){super(e)}get_image_url(e,t,r){const s=this.string_lookup_replace(this.url,this.extra_url_vars),[_,o,c]=this.tms_to_wmts(e,t,r),i=this.tile_xyz_to_quadkey(_,o,c);return s.replace(\"{Q}\",i)}}r.QUADKEYTileSource=c,c.__name__=\"QUADKEYTileSource\"},\n function _(t,e,i,s,_){s();const n=t(1);var a;const o=t(349),r=t(353),h=t(41),l=t(58),d=t(43),m=t(136),c=t(9),u=t(8),p=(0,n.__importStar)(t(354));class g extends h.RendererView{initialize(){this._tiles=[],super.initialize()}connect_signals(){super.connect_signals(),this.connect(this.model.change,(()=>this.request_render())),this.connect(this.model.tile_source.change,(()=>this.request_render()))}remove(){null!=this.attribution_el&&(0,d.removeElement)(this.attribution_el),super.remove()}styles(){return[...super.styles(),p.default]}get_extent(){return[this.x_range.start,this.y_range.start,this.x_range.end,this.y_range.end]}get map_plot(){return this.plot_model}get map_canvas(){return this.layer.ctx}get map_frame(){return this.plot_view.frame}get x_range(){return this.map_plot.x_range}get y_range(){return this.map_plot.y_range}_set_data(){this.extent=this.get_extent(),this._last_height=void 0,this._last_width=void 0}_update_attribution(){null!=this.attribution_el&&(0,d.removeElement)(this.attribution_el);const{attribution:t}=this.model.tile_source;if((0,u.isString)(t)&&t.length>0){const{layout:e,frame:i}=this.plot_view,s=e.bbox.width-i.bbox.right,_=e.bbox.height-i.bbox.bottom,n=i.bbox.width;this.attribution_el=(0,d.div)({class:p.tile_attribution,style:{position:\"absolute\",right:`${s}px`,bottom:`${_}px`,\"max-width\":n-4+\"px\",padding:\"2px\",\"background-color\":\"rgba(255,255,255,0.5)\",\"font-size\":\"9px\",\"line-height\":\"1.05\",\"white-space\":\"nowrap\",overflow:\"hidden\",\"text-overflow\":\"ellipsis\"}}),this.plot_view.canvas_view.add_event(this.attribution_el),this.attribution_el.innerHTML=t,this.attribution_el.title=this.attribution_el.textContent.replace(/\\s*\\n\\s*/g,\" \")}}_map_data(){this.initial_extent=this.get_extent();const t=this.model.tile_source.get_level_by_extent(this.initial_extent,this.map_frame.bbox.height,this.map_frame.bbox.width),e=this.model.tile_source.snap_to_zoom_level(this.initial_extent,this.map_frame.bbox.height,this.map_frame.bbox.width,t);this.x_range.start=e[0],this.y_range.start=e[1],this.x_range.end=e[2],this.y_range.end=e[3],this.x_range instanceof l.Range1d&&(this.x_range.reset_start=e[0],this.x_range.reset_end=e[2]),this.y_range instanceof l.Range1d&&(this.y_range.reset_start=e[1],this.y_range.reset_end=e[3]),this._update_attribution()}_create_tile(t,e,i,s,_=!1){const n=this.model.tile_source.tile_xyz_to_quadkey(t,e,i),a=this.model.tile_source.tile_xyz_to_key(t,e,i);if(this.model.tile_source.tiles.has(a))return;const[o,r,h]=this.model.tile_source.normalize_xyz(t,e,i),l=this.model.tile_source.get_image_url(o,r,h),d={img:void 0,tile_coords:[t,e,i],normalized_coords:[o,r,h],quadkey:n,cache_key:a,bounds:s,loaded:!1,finished:!1,x_coord:s[0],y_coord:s[3]};this.model.tile_source.tiles.set(a,d),this._tiles.push(d),new m.ImageLoader(l,{loaded:t=>{Object.assign(d,{img:t,loaded:!0}),_?(d.finished=!0,this.notify_finished()):this.request_render()},failed(){d.finished=!0}})}_enforce_aspect_ratio(){if(this._last_height!==this.map_frame.bbox.height||this._last_width!==this.map_frame.bbox.width){const t=this.get_extent(),e=this.model.tile_source.get_level_by_extent(t,this.map_frame.bbox.height,this.map_frame.bbox.width),i=this.model.tile_source.snap_to_zoom_level(t,this.map_frame.bbox.height,this.map_frame.bbox.width,e);this.x_range.setv({start:i[0],end:i[2]}),this.y_range.setv({start:i[1],end:i[3]}),this.extent=i,this._last_height=this.map_frame.bbox.height,this._last_width=this.map_frame.bbox.width}}has_finished(){if(!super.has_finished())return!1;if(0==this._tiles.length)return!1;for(const t of this._tiles)if(!t.finished)return!1;return!0}_render(){null==this.map_initialized&&(this._set_data(),this._map_data(),this.map_initialized=!0),this._enforce_aspect_ratio(),this._update(),null!=this.prefetch_timer&&clearTimeout(this.prefetch_timer),this.prefetch_timer=setTimeout(this._prefetch_tiles.bind(this),500),this.has_finished()&&this.notify_finished()}_draw_tile(t){const e=this.model.tile_source.tiles.get(t);if(null!=e&&e.loaded){const[[t],[i]]=this.coordinates.map_to_screen([e.bounds[0]],[e.bounds[3]]),[[s],[_]]=this.coordinates.map_to_screen([e.bounds[2]],[e.bounds[1]]),n=s-t,a=_-i,o=t,r=i,h=this.map_canvas.getImageSmoothingEnabled();this.map_canvas.setImageSmoothingEnabled(this.model.smoothing),this.map_canvas.drawImage(e.img,o,r,n,a),this.map_canvas.setImageSmoothingEnabled(h),e.finished=!0}}_set_rect(){const t=this.plot_model.outline_line_width,e=this.map_frame.bbox.left+t/2,i=this.map_frame.bbox.top+t/2,s=this.map_frame.bbox.width-t,_=this.map_frame.bbox.height-t;this.map_canvas.rect(e,i,s,_),this.map_canvas.clip()}_render_tiles(t){this.map_canvas.save(),this._set_rect(),this.map_canvas.globalAlpha=this.model.alpha;for(const e of t)this._draw_tile(e);this.map_canvas.restore()}_prefetch_tiles(){const{tile_source:t}=this.model,e=this.get_extent(),i=this.map_frame.bbox.height,s=this.map_frame.bbox.width,_=this.model.tile_source.get_level_by_extent(e,i,s),n=this.model.tile_source.get_tiles_by_extent(e,_);for(let e=0,i=Math.min(10,n.length);ei&&(s=this.extent,o=i,r=!0),r&&(this.x_range.setv({start:s[0],end:s[2]}),this.y_range.setv({start:s[1],end:s[3]})),this.extent=s;const h=t.get_tiles_by_extent(s,o),l=[],d=[],m=[],u=[];for(const e of h){const[i,s,n]=e,a=t.tile_xyz_to_key(i,s,n),o=t.tiles.get(a);if(null!=o&&o.loaded)d.push(a);else if(this.model.render_parents){const[e,a,o]=t.get_closest_parent_by_tile_xyz(i,s,n),r=t.tile_xyz_to_key(e,a,o),h=t.tiles.get(r);if(null!=h&&h.loaded&&!(0,c.includes)(m,r)&&m.push(r),_){const e=t.children_by_tile_xyz(i,s,n);for(const[i,s,_]of e){const e=t.tile_xyz_to_key(i,s,_);t.tiles.has(e)&&u.push(e)}}}null==o&&l.push(e)}this._render_tiles(m),this._render_tiles(u),this._render_tiles(d),null!=this.render_timer&&clearTimeout(this.render_timer),this.render_timer=setTimeout((()=>this._fetch_tiles(l)),65)}}i.TileRendererView=g,g.__name__=\"TileRendererView\";class b extends h.Renderer{constructor(t){super(t)}}i.TileRenderer=b,a=b,b.__name__=\"TileRenderer\",a.prototype.default_view=g,a.define((({Boolean:t,Number:e,Ref:i})=>({alpha:[e,1],smoothing:[t,!0],tile_source:[i(o.TileSource),()=>new r.WMTSTileSource],render_parents:[t,!0]}))),a.override({level:\"image\"})},\n function _(t,e,r,o,s){o();const c=t(348);class i extends c.MercatorTileSource{constructor(t){super(t)}get_image_url(t,e,r){const o=this.string_lookup_replace(this.url,this.extra_url_vars),[s,c,i]=this.tms_to_wmts(t,e,r);return o.replace(\"{X}\",s.toString()).replace(\"{Y}\",c.toString()).replace(\"{Z}\",i.toString())}}r.WMTSTileSource=i,i.__name__=\"WMTSTileSource\"},\n function _(t,o,i,b,r){b(),i.root=\"bk-root\",i.tile_attribution=\"bk-tile-attribution\",i.default=\".bk-root .bk-tile-attribution a{color:black;}\"},\n function _(e,r,t,c,o){c();const i=e(348);class l extends i.MercatorTileSource{constructor(e){super(e)}get_image_url(e,r,t){return this.string_lookup_replace(this.url,this.extra_url_vars).replace(\"{X}\",e.toString()).replace(\"{Y}\",r.toString()).replace(\"{Z}\",t.toString())}}t.TMSTileSource=l,l.__name__=\"TMSTileSource\"},\n function _(e,t,u,a,r){a(),r(\"CanvasTexture\",e(357).CanvasTexture),r(\"ImageURLTexture\",e(359).ImageURLTexture),r(\"Texture\",e(358).Texture)},\n function _(t,e,n,c,s){var r;c();const o=t(358),a=t(34);class u extends o.Texture{constructor(t){super(t)}get func(){const t=(0,a.use_strict)(this.code);return new Function(\"ctx\",\"color\",\"scale\",\"weight\",t)}get_pattern(t,e,n){const c=document.createElement(\"canvas\");c.width=e,c.height=e;const s=c.getContext(\"2d\");return this.func.call(this,s,t,e,n),c}}n.CanvasTexture=u,r=u,u.__name__=\"CanvasTexture\",r.define((({String:t})=>({code:[t]})))},\n function _(e,t,n,r,o){var i;r();const s=e(53),u=e(20);class c extends s.Model{constructor(e){super(e)}}n.Texture=c,i=c,c.__name__=\"Texture\",i.define((()=>({repetition:[u.TextureRepetition,\"repeat\"]})))},\n function _(e,t,i,r,n){var a;r();const s=e(358),o=e(136);class u extends s.Texture{constructor(e){super(e)}initialize(){super.initialize(),this._loader=new o.ImageLoader(this.url)}get_pattern(e,t,i){const{_loader:r}=this;return this._loader.finished?r.image:r.promise}}i.ImageURLTexture=u,a=u,u.__name__=\"ImageURLTexture\",a.define((({String:e})=>({url:[e]})))},\n function _(o,l,T,e,t){e(),t(\"ActionTool\",o(238).ActionTool),t(\"CustomAction\",o(361).CustomAction),t(\"HelpTool\",o(239).HelpTool),t(\"RedoTool\",o(362).RedoTool),t(\"ResetTool\",o(363).ResetTool),t(\"SaveTool\",o(364).SaveTool),t(\"UndoTool\",o(365).UndoTool),t(\"ZoomInTool\",o(366).ZoomInTool),t(\"ZoomOutTool\",o(369).ZoomOutTool),t(\"ButtonTool\",o(224).ButtonTool),t(\"EditTool\",o(370).EditTool),t(\"BoxEditTool\",o(371).BoxEditTool),t(\"FreehandDrawTool\",o(372).FreehandDrawTool),t(\"PointDrawTool\",o(373).PointDrawTool),t(\"PolyDrawTool\",o(374).PolyDrawTool),t(\"PolyTool\",o(375).PolyTool),t(\"PolyEditTool\",o(376).PolyEditTool),t(\"BoxSelectTool\",o(377).BoxSelectTool),t(\"BoxZoomTool\",o(379).BoxZoomTool),t(\"GestureTool\",o(223).GestureTool),t(\"LassoSelectTool\",o(380).LassoSelectTool),t(\"LineEditTool\",o(382).LineEditTool),t(\"PanTool\",o(384).PanTool),t(\"PolySelectTool\",o(381).PolySelectTool),t(\"RangeTool\",o(385).RangeTool),t(\"SelectTool\",o(378).SelectTool),t(\"TapTool\",o(386).TapTool),t(\"WheelPanTool\",o(387).WheelPanTool),t(\"WheelZoomTool\",o(388).WheelZoomTool),t(\"CrosshairTool\",o(389).CrosshairTool),t(\"CustomJSHover\",o(390).CustomJSHover),t(\"HoverTool\",o(391).HoverTool),t(\"InspectTool\",o(232).InspectTool),t(\"Tool\",o(222).Tool),t(\"ToolProxy\",o(394).ToolProxy),t(\"Toolbar\",o(221).Toolbar),t(\"ToolbarBase\",o(233).ToolbarBase),t(\"ProxyToolbar\",o(395).ProxyToolbar),t(\"ToolbarBox\",o(395).ToolbarBox)},\n function _(t,o,e,s,n){var c;s();const i=t(238);class u extends i.ActionToolButtonView{css_classes(){return super.css_classes().concat(\"bk-toolbar-button-custom-action\")}}e.CustomActionButtonView=u,u.__name__=\"CustomActionButtonView\";class l extends i.ActionToolView{doit(){var t;null===(t=this.model.callback)||void 0===t||t.execute(this.model)}}e.CustomActionView=l,l.__name__=\"CustomActionView\";class a extends i.ActionTool{constructor(t){super(t),this.tool_name=\"Custom Action\",this.button_view=u}}e.CustomAction=a,c=a,a.__name__=\"CustomAction\",c.prototype.default_view=l,c.define((({Any:t,String:o,Nullable:e})=>({callback:[e(t)],icon:[o]}))),c.override({description:\"Perform a Custom Action\"})},\n function _(e,o,t,i,s){var n;i();const l=e(238),_=e(228);class d extends l.ActionToolView{connect_signals(){super.connect_signals(),this.connect(this.plot_view.state.changed,(()=>this.model.disabled=!this.plot_view.state.can_redo))}doit(){const e=this.plot_view.state.redo();null!=(null==e?void 0:e.range)&&this.plot_view.trigger_ranges_update_event()}}t.RedoToolView=d,d.__name__=\"RedoToolView\";class a extends l.ActionTool{constructor(e){super(e),this.tool_name=\"Redo\",this.icon=_.tool_icon_redo}}t.RedoTool=a,n=a,a.__name__=\"RedoTool\",n.prototype.default_view=d,n.override({disabled:!0}),n.register_alias(\"redo\",(()=>new a))},\n function _(e,o,t,s,i){var _;s();const n=e(238),l=e(228);class c extends n.ActionToolView{doit(){this.plot_view.reset()}}t.ResetToolView=c,c.__name__=\"ResetToolView\";class r extends n.ActionTool{constructor(e){super(e),this.tool_name=\"Reset\",this.icon=l.tool_icon_reset}}t.ResetTool=r,_=r,r.__name__=\"ResetTool\",_.prototype.default_view=c,_.register_alias(\"reset\",(()=>new r))},\n function _(e,o,t,a,i){var s;a();const c=e(238),n=e(228);class l extends c.ActionToolView{async copy(){const e=await this.plot_view.to_blob(),o=new ClipboardItem({[e.type]:Promise.resolve(e)});await navigator.clipboard.write([o])}async save(e){const o=await this.plot_view.to_blob(),t=document.createElement(\"a\");t.href=URL.createObjectURL(o),t.download=e,t.target=\"_blank\",t.dispatchEvent(new MouseEvent(\"click\"))}doit(e=\"save\"){switch(e){case\"save\":this.save(\"bokeh_plot\");break;case\"copy\":this.copy()}}}t.SaveToolView=l,l.__name__=\"SaveToolView\";class r extends c.ActionTool{constructor(e){super(e),this.tool_name=\"Save\",this.icon=n.tool_icon_save}get menu(){return[{icon:\"bk-tool-icon-copy-to-clipboard\",tooltip:\"Copy image to clipboard\",if:()=>\"undefined\"!=typeof ClipboardItem,handler:()=>{this.do.emit(\"copy\")}}]}}t.SaveTool=r,s=r,r.__name__=\"SaveTool\",s.prototype.default_view=l,s.register_alias(\"save\",(()=>new r))},\n function _(o,e,t,n,i){var s;n();const l=o(238),_=o(228);class d extends l.ActionToolView{connect_signals(){super.connect_signals(),this.connect(this.plot_view.state.changed,(()=>this.model.disabled=!this.plot_view.state.can_undo))}doit(){const o=this.plot_view.state.undo();null!=(null==o?void 0:o.range)&&this.plot_view.trigger_ranges_update_event()}}t.UndoToolView=d,d.__name__=\"UndoToolView\";class a extends l.ActionTool{constructor(o){super(o),this.tool_name=\"Undo\",this.icon=_.tool_icon_undo}}t.UndoTool=a,s=a,a.__name__=\"UndoTool\",s.prototype.default_view=d,s.override({disabled:!0}),s.register_alias(\"undo\",(()=>new a))},\n function _(o,n,e,i,s){var t;i();const _=o(367),m=o(228);class a extends _.ZoomBaseToolView{}e.ZoomInToolView=a,a.__name__=\"ZoomInToolView\";class l extends _.ZoomBaseTool{constructor(o){super(o),this.sign=1,this.tool_name=\"Zoom In\",this.icon=m.tool_icon_zoom_in}}e.ZoomInTool=l,t=l,l.__name__=\"ZoomInTool\",t.prototype.default_view=a,t.register_alias(\"zoom_in\",(()=>new l({dimensions:\"both\"}))),t.register_alias(\"xzoom_in\",(()=>new l({dimensions:\"width\"}))),t.register_alias(\"yzoom_in\",(()=>new l({dimensions:\"height\"})))},\n function _(o,t,e,i,s){var n;i();const a=o(238),_=o(20),l=o(368);class m extends a.ActionToolView{doit(){var o;const t=this.plot_view.frame,e=this.model.dimensions,i=\"width\"==e||\"both\"==e,s=\"height\"==e||\"both\"==e,n=(0,l.scale_range)(t,this.model.sign*this.model.factor,i,s);this.plot_view.state.push(\"zoom_out\",{range:n}),this.plot_view.update_range(n,{scrolling:!0,maintain_focus:this.model.maintain_focus}),null===(o=this.model.document)||void 0===o||o.interactive_start(this.plot_model),this.plot_view.trigger_ranges_update_event()}}e.ZoomBaseToolView=m,m.__name__=\"ZoomBaseToolView\";class h extends a.ActionTool{constructor(o){super(o),this.maintain_focus=!0}get tooltip(){return this._get_dim_tooltip(this.dimensions)}}e.ZoomBaseTool=h,n=h,h.__name__=\"ZoomBaseTool\",n.define((({Percent:o})=>({factor:[o,.1],dimensions:[_.Dimensions,\"both\"]})))},\n function _(n,t,o,r,s){r();const c=n(10);function e(n,t,o){const[r,s]=[n.start,n.end],c=null!=o?o:(s+r)/2;return[r-(r-c)*t,s-(s-c)*t]}function a(n,[t,o]){const r=new Map;for(const[s,c]of n){const[n,e]=c.r_invert(t,o);r.set(s,{start:n,end:e})}return r}o.scale_highlow=e,o.get_info=a,o.scale_range=function(n,t,o=!0,r=!0,s){t=(0,c.clamp)(t,-.9,.9);const l=o?t:0,[u,i]=e(n.bbox.h_range,l,null!=s?s.x:void 0),_=a(n.x_scales,[u,i]),f=r?t:0,[g,x]=e(n.bbox.v_range,f,null!=s?s.y:void 0);return{xrs:_,yrs:a(n.y_scales,[g,x]),factor:t}}},\n function _(o,e,t,i,s){var n;i();const _=o(367),a=o(228);class m extends _.ZoomBaseToolView{}t.ZoomOutToolView=m,m.__name__=\"ZoomOutToolView\";class l extends _.ZoomBaseTool{constructor(o){super(o),this.sign=-1,this.tool_name=\"Zoom Out\",this.icon=a.tool_icon_zoom_out}}t.ZoomOutTool=l,n=l,l.__name__=\"ZoomOutTool\",n.prototype.default_view=m,n.define((({Boolean:o})=>({maintain_focus:[o,!0]}))),n.register_alias(\"zoom_out\",(()=>new l({dimensions:\"both\"}))),n.register_alias(\"xzoom_out\",(()=>new l({dimensions:\"width\"}))),n.register_alias(\"yzoom_out\",(()=>new l({dimensions:\"height\"})))},\n function _(e,t,s,o,n){var r;o();const i=e(9),c=e(8),a=e(11),_=e(175),l=e(223);class d extends l.GestureToolView{constructor(){super(...arguments),this._mouse_in_frame=!0}_select_mode(e){const{shiftKey:t,ctrlKey:s}=e;return t||s?t&&!s?\"append\":!t&&s?\"intersect\":t&&s?\"subtract\":void(0,a.unreachable)():\"replace\"}_move_enter(e){this._mouse_in_frame=!0}_move_exit(e){this._mouse_in_frame=!1}_map_drag(e,t,s){if(!this.plot_view.frame.bbox.contains(e,t))return null;const o=this.plot_view.renderer_view(s);if(null==o)return null;return[o.coordinates.x_scale.invert(e),o.coordinates.y_scale.invert(t)]}_delete_selected(e){const t=e.data_source,s=t.selected.indices;s.sort();for(const e of t.columns()){const o=t.get_array(e);for(let e=0;e({custom_icon:[n(t),null],empty_value:[e],renderers:[s(o(_.GlyphRenderer)),[]]})))},\n function _(e,t,s,i,_){var o;i();const n=e(43),a=e(20),d=e(370),l=e(228);class r extends d.EditToolView{_tap(e){null==this._draw_basepoint&&null==this._basepoint&&this._select_event(e,this._select_mode(e),this.model.renderers)}_keyup(e){if(this.model.active&&this._mouse_in_frame)for(const t of this.model.renderers)if(e.keyCode===n.Keys.Backspace)this._delete_selected(t);else if(e.keyCode==n.Keys.Esc){t.data_source.selection_manager.clear()}}_set_extent([e,t],[s,i],_,o=!1){const n=this.model.renderers[0],a=this.plot_view.renderer_view(n);if(null==a)return;const d=n.glyph,l=n.data_source,[r,h]=a.coordinates.x_scale.r_invert(e,t),[p,u]=a.coordinates.y_scale.r_invert(s,i),[c,m]=[(r+h)/2,(p+u)/2],[f,b]=[h-r,u-p],[y,x]=[d.x.field,d.y.field],[w,v]=[d.width.field,d.height.field];if(_)this._pop_glyphs(l,this.model.num_objects),y&&l.get_array(y).push(c),x&&l.get_array(x).push(m),w&&l.get_array(w).push(f),v&&l.get_array(v).push(b),this._pad_empty_columns(l,[y,x,w,v]);else{const e=l.data[y].length-1;y&&(l.data[y][e]=c),x&&(l.data[x][e]=m),w&&(l.data[w][e]=f),v&&(l.data[v][e]=b)}this._emit_cds_changes(l,!0,!1,o)}_update_box(e,t=!1,s=!1){if(null==this._draw_basepoint)return;const i=[e.sx,e.sy],_=this.plot_view.frame,o=this.model.dimensions,n=this.model._get_dim_limits(this._draw_basepoint,i,_,o);if(null!=n){const[e,i]=n;this._set_extent(e,i,t,s)}}_doubletap(e){this.model.active&&(null!=this._draw_basepoint?(this._update_box(e,!1,!0),this._draw_basepoint=null):(this._draw_basepoint=[e.sx,e.sy],this._select_event(e,\"append\",this.model.renderers),this._update_box(e,!0,!1)))}_move(e){this._update_box(e,!1,!1)}_pan_start(e){if(e.shiftKey){if(null!=this._draw_basepoint)return;this._draw_basepoint=[e.sx,e.sy],this._update_box(e,!0,!1)}else{if(null!=this._basepoint)return;this._select_event(e,\"append\",this.model.renderers),this._basepoint=[e.sx,e.sy]}}_pan(e,t=!1,s=!1){if(e.shiftKey){if(null==this._draw_basepoint)return;this._update_box(e,t,s)}else{if(null==this._basepoint)return;this._drag_points(e,this.model.renderers)}}_pan_end(e){if(this._pan(e,!1,!0),e.shiftKey)this._draw_basepoint=null;else{this._basepoint=null;for(const e of this.model.renderers)this._emit_cds_changes(e.data_source,!1,!0,!0)}}}s.BoxEditToolView=r,r.__name__=\"BoxEditToolView\";class h extends d.EditTool{constructor(e){super(e),this.tool_name=\"Box Edit Tool\",this.icon=l.tool_icon_box_edit,this.event_type=[\"tap\",\"pan\",\"move\"],this.default_order=1}}s.BoxEditTool=h,o=h,h.__name__=\"BoxEditTool\",o.prototype.default_view=r,o.define((({Int:e})=>({dimensions:[a.Dimensions,\"both\"],num_objects:[e,0]})))},\n function _(e,t,a,s,r){var _;s();const d=e(43),o=e(8),n=e(370),i=e(228);class l extends n.EditToolView{_draw(e,t,a=!1){if(!this.model.active)return;const s=this.model.renderers[0],r=this._map_drag(e.sx,e.sy,s);if(null==r)return;const[_,d]=r,n=s.data_source,i=s.glyph,[l,h]=[i.xs.field,i.ys.field];if(\"new\"==t)this._pop_glyphs(n,this.model.num_objects),l&&n.get_array(l).push([_]),h&&n.get_array(h).push([d]),this._pad_empty_columns(n,[l,h]);else if(\"add\"==t){if(l){const e=n.data[l].length-1;let t=n.get_array(l)[e];(0,o.isArray)(t)||(t=Array.from(t),n.data[l][e]=t),t.push(_)}if(h){const e=n.data[h].length-1;let t=n.get_array(h)[e];(0,o.isArray)(t)||(t=Array.from(t),n.data[h][e]=t),t.push(d)}}this._emit_cds_changes(n,!0,!0,a)}_pan_start(e){this._draw(e,\"new\")}_pan(e){this._draw(e,\"add\")}_pan_end(e){this._draw(e,\"add\",!0)}_tap(e){this._select_event(e,this._select_mode(e),this.model.renderers)}_keyup(e){if(this.model.active&&this._mouse_in_frame)for(const t of this.model.renderers)e.keyCode===d.Keys.Esc?t.data_source.selection_manager.clear():e.keyCode===d.Keys.Backspace&&this._delete_selected(t)}}a.FreehandDrawToolView=l,l.__name__=\"FreehandDrawToolView\";class h extends n.EditTool{constructor(e){super(e),this.tool_name=\"Freehand Draw Tool\",this.icon=i.tool_icon_freehand_draw,this.event_type=[\"pan\",\"tap\"],this.default_order=3}}a.FreehandDrawTool=h,_=h,h.__name__=\"FreehandDrawTool\",_.prototype.default_view=l,_.define((({Int:e})=>({num_objects:[e,0]}))),_.register_alias(\"freehand_draw\",(()=>new h))},\n function _(e,t,s,o,a){var i;o();const n=e(43),_=e(370),r=e(228);class d extends _.EditToolView{_tap(e){if(this._select_event(e,this._select_mode(e),this.model.renderers).length||!this.model.add)return;const t=this.model.renderers[0],s=this._map_drag(e.sx,e.sy,t);if(null==s)return;const o=t.glyph,a=t.data_source,[i,n]=[o.x.field,o.y.field],[_,r]=s;this._pop_glyphs(a,this.model.num_objects),i&&a.get_array(i).push(_),n&&a.get_array(n).push(r),this._pad_empty_columns(a,[i,n]),a.change.emit(),a.data=a.data,a.properties.data.change.emit()}_keyup(e){if(this.model.active&&this._mouse_in_frame)for(const t of this.model.renderers)e.keyCode===n.Keys.Backspace?this._delete_selected(t):e.keyCode==n.Keys.Esc&&t.data_source.selection_manager.clear()}_pan_start(e){this.model.drag&&(this._select_event(e,\"append\",this.model.renderers),this._basepoint=[e.sx,e.sy])}_pan(e){this.model.drag&&null!=this._basepoint&&this._drag_points(e,this.model.renderers)}_pan_end(e){if(this.model.drag){this._pan(e);for(const e of this.model.renderers)this._emit_cds_changes(e.data_source,!1,!0,!0);this._basepoint=null}}}s.PointDrawToolView=d,d.__name__=\"PointDrawToolView\";class l extends _.EditTool{constructor(e){super(e),this.tool_name=\"Point Draw Tool\",this.icon=r.tool_icon_point_draw,this.event_type=[\"tap\",\"pan\",\"move\"],this.default_order=2}}s.PointDrawTool=l,i=l,l.__name__=\"PointDrawTool\",i.prototype.default_view=d,i.define((({Boolean:e,Int:t})=>({add:[e,!0],drag:[e,!0],num_objects:[t,0]})))},\n function _(e,t,s,i,a){var r;i();const o=e(43),n=e(8),d=e(375),_=e(228);class h extends d.PolyToolView{constructor(){super(...arguments),this._drawing=!1,this._initialized=!1}_tap(e){this._drawing?this._draw(e,\"add\",!0):this._select_event(e,this._select_mode(e),this.model.renderers)}_draw(e,t,s=!1){const i=this.model.renderers[0],a=this._map_drag(e.sx,e.sy,i);if(this._initialized||this.activate(),null==a)return;const[r,o]=this._snap_to_vertex(e,...a),d=i.data_source,_=i.glyph,[h,l]=[_.xs.field,_.ys.field];if(\"new\"==t)this._pop_glyphs(d,this.model.num_objects),h&&d.get_array(h).push([r,r]),l&&d.get_array(l).push([o,o]),this._pad_empty_columns(d,[h,l]);else if(\"edit\"==t){if(h){const e=d.data[h][d.data[h].length-1];e[e.length-1]=r}if(l){const e=d.data[l][d.data[l].length-1];e[e.length-1]=o}}else if(\"add\"==t){if(h){const e=d.data[h].length-1;let t=d.get_array(h)[e];const s=t[t.length-1];t[t.length-1]=r,(0,n.isArray)(t)||(t=Array.from(t),d.data[h][e]=t),t.push(s)}if(l){const e=d.data[l].length-1;let t=d.get_array(l)[e];const s=t[t.length-1];t[t.length-1]=o,(0,n.isArray)(t)||(t=Array.from(t),d.data[l][e]=t),t.push(s)}}this._emit_cds_changes(d,!0,!1,s)}_show_vertices(){if(!this.model.active)return;const e=[],t=[];for(let s=0;sthis._show_vertices()))}this._initialized=!0}}deactivate(){this._drawing&&(this._remove(),this._drawing=!1),this.model.vertex_renderer&&this._hide_vertices()}}s.PolyDrawToolView=h,h.__name__=\"PolyDrawToolView\";class l extends d.PolyTool{constructor(e){super(e),this.tool_name=\"Polygon Draw Tool\",this.icon=_.tool_icon_poly_draw,this.event_type=[\"pan\",\"tap\",\"move\"],this.default_order=3}}s.PolyDrawTool=l,r=l,l.__name__=\"PolyDrawTool\",r.prototype.default_view=h,r.define((({Boolean:e,Int:t})=>({drag:[e,!0],num_objects:[t,0]})))},\n function _(e,r,t,s,o){var _;s();const d=e(8),i=e(370);class l extends i.EditToolView{_set_vertices(e,r){const t=this.model.vertex_renderer.glyph,s=this.model.vertex_renderer.data_source,[o,_]=[t.x.field,t.y.field];o&&((0,d.isArray)(e)?s.data[o]=e:t.x={value:e}),_&&((0,d.isArray)(r)?s.data[_]=r:t.y={value:r}),this._emit_cds_changes(s,!0,!0,!1)}_hide_vertices(){this._set_vertices([],[])}_snap_to_vertex(e,r,t){if(this.model.vertex_renderer){const s=this._select_event(e,\"replace\",[this.model.vertex_renderer]),o=this.model.vertex_renderer.data_source,_=this.model.vertex_renderer.glyph,[d,i]=[_.x.field,_.y.field];if(s.length){const e=o.selected.indices[0];d&&(r=o.data[d][e]),i&&(t=o.data[i][e]),o.selection_manager.clear()}}return[r,t]}}t.PolyToolView=l,l.__name__=\"PolyToolView\";class n extends i.EditTool{constructor(e){super(e)}}t.PolyTool=n,_=n,n.__name__=\"PolyTool\",_.define((({AnyRef:e})=>({vertex_renderer:[e()]})))},\n function _(e,t,s,r,i){var _;r();const d=e(43),n=e(8),l=e(375),a=e(228);class c extends l.PolyToolView{constructor(){super(...arguments),this._drawing=!1,this._cur_index=null}_doubletap(e){if(!this.model.active)return;const t=this._map_drag(e.sx,e.sy,this.model.vertex_renderer);if(null==t)return;const[s,r]=t,i=this._select_event(e,\"replace\",[this.model.vertex_renderer]),_=this.model.vertex_renderer.data_source,d=this.model.vertex_renderer.glyph,[n,l]=[d.x.field,d.y.field];if(i.length&&null!=this._selected_renderer){const e=_.selected.indices[0];this._drawing?(this._drawing=!1,_.selection_manager.clear()):(_.selected.indices=[e+1],n&&_.get_array(n).splice(e+1,0,s),l&&_.get_array(l).splice(e+1,0,r),this._drawing=!0),_.change.emit(),this._emit_cds_changes(this._selected_renderer.data_source)}else this._show_vertices(e)}_show_vertices(e){if(!this.model.active)return;const t=this.model.renderers[0],s=()=>this._update_vertices(t),r=null==t?void 0:t.data_source,i=this._select_event(e,\"replace\",this.model.renderers);if(!i.length)return this._set_vertices([],[]),this._selected_renderer=null,this._drawing=!1,this._cur_index=null,void(null!=r&&r.disconnect(r.properties.data.change,s));null!=r&&r.connect(r.properties.data.change,s),this._cur_index=i[0].data_source.selected.indices[0],this._update_vertices(i[0])}_update_vertices(e){const t=e.glyph,s=e.data_source,r=this._cur_index,[i,_]=[t.xs.field,t.ys.field];if(this._drawing)return;if(null==r&&(i||_))return;let d,l;i&&null!=r?(d=s.data[i][r],(0,n.isArray)(d)||(s.data[i][r]=d=Array.from(d))):d=t.xs.value,_&&null!=r?(l=s.data[_][r],(0,n.isArray)(l)||(s.data[_][r]=l=Array.from(l))):l=t.ys.value,this._selected_renderer=e,this._set_vertices(d,l)}_move(e){if(this._drawing&&null!=this._selected_renderer){const t=this.model.vertex_renderer,s=t.data_source,r=t.glyph,i=this._map_drag(e.sx,e.sy,t);if(null==i)return;let[_,d]=i;const n=s.selected.indices;[_,d]=this._snap_to_vertex(e,_,d),s.selected.indices=n;const[l,a]=[r.x.field,r.y.field],c=n[0];l&&(s.data[l][c]=_),a&&(s.data[a][c]=d),s.change.emit(),this._selected_renderer.data_source.change.emit()}}_tap(e){const t=this.model.vertex_renderer,s=this._map_drag(e.sx,e.sy,t);if(null==s)return;if(this._drawing&&this._selected_renderer){let[r,i]=s;const _=t.data_source,d=t.glyph,[n,l]=[d.x.field,d.y.field],a=_.selected.indices;[r,i]=this._snap_to_vertex(e,r,i);const c=a[0];if(_.selected.indices=[c+1],n){const e=_.get_array(n),t=e[c];e[c]=r,e.splice(c+1,0,t)}if(l){const e=_.get_array(l),t=e[c];e[c]=i,e.splice(c+1,0,t)}return _.change.emit(),void this._emit_cds_changes(this._selected_renderer.data_source,!0,!1,!0)}const r=this._select_mode(e);this._select_event(e,r,[t]),this._select_event(e,r,this.model.renderers)}_remove_vertex(){if(!this._drawing||!this._selected_renderer)return;const e=this.model.vertex_renderer,t=e.data_source,s=e.glyph,r=t.selected.indices[0],[i,_]=[s.x.field,s.y.field];i&&t.get_array(i).splice(r,1),_&&t.get_array(_).splice(r,1),t.change.emit(),this._emit_cds_changes(this._selected_renderer.data_source)}_pan_start(e){this._select_event(e,\"append\",[this.model.vertex_renderer]),this._basepoint=[e.sx,e.sy]}_pan(e){null!=this._basepoint&&(this._drag_points(e,[this.model.vertex_renderer]),this._selected_renderer&&this._selected_renderer.data_source.change.emit())}_pan_end(e){null!=this._basepoint&&(this._drag_points(e,[this.model.vertex_renderer]),this._emit_cds_changes(this.model.vertex_renderer.data_source,!1,!0,!0),this._selected_renderer&&this._emit_cds_changes(this._selected_renderer.data_source),this._basepoint=null)}_keyup(e){if(!this.model.active||!this._mouse_in_frame)return;let t;t=this._selected_renderer?[this.model.vertex_renderer]:this.model.renderers;for(const s of t)e.keyCode===d.Keys.Backspace?(this._delete_selected(s),this._selected_renderer&&this._emit_cds_changes(this._selected_renderer.data_source)):e.keyCode==d.Keys.Esc&&(this._drawing?(this._remove_vertex(),this._drawing=!1):this._selected_renderer&&this._hide_vertices(),s.data_source.selection_manager.clear())}deactivate(){this._selected_renderer&&(this._drawing&&(this._remove_vertex(),this._drawing=!1),this._hide_vertices())}}s.PolyEditToolView=c,c.__name__=\"PolyEditToolView\";class o extends l.PolyTool{constructor(e){super(e),this.tool_name=\"Poly Edit Tool\",this.icon=a.tool_icon_poly_edit,this.event_type=[\"tap\",\"pan\",\"move\"],this.default_order=4}}s.PolyEditTool=o,_=o,o.__name__=\"PolyEditTool\",_.prototype.default_view=c},\n function _(e,t,o,s,i){var l;s();const n=e(378),_=e(116),c=e(20),r=e(228);class a extends n.SelectToolView{_compute_limits(e){const t=this.plot_view.frame,o=this.model.dimensions;let s=this._base_point;if(\"center\"==this.model.origin){const[t,o]=s,[i,l]=e;s=[t-(i-t),o-(l-o)]}return this.model._get_dim_limits(s,e,t,o)}_pan_start(e){const{sx:t,sy:o}=e;this._base_point=[t,o]}_pan(e){const{sx:t,sy:o}=e,s=[t,o],[i,l]=this._compute_limits(s);this.model.overlay.update({left:i[0],right:i[1],top:l[0],bottom:l[1]}),this.model.select_every_mousemove&&this._do_select(i,l,!1,this._select_mode(e))}_pan_end(e){const{sx:t,sy:o}=e,s=[t,o],[i,l]=this._compute_limits(s);this._do_select(i,l,!0,this._select_mode(e)),this.model.overlay.update({left:null,right:null,top:null,bottom:null}),this._base_point=null,this.plot_view.state.push(\"box_select\",{selection:this.plot_view.get_selection()})}_do_select([e,t],[o,s],i,l=\"replace\"){const n={type:\"rect\",sx0:e,sx1:t,sy0:o,sy1:s};this._select(n,i,l)}}o.BoxSelectToolView=a,a.__name__=\"BoxSelectToolView\";const h=()=>new _.BoxAnnotation({level:\"overlay\",top_units:\"screen\",left_units:\"screen\",bottom_units:\"screen\",right_units:\"screen\",fill_color:\"lightgrey\",fill_alpha:.5,line_color:\"black\",line_alpha:1,line_width:2,line_dash:[4,4]});class m extends n.SelectTool{constructor(e){super(e),this.tool_name=\"Box Select\",this.icon=r.tool_icon_box_select,this.event_type=\"pan\",this.default_order=30}get tooltip(){return this._get_dim_tooltip(this.dimensions)}}o.BoxSelectTool=m,l=m,m.__name__=\"BoxSelectTool\",l.prototype.default_view=a,l.define((({Boolean:e,Ref:t})=>({dimensions:[c.Dimensions,\"both\"],select_every_mousemove:[e,!1],overlay:[t(_.BoxAnnotation),h],origin:[c.BoxOrigin,\"corner\"]}))),l.register_alias(\"box_select\",(()=>new m)),l.register_alias(\"xbox_select\",(()=>new m({dimensions:\"width\"}))),l.register_alias(\"ybox_select\",(()=>new m({dimensions:\"height\"})))},\n function _(e,t,s,n,r){var o;n();const c=e(223),i=e(175),a=e(339),l=e(176),d=e(66),_=e(20),h=e(43),p=e(251),u=e(15),m=e(11);class v extends c.GestureToolView{connect_signals(){super.connect_signals(),this.model.clear.connect((()=>this._clear()))}get computed_renderers(){const{renderers:e,names:t}=this.model,s=this.plot_model.data_renderers;return(0,d.compute_renderers)(e,s,t)}_computed_renderers_by_data_source(){var e;const t=new Map;for(const s of this.computed_renderers){let n;if(s instanceof i.GlyphRenderer)n=s.data_source;else{if(!(s instanceof a.GraphRenderer))continue;n=s.node_renderer.data_source}const r=null!==(e=t.get(n))&&void 0!==e?e:[];t.set(n,[...r,s])}return t}_select_mode(e){const{shiftKey:t,ctrlKey:s}=e;return t||s?t&&!s?\"append\":!t&&s?\"intersect\":t&&s?\"subtract\":void(0,m.unreachable)():this.model.mode}_keyup(e){e.keyCode==h.Keys.Esc&&this._clear()}_clear(){for(const e of this.computed_renderers)e.get_selection_manager().clear();const e=this.computed_renderers.map((e=>this.plot_view.renderer_view(e)));this.plot_view.request_paint(e)}_select(e,t,s){const n=this._computed_renderers_by_data_source();for(const[,r]of n){const n=r[0].get_selection_manager(),o=[];for(const e of r){const t=this.plot_view.renderer_view(e);null!=t&&o.push(t)}n.select(o,e,t,s)}null!=this.model.callback&&this._emit_callback(e),this._emit_selection_event(e,t)}_emit_selection_event(e,t=!0){const{x_scale:s,y_scale:n}=this.plot_view.frame;let r;switch(e.type){case\"point\":{const{sx:t,sy:o}=e,c=s.invert(t),i=n.invert(o);r=Object.assign(Object.assign({},e),{x:c,y:i});break}case\"span\":{const{sx:t,sy:o}=e,c=s.invert(t),i=n.invert(o);r=Object.assign(Object.assign({},e),{x:c,y:i});break}case\"rect\":{const{sx0:t,sx1:o,sy0:c,sy1:i}=e,[a,l]=s.r_invert(t,o),[d,_]=n.r_invert(c,i);r=Object.assign(Object.assign({},e),{x0:a,y0:d,x1:l,y1:_});break}case\"poly\":{const{sx:t,sy:o}=e,c=s.v_invert(t),i=n.v_invert(o);r=Object.assign(Object.assign({},e),{x:c,y:i});break}}this.plot_model.trigger_event(new p.SelectionGeometry(r,t))}}s.SelectToolView=v,v.__name__=\"SelectToolView\";class b extends c.GestureTool{constructor(e){super(e)}initialize(){super.initialize(),this.clear=new u.Signal0(this,\"clear\")}get menu(){return[{icon:\"bk-tool-icon-replace-mode\",tooltip:\"Replace the current selection\",active:()=>\"replace\"==this.mode,handler:()=>{this.mode=\"replace\",this.active=!0}},{icon:\"bk-tool-icon-append-mode\",tooltip:\"Append to the current selection (Shift)\",active:()=>\"append\"==this.mode,handler:()=>{this.mode=\"append\",this.active=!0}},{icon:\"bk-tool-icon-intersect-mode\",tooltip:\"Intersect with the current selection (Ctrl)\",active:()=>\"intersect\"==this.mode,handler:()=>{this.mode=\"intersect\",this.active=!0}},{icon:\"bk-tool-icon-subtract-mode\",tooltip:\"Subtract from the current selection (Shift+Ctrl)\",active:()=>\"subtract\"==this.mode,handler:()=>{this.mode=\"subtract\",this.active=!0}},null,{icon:\"bk-tool-icon-clear-selection\",tooltip:\"Clear the current selection (Esc)\",handler:()=>{this.clear.emit()}}]}}s.SelectTool=b,o=b,b.__name__=\"SelectTool\",o.define((({String:e,Array:t,Ref:s,Or:n,Auto:r})=>({renderers:[n(t(s(l.DataRenderer)),r),\"auto\"],names:[t(e),[]],mode:[_.SelectionMode,\"replace\"]})))},\n function _(t,o,e,s,i){var n;s();const _=t(223),a=t(116),l=t(20),r=t(228);class h extends _.GestureToolView{_match_aspect(t,o,e){const s=e.bbox.aspect,i=e.bbox.h_range.end,n=e.bbox.h_range.start,_=e.bbox.v_range.end,a=e.bbox.v_range.start;let l=Math.abs(t[0]-o[0]),r=Math.abs(t[1]-o[1]);const h=0==r?0:l/r,[c]=h>=s?[1,h/s]:[s/h,1];let m,p,d,b;return t[0]<=o[0]?(m=t[0],p=t[0]+l*c,p>i&&(p=i)):(p=t[0],m=t[0]-l*c,m_&&(d=_)):(d=t[1],b=t[1]-l/s,bnew a.BoxAnnotation({level:\"overlay\",top_units:\"screen\",left_units:\"screen\",bottom_units:\"screen\",right_units:\"screen\",fill_color:\"lightgrey\",fill_alpha:.5,line_color:\"black\",line_alpha:1,line_width:2,line_dash:[4,4]});class m extends _.GestureTool{constructor(t){super(t),this.tool_name=\"Box Zoom\",this.icon=r.tool_icon_box_zoom,this.event_type=\"pan\",this.default_order=20}get tooltip(){return this._get_dim_tooltip(this.dimensions)}}e.BoxZoomTool=m,n=m,m.__name__=\"BoxZoomTool\",n.prototype.default_view=h,n.define((({Boolean:t,Ref:o})=>({dimensions:[l.Dimensions,\"both\"],overlay:[o(a.BoxAnnotation),c],match_aspect:[t,!1],origin:[l.BoxOrigin,\"corner\"]}))),n.register_alias(\"box_zoom\",(()=>new m({dimensions:\"both\"}))),n.register_alias(\"xbox_zoom\",(()=>new m({dimensions:\"width\"}))),n.register_alias(\"ybox_zoom\",(()=>new m({dimensions:\"height\"})))},\n function _(s,e,t,o,_){var l;o();const i=s(378),a=s(217),c=s(381),n=s(43),h=s(228);class r extends i.SelectToolView{constructor(){super(...arguments),this.sxs=[],this.sys=[]}connect_signals(){super.connect_signals(),this.connect(this.model.properties.active.change,(()=>this._active_change()))}_active_change(){this.model.active||this._clear_overlay()}_keyup(s){s.keyCode==n.Keys.Enter&&this._clear_overlay()}_pan_start(s){this.sxs=[],this.sys=[];const{sx:e,sy:t}=s;this._append_overlay(e,t)}_pan(s){const[e,t]=this.plot_view.frame.bbox.clip(s.sx,s.sy);this._append_overlay(e,t),this.model.select_every_mousemove&&this._do_select(this.sxs,this.sys,!1,this._select_mode(s))}_pan_end(s){const{sxs:e,sys:t}=this;this._clear_overlay(),this._do_select(e,t,!0,this._select_mode(s)),this.plot_view.state.push(\"lasso_select\",{selection:this.plot_view.get_selection()})}_append_overlay(s,e){const{sxs:t,sys:o}=this;t.push(s),o.push(e),this.model.overlay.update({xs:t,ys:o})}_clear_overlay(){this.sxs=[],this.sys=[],this.model.overlay.update({xs:this.sxs,ys:this.sys})}_do_select(s,e,t,o){const _={type:\"poly\",sx:s,sy:e};this._select(_,t,o)}}t.LassoSelectToolView=r,r.__name__=\"LassoSelectToolView\";class y extends i.SelectTool{constructor(s){super(s),this.tool_name=\"Lasso Select\",this.icon=h.tool_icon_lasso_select,this.event_type=\"pan\",this.default_order=12}}t.LassoSelectTool=y,l=y,y.__name__=\"LassoSelectTool\",l.prototype.default_view=r,l.define((({Boolean:s,Ref:e})=>({select_every_mousemove:[s,!0],overlay:[e(a.PolyAnnotation),c.DEFAULT_POLY_OVERLAY]}))),l.register_alias(\"lasso_select\",(()=>new y))},\n function _(e,t,s,l,o){var i;l();const a=e(378),_=e(217),c=e(43),n=e(9),h=e(228);class y extends a.SelectToolView{initialize(){super.initialize(),this.data={sx:[],sy:[]}}connect_signals(){super.connect_signals(),this.connect(this.model.properties.active.change,(()=>this._active_change()))}_active_change(){this.model.active||this._clear_data()}_keyup(e){e.keyCode==c.Keys.Enter&&this._clear_data()}_doubletap(e){this._do_select(this.data.sx,this.data.sy,!0,this._select_mode(e)),this.plot_view.state.push(\"poly_select\",{selection:this.plot_view.get_selection()}),this._clear_data()}_clear_data(){this.data={sx:[],sy:[]},this.model.overlay.update({xs:[],ys:[]})}_tap(e){const{sx:t,sy:s}=e;this.plot_view.frame.bbox.contains(t,s)&&(this.data.sx.push(t),this.data.sy.push(s),this.model.overlay.update({xs:(0,n.copy)(this.data.sx),ys:(0,n.copy)(this.data.sy)}))}_do_select(e,t,s,l){const o={type:\"poly\",sx:e,sy:t};this._select(o,s,l)}}s.PolySelectToolView=y,y.__name__=\"PolySelectToolView\";s.DEFAULT_POLY_OVERLAY=()=>new _.PolyAnnotation({level:\"overlay\",xs_units:\"screen\",ys_units:\"screen\",fill_color:\"lightgrey\",fill_alpha:.5,line_color:\"black\",line_alpha:1,line_width:2,line_dash:[4,4]});class d extends a.SelectTool{constructor(e){super(e),this.tool_name=\"Poly Select\",this.icon=h.tool_icon_polygon_select,this.event_type=\"tap\",this.default_order=11}}s.PolySelectTool=d,i=d,d.__name__=\"PolySelectTool\",i.prototype.default_view=y,i.define((({Ref:e})=>({overlay:[e(_.PolyAnnotation),s.DEFAULT_POLY_OVERLAY]}))),i.register_alias(\"poly_select\",(()=>new d))},\n function _(e,t,s,i,r){var n;i();const _=e(20),d=e(383),o=e(228);class l extends d.LineToolView{constructor(){super(...arguments),this._drawing=!1}_doubletap(e){if(!this.model.active)return;const t=this.model.renderers;for(const s of t){1==this._select_event(e,\"replace\",[s]).length&&(this._selected_renderer=s)}this._show_intersections(),this._update_line_cds()}_show_intersections(){if(!this.model.active)return;if(null==this._selected_renderer)return;if(!this.model.renderers.length)return this._set_intersection([],[]),this._selected_renderer=null,void(this._drawing=!1);const e=this._selected_renderer.data_source,t=this._selected_renderer.glyph,[s,i]=[t.x.field,t.y.field],r=e.get_array(s),n=e.get_array(i);this._set_intersection(r,n)}_tap(e){const t=this.model.intersection_renderer;if(null==this._map_drag(e.sx,e.sy,t))return;if(this._drawing&&this._selected_renderer){const s=this._select_mode(e);if(0==this._select_event(e,s,[t]).length)return}const s=this._select_mode(e);this._select_event(e,s,[t]),this._select_event(e,s,this.model.renderers)}_update_line_cds(){if(null==this._selected_renderer)return;const e=this.model.intersection_renderer.glyph,t=this.model.intersection_renderer.data_source,[s,i]=[e.x.field,e.y.field];if(s&&i){const e=t.data[s],r=t.data[i];this._selected_renderer.data_source.data[s]=e,this._selected_renderer.data_source.data[i]=r}this._emit_cds_changes(this._selected_renderer.data_source,!0,!0,!1)}_pan_start(e){this._select_event(e,\"append\",[this.model.intersection_renderer]),this._basepoint=[e.sx,e.sy]}_pan(e){null!=this._basepoint&&(this._drag_points(e,[this.model.intersection_renderer],this.model.dimensions),this._selected_renderer&&this._selected_renderer.data_source.change.emit())}_pan_end(e){null!=this._basepoint&&(this._drag_points(e,[this.model.intersection_renderer]),this._emit_cds_changes(this.model.intersection_renderer.data_source,!1,!0,!0),this._selected_renderer&&this._emit_cds_changes(this._selected_renderer.data_source),this._basepoint=null)}activate(){this._drawing=!0}deactivate(){this._selected_renderer&&(this._drawing&&(this._drawing=!1),this._hide_intersections())}}s.LineEditToolView=l,l.__name__=\"LineEditToolView\";class h extends d.LineTool{constructor(e){super(e),this.tool_name=\"Line Edit Tool\",this.icon=o.tool_icon_line_edit,this.event_type=[\"tap\",\"pan\",\"move\"],this.default_order=4}get tooltip(){return this._get_dim_tooltip(this.dimensions)}}s.LineEditTool=h,n=h,h.__name__=\"LineEditTool\",n.prototype.default_view=l,n.define((()=>({dimensions:[_.Dimensions,\"both\"]})))},\n function _(e,i,n,t,s){var o;t();const r=e(8),_=e(370);class d extends _.EditToolView{_set_intersection(e,i){const n=this.model.intersection_renderer.glyph,t=this.model.intersection_renderer.data_source,[s,o]=[n.x.field,n.y.field];s&&((0,r.isArray)(e)?t.data[s]=e:n.x={value:e}),o&&((0,r.isArray)(i)?t.data[o]=i:n.y={value:i}),this._emit_cds_changes(t,!0,!0,!1)}_hide_intersections(){this._set_intersection([],[])}}n.LineToolView=d,d.__name__=\"LineToolView\";class a extends _.EditTool{constructor(e){super(e)}}n.LineTool=a,o=a,a.__name__=\"LineTool\",o.define((({AnyRef:e})=>({intersection_renderer:[e()]})))},\n function _(t,s,n,e,i){e();const o=t(1);var a;const _=t(223),l=t(20),r=(0,o.__importStar)(t(228));function h(t,s,n){const e=new Map;for(const[i,o]of t){const[t,a]=o.r_invert(s,n);e.set(i,{start:t,end:a})}return e}n.update_ranges=h;class d extends _.GestureToolView{_pan_start(t){var s;this.last_dx=0,this.last_dy=0;const{sx:n,sy:e}=t,i=this.plot_view.frame.bbox;if(!i.contains(n,e)){const t=i.h_range,s=i.v_range;(nt.end)&&(this.v_axis_only=!0),(es.end)&&(this.h_axis_only=!0)}null===(s=this.model.document)||void 0===s||s.interactive_start(this.plot_model)}_pan(t){var s;this._update(t.deltaX,t.deltaY),null===(s=this.model.document)||void 0===s||s.interactive_start(this.plot_model)}_pan_end(t){this.h_axis_only=!1,this.v_axis_only=!1,null!=this.pan_info&&this.plot_view.state.push(\"pan\",{range:this.pan_info}),this.plot_view.trigger_ranges_update_event()}_update(t,s){const n=this.plot_view.frame,e=t-this.last_dx,i=s-this.last_dy,o=n.bbox.h_range,a=o.start-e,_=o.end-e,l=n.bbox.v_range,r=l.start-i,d=l.end-i,p=this.model.dimensions;let c,u,m,v,x,g;\"width\"!=p&&\"both\"!=p||this.v_axis_only?(c=o.start,u=o.end,m=0):(c=a,u=_,m=-e),\"height\"!=p&&\"both\"!=p||this.h_axis_only?(v=l.start,x=l.end,g=0):(v=r,x=d,g=-i),this.last_dx=t,this.last_dy=s;const{x_scales:w,y_scales:y}=n,f=h(w,c,u),b=h(y,v,x);this.pan_info={xrs:f,yrs:b,sdx:m,sdy:g},this.plot_view.update_range(this.pan_info,{panning:!0})}}n.PanToolView=d,d.__name__=\"PanToolView\";class p extends _.GestureTool{constructor(t){super(t),this.tool_name=\"Pan\",this.event_type=\"pan\",this.default_order=10}get tooltip(){return this._get_dim_tooltip(this.dimensions)}}n.PanTool=p,a=p,p.__name__=\"PanTool\",a.prototype.default_view=d,a.define((()=>({dimensions:[l.Dimensions,\"both\",{on_update(t,s){switch(t){case\"both\":s.icon=r.tool_icon_pan;break;case\"width\":s.icon=r.tool_icon_xpan;break;case\"height\":s.icon=r.tool_icon_ypan}}}]}))),a.register_alias(\"pan\",(()=>new p({dimensions:\"both\"}))),a.register_alias(\"xpan\",(()=>new p({dimensions:\"width\"}))),a.register_alias(\"ypan\",(()=>new p({dimensions:\"height\"})))},\n function _(e,t,i,s,n){var l;s();const a=e(116),r=e(58),o=e(19),_=e(223),h=e(228);function d(e){switch(e){case 1:return 2;case 2:return 1;case 4:return 5;case 5:return 4;default:return e}}function u(e,t,i,s){if(null==t)return!1;const n=i.compute(t);return Math.abs(e-n)n.right)&&(l=!1)}if(null!=n.bottom&&null!=n.top){const e=s.invert(t);(en.top)&&(l=!1)}return l}function g(e,t,i){let s=0;return e>=i.start&&e<=i.end&&(s+=1),t>=i.start&&t<=i.end&&(s+=1),s}function y(e,t,i,s){const n=t.compute(e),l=t.invert(n+i);return l>=s.start&&l<=s.end?l:e}function f(e,t,i){return e>t.start?(t.end=e,i):(t.end=t.start,t.start=e,d(i))}function v(e,t,i){return e=o&&(e.start=a,e.end=r)}i.flip_side=d,i.is_near=u,i.is_inside=c,i.sides_inside=g,i.compute_value=y,i.update_range_end_side=f,i.update_range_start_side=v,i.update_range=m;class p extends _.GestureToolView{initialize(){super.initialize(),this.side=0,this.model.update_overlay_from_ranges()}connect_signals(){super.connect_signals(),null!=this.model.x_range&&this.connect(this.model.x_range.change,(()=>this.model.update_overlay_from_ranges())),null!=this.model.y_range&&this.connect(this.model.y_range.change,(()=>this.model.update_overlay_from_ranges()))}_pan_start(e){this.last_dx=0,this.last_dy=0;const t=this.model.x_range,i=this.model.y_range,{frame:s}=this.plot_view,n=s.x_scale,l=s.y_scale,r=this.model.overlay,{left:o,right:_,top:h,bottom:d}=r,g=this.model.overlay.line_width+a.EDGE_TOLERANCE;null!=t&&this.model.x_interaction&&(u(e.sx,o,n,g)?this.side=1:u(e.sx,_,n,g)?this.side=2:c(e.sx,e.sy,n,l,r)&&(this.side=3)),null!=i&&this.model.y_interaction&&(0==this.side&&u(e.sy,d,l,g)&&(this.side=4),0==this.side&&u(e.sy,h,l,g)?this.side=5:c(e.sx,e.sy,n,l,this.model.overlay)&&(3==this.side?this.side=7:this.side=6))}_pan(e){const t=this.plot_view.frame,i=e.deltaX-this.last_dx,s=e.deltaY-this.last_dy,n=this.model.x_range,l=this.model.y_range,a=t.x_scale,r=t.y_scale;if(null!=n)if(3==this.side||7==this.side)m(n,a,i,t.x_range);else if(1==this.side){const e=y(n.start,a,i,t.x_range);this.side=v(e,n,this.side)}else if(2==this.side){const e=y(n.end,a,i,t.x_range);this.side=f(e,n,this.side)}if(null!=l)if(6==this.side||7==this.side)m(l,r,s,t.y_range);else if(4==this.side){const e=y(l.start,r,s,t.y_range);this.side=v(e,l,this.side)}else if(5==this.side){const e=y(l.end,r,s,t.y_range);this.side=f(e,l,this.side)}this.last_dx=e.deltaX,this.last_dy=e.deltaY}_pan_end(e){this.side=0,this.plot_view.trigger_ranges_update_event()}}i.RangeToolView=p,p.__name__=\"RangeToolView\";const x=()=>new a.BoxAnnotation({level:\"overlay\",fill_color:\"lightgrey\",fill_alpha:.5,line_color:\"black\",line_alpha:1,line_width:.5,line_dash:[2,2]});class w extends _.GestureTool{constructor(e){super(e),this.tool_name=\"Range Tool\",this.icon=h.tool_icon_range,this.event_type=\"pan\",this.default_order=1}initialize(){super.initialize(),this.overlay.in_cursor=\"grab\",this.overlay.ew_cursor=null!=this.x_range&&this.x_interaction?\"ew-resize\":null,this.overlay.ns_cursor=null!=this.y_range&&this.y_interaction?\"ns-resize\":null}update_overlay_from_ranges(){null==this.x_range&&null==this.y_range&&(this.overlay.left=null,this.overlay.right=null,this.overlay.bottom=null,this.overlay.top=null,o.logger.warn(\"RangeTool not configured with any Ranges.\")),null==this.x_range?(this.overlay.left=null,this.overlay.right=null):(this.overlay.left=this.x_range.start,this.overlay.right=this.x_range.end),null==this.y_range?(this.overlay.bottom=null,this.overlay.top=null):(this.overlay.bottom=this.y_range.start,this.overlay.top=this.y_range.end)}}i.RangeTool=w,l=w,w.__name__=\"RangeTool\",l.prototype.default_view=p,l.define((({Boolean:e,Ref:t,Nullable:i})=>({x_range:[i(t(r.Range1d)),null],x_interaction:[e,!0],y_range:[i(t(r.Range1d)),null],y_interaction:[e,!0],overlay:[t(a.BoxAnnotation),x]})))},\n function _(e,t,s,o,i){var l;o();const a=e(378),n=e(20),c=e(228);class _ extends a.SelectToolView{_tap(e){\"tap\"==this.model.gesture&&this._handle_tap(e)}_doubletap(e){\"doubletap\"==this.model.gesture&&this._handle_tap(e)}_handle_tap(e){const{sx:t,sy:s}=e,o={type:\"point\",sx:t,sy:s};this._select(o,!0,this._select_mode(e))}_select(e,t,s){const{callback:o}=this.model;if(\"select\"==this.model.behavior){const i=this._computed_renderers_by_data_source();for(const[,l]of i){const i=l[0].get_selection_manager(),a=l.map((e=>this.plot_view.renderer_view(e))).filter((e=>null!=e));if(i.select(a,e,t,s)&&null!=o){const t=a[0].coordinates.x_scale.invert(e.sx),s=a[0].coordinates.y_scale.invert(e.sy),l={geometries:Object.assign(Object.assign({},e),{x:t,y:s}),source:i.source};o.execute(this.model,l)}}this._emit_selection_event(e),this.plot_view.state.push(\"tap\",{selection:this.plot_view.get_selection()})}else for(const t of this.computed_renderers){const s=this.plot_view.renderer_view(t);if(null==s)continue;const i=t.get_selection_manager();if(i.inspect(s,e)&&null!=o){const t=s.coordinates.x_scale.invert(e.sx),l=s.coordinates.y_scale.invert(e.sy),a={geometries:Object.assign(Object.assign({},e),{x:t,y:l}),source:i.source};o.execute(this.model,a)}}}}s.TapToolView=_,_.__name__=\"TapToolView\";class r extends a.SelectTool{constructor(e){super(e),this.tool_name=\"Tap\",this.icon=c.tool_icon_tap_select,this.event_type=\"tap\",this.default_order=10}}s.TapTool=r,l=r,r.__name__=\"TapTool\",l.prototype.default_view=_,l.define((({Any:e,Enum:t,Nullable:s})=>({behavior:[n.TapBehavior,\"select\"],gesture:[t(\"tap\",\"doubletap\"),\"tap\"],callback:[s(e)]}))),l.register_alias(\"click\",(()=>new r({behavior:\"inspect\"}))),l.register_alias(\"tap\",(()=>new r)),l.register_alias(\"doubletap\",(()=>new r({gesture:\"doubletap\"})))},\n function _(e,t,s,n,i){var a;n();const o=e(223),l=e(20),_=e(228),r=e(384);class h extends o.GestureToolView{_scroll(e){let t=this.model.speed*e.delta;t>.9?t=.9:t<-.9&&(t=-.9),this._update_ranges(t)}_update_ranges(e){var t;const{frame:s}=this.plot_view,n=s.bbox.h_range,i=s.bbox.v_range,[a,o]=[n.start,n.end],[l,_]=[i.start,i.end];let h,d,p,c;switch(this.model.dimension){case\"height\":{const t=Math.abs(_-l);h=a,d=o,p=l-t*e,c=_-t*e;break}case\"width\":{const t=Math.abs(o-a);h=a-t*e,d=o-t*e,p=l,c=_;break}}const{x_scales:g,y_scales:u}=s,w={xrs:(0,r.update_ranges)(g,h,d),yrs:(0,r.update_ranges)(u,p,c),factor:e};this.plot_view.state.push(\"wheel_pan\",{range:w}),this.plot_view.update_range(w,{scrolling:!0}),null===(t=this.model.document)||void 0===t||t.interactive_start(this.plot_model,(()=>this.plot_view.trigger_ranges_update_event()))}}s.WheelPanToolView=h,h.__name__=\"WheelPanToolView\";class d extends o.GestureTool{constructor(e){super(e),this.tool_name=\"Wheel Pan\",this.icon=_.tool_icon_wheel_pan,this.event_type=\"scroll\",this.default_order=12}get tooltip(){return this._get_dim_tooltip(this.dimension)}}s.WheelPanTool=d,a=d,d.__name__=\"WheelPanTool\",a.prototype.default_view=h,a.define((()=>({dimension:[l.Dimension,\"width\"]}))),a.internal((({Number:e})=>({speed:[e,.001]}))),a.register_alias(\"xwheel_pan\",(()=>new d({dimension:\"width\"}))),a.register_alias(\"ywheel_pan\",(()=>new d({dimension:\"height\"})))},\n function _(e,o,t,s,i){var n;s();const l=e(223),_=e(368),h=e(20),a=e(27),r=e(228);class m extends l.GestureToolView{_pinch(e){const{sx:o,sy:t,scale:s,ctrlKey:i,shiftKey:n}=e;let l;l=s>=1?20*(s-1):-20/s,this._scroll({type:\"wheel\",sx:o,sy:t,delta:l,ctrlKey:i,shiftKey:n})}_scroll(e){var o;const{frame:t}=this.plot_view,s=t.bbox.h_range,i=t.bbox.v_range,{sx:n,sy:l}=e,h=this.model.dimensions,a=(\"width\"==h||\"both\"==h)&&s.startthis.plot_view.trigger_ranges_update_event()))}}t.WheelZoomToolView=m,m.__name__=\"WheelZoomToolView\";class d extends l.GestureTool{constructor(e){super(e),this.tool_name=\"Wheel Zoom\",this.icon=r.tool_icon_wheel_zoom,this.event_type=a.is_mobile?\"pinch\":\"scroll\",this.default_order=10}get tooltip(){return this._get_dim_tooltip(this.dimensions)}}t.WheelZoomTool=d,n=d,d.__name__=\"WheelZoomTool\",n.prototype.default_view=m,n.define((({Boolean:e,Number:o})=>({dimensions:[h.Dimensions,\"both\"],maintain_focus:[e,!0],zoom_on_axis:[e,!0],speed:[o,1/600]}))),n.register_alias(\"wheel_zoom\",(()=>new d({dimensions:\"both\"}))),n.register_alias(\"xwheel_zoom\",(()=>new d({dimensions:\"width\"}))),n.register_alias(\"ywheel_zoom\",(()=>new d({dimensions:\"height\"})))},\n function _(i,e,s,t,o){var n;t();const l=i(232),a=i(219),h=i(20),r=i(13),_=i(228);class c extends l.InspectToolView{_move(i){if(!this.model.active)return;const{sx:e,sy:s}=i;this.plot_view.frame.bbox.contains(e,s)?this._update_spans(e,s):this._update_spans(null,null)}_move_exit(i){this._update_spans(null,null)}_update_spans(i,e){const s=this.model.dimensions;\"width\"!=s&&\"both\"!=s||(this.model.spans.width.location=e),\"height\"!=s&&\"both\"!=s||(this.model.spans.height.location=i)}}s.CrosshairToolView=c,c.__name__=\"CrosshairToolView\";class p extends l.InspectTool{constructor(i){super(i),this.tool_name=\"Crosshair\",this.icon=_.tool_icon_crosshair}get tooltip(){return this._get_dim_tooltip(this.dimensions)}get synthetic_renderers(){return(0,r.values)(this.spans)}}s.CrosshairTool=p,n=p,p.__name__=\"CrosshairTool\",(()=>{function i(i,e){return new a.Span({for_hover:!0,dimension:e,location_units:\"screen\",level:\"overlay\",line_color:i.line_color,line_width:i.line_width,line_alpha:i.line_alpha})}n.prototype.default_view=c,n.define((({Alpha:i,Number:e,Color:s})=>({dimensions:[h.Dimensions,\"both\"],line_color:[s,\"black\"],line_width:[e,1],line_alpha:[i,1]}))),n.internal((({Struct:e,Ref:s})=>({spans:[e({width:s(a.Span),height:s(a.Span)}),e=>({width:i(e,\"width\"),height:i(e,\"height\")})]}))),n.register_alias(\"crosshair\",(()=>new p))})()},\n function _(e,s,t,r,n){var o;r();const a=e(53),u=e(13),c=e(34);class i extends a.Model{constructor(e){super(e)}get values(){return(0,u.values)(this.args)}_make_code(e,s,t,r){return new Function(...(0,u.keys)(this.args),e,s,t,(0,c.use_strict)(r))}format(e,s,t){return this._make_code(\"value\",\"format\",\"special_vars\",this.code)(...this.values,e,s,t)}}t.CustomJSHover=i,o=i,i.__name__=\"CustomJSHover\",o.define((({Unknown:e,String:s,Dict:t})=>({args:[t(e),{}],code:[s,\"\"]})))},\n function _(e,t,n,s,i){s();const o=e(1);var r;const l=e(232),a=e(390),c=e(241),_=e(175),d=e(339),p=e(176),h=e(177),u=e(283),m=e(186),y=e(187),f=e(189),x=(0,o.__importStar)(e(185)),v=e(152),w=e(43),g=e(22),b=e(13),k=e(234),C=e(8),S=e(113),T=e(20),$=e(228),R=e(15),A=e(66),M=(0,o.__importStar)(e(242)),V=e(392);function G(e,t,n,s,i,o){const r={x:i[e],y:o[e]},l={x:i[e+1],y:o[e+1]};let a,c;if(\"span\"==t.type)\"h\"==t.direction?(a=Math.abs(r.x-n),c=Math.abs(l.x-n)):(a=Math.abs(r.y-s),c=Math.abs(l.y-s));else{const e={x:n,y:s};a=x.dist_2_pts(r,e),c=x.dist_2_pts(l,e)}return adelete this._template_el)),this.on_change([e,t,n],(async()=>await this._update_ttmodels()))}async _update_ttmodels(){const{_ttmodels:e,computed_renderers:t}=this;e.clear();const{tooltips:n}=this.model;if(null!=n)for(const t of this.computed_renderers){const s=new c.Tooltip({custom:(0,C.isString)(n)||(0,C.isFunction)(n),attachment:this.model.attachment,show_arrow:this.model.show_arrow});t instanceof _.GlyphRenderer?e.set(t,s):t instanceof d.GraphRenderer&&(e.set(t.node_renderer,s),e.set(t.edge_renderer,s))}const s=await(0,S.build_views)(this._ttviews,[...e.values()],{parent:this.plot_view});for(const e of s)e.render();const i=[...function*(){for(const e of t)e instanceof _.GlyphRenderer?yield e:e instanceof d.GraphRenderer&&(yield e.node_renderer,yield e.edge_renderer)}()],o=this._slots.get(this._update);if(null!=o){const e=new Set(i.map((e=>e.data_source)));R.Signal.disconnect_receiver(this,o,e)}for(const e of i)this.connect(e.data_source.inspect,this._update)}get computed_renderers(){const{renderers:e,names:t}=this.model,n=this.plot_model.data_renderers;return(0,A.compute_renderers)(e,n,t)}get ttmodels(){return this._ttmodels}_clear(){this._inspect(1/0,1/0);for(const[,e]of this.ttmodels)e.clear()}_move(e){if(!this.model.active)return;const{sx:t,sy:n}=e;this.plot_view.frame.bbox.contains(t,n)?this._inspect(t,n):this._clear()}_move_exit(){this._clear()}_inspect(e,t){let n;if(\"mouse\"==this.model.mode)n={type:\"point\",sx:e,sy:t};else{n={type:\"span\",direction:\"vline\"==this.model.mode?\"h\":\"v\",sx:e,sy:t}}for(const e of this.computed_renderers){const t=e.get_selection_manager(),s=this.plot_view.renderer_view(e);null!=s&&t.inspect(s,n)}this._emit_callback(n)}_update([e,{geometry:t}]){var n,s;if(!this.model.active)return;if(\"point\"!=t.type&&\"span\"!=t.type)return;if(!(e instanceof _.GlyphRenderer))return;if(\"ignore\"==this.model.muted_policy&&e.muted)return;const i=this.ttmodels.get(e);if(null==i)return;const o=e.get_selection_manager(),r=o.inspectors.get(e),l=e.view.convert_selection_to_subset(r);if(r.is_empty()&&null==r.view)return void i.clear();const a=o.source,c=this.plot_view.renderer_view(e);if(null==c)return;const{sx:d,sy:p}=t,x=c.coordinates.x_scale,v=c.coordinates.y_scale,g=x.invert(d),k=v.invert(p),{glyph:C}=c,S=[];if(C instanceof m.PatchView){const[t,n]=[d,p],s={x:g,y:k,sx:d,sy:p,rx:t,ry:n,name:e.name};S.push([t,n,this._render_tooltips(a,-1,s)])}if(C instanceof y.HAreaView)for(const t of l.line_indices){const n=C._x1,s=C._x2,i=C._y,[o,r]=[d,p],c={index:t,x:g,y:k,sx:d,sy:p,data_x1:n,data_x2:s,data_y:i,rx:o,ry:r,indices:l.line_indices,name:e.name};S.push([o,r,this._render_tooltips(a,t,c)])}if(C instanceof f.VAreaView)for(const t of l.line_indices){const n=C._x,s=C._y1,i=C._y2,[o,r]=[d,p],c={index:t,x:g,y:k,sx:d,sy:p,data_x:n,data_y1:s,data_y2:i,rx:o,ry:r,indices:l.line_indices,name:e.name};S.push([o,r,this._render_tooltips(a,t,c)])}if(C instanceof h.LineView)for(const n of l.line_indices){let s,i,o=C._x[n+1],r=C._y[n+1],c=n;switch(this.model.line_policy){case\"interp\":[o,r]=C.get_interpolation_hit(n,t),s=x.compute(o),i=v.compute(r);break;case\"prev\":[[s,i],c]=H(C.sx,C.sy,n);break;case\"next\":[[s,i],c]=H(C.sx,C.sy,n+1);break;case\"nearest\":[[s,i],c]=G(n,t,d,p,C.sx,C.sy),o=C._x[c],r=C._y[c];break;default:[s,i]=[d,p]}const _={index:c,x:g,y:k,sx:d,sy:p,data_x:o,data_y:r,rx:s,ry:i,indices:l.line_indices,name:e.name};S.push([s,i,this._render_tooltips(a,c,_)])}for(const t of r.image_indices){const n={index:t.index,x:g,y:k,sx:d,sy:p,name:e.name},s=this._render_tooltips(a,t,n);S.push([d,p,s])}for(const i of l.indices)if(C instanceof u.MultiLineView&&!(0,b.isEmpty)(l.multiline_indices))for(const n of l.multiline_indices[i.toString()]){let s,o,r,c=C._xs.get(i)[n],h=C._ys.get(i)[n],u=n;switch(this.model.line_policy){case\"interp\":[c,h]=C.get_interpolation_hit(i,n,t),s=x.compute(c),o=v.compute(h);break;case\"prev\":[[s,o],u]=H(C.sxs.get(i),C.sys.get(i),n);break;case\"next\":[[s,o],u]=H(C.sxs.get(i),C.sys.get(i),n+1);break;case\"nearest\":[[s,o],u]=G(n,t,d,p,C.sxs.get(i),C.sys.get(i)),c=C._xs.get(i)[u],h=C._ys.get(i)[u];break;default:throw new Error(\"shouldn't have happened\")}r=e instanceof _.GlyphRenderer?e.view.convert_indices_from_subset([i])[0]:i;const m={index:r,x:g,y:k,sx:d,sy:p,data_x:c,data_y:h,segment_index:u,indices:l.multiline_indices,name:e.name};S.push([s,o,this._render_tooltips(a,r,m)])}else{const t=null===(n=C._x)||void 0===n?void 0:n[i],o=null===(s=C._y)||void 0===s?void 0:s[i];let r,c,h;if(\"snap_to_data\"==this.model.point_policy){let e=C.get_anchor_point(this.model.anchor,i,[d,p]);if(null==e&&(e=C.get_anchor_point(\"center\",i,[d,p]),null==e))continue;r=e.x,c=e.y}else[r,c]=[d,p];h=e instanceof _.GlyphRenderer?e.view.convert_indices_from_subset([i])[0]:i;const u={index:h,x:g,y:k,sx:d,sy:p,data_x:t,data_y:o,indices:l.indices,name:e.name};S.push([r,c,this._render_tooltips(a,h,u)])}if(0==S.length)i.clear();else{const{content:e}=i;(0,w.empty)(i.content);for(const[,,t]of S)null!=t&&e.appendChild(t);const[t,n]=S[S.length-1];i.setv({position:[t,n]},{check_eq:!1})}}_emit_callback(e){const{callback:t}=this.model;if(null!=t)for(const n of this.computed_renderers){if(!(n instanceof _.GlyphRenderer))continue;const s=this.plot_view.renderer_view(n);if(null==s)continue;const{x_scale:i,y_scale:o}=s.coordinates,r=i.invert(e.sx),l=o.invert(e.sy),a=n.data_source.inspected;t.execute(this.model,{geometry:Object.assign({x:r,y:l},e),renderer:n,index:a})}}_create_template(e){const t=(0,w.div)({style:{display:\"table\",borderSpacing:\"2px\"}});for(const[n]of e){const e=(0,w.div)({style:{display:\"table-row\"}});t.appendChild(e);const s=(0,w.div)({style:{display:\"table-cell\"},class:M.tooltip_row_label},0!=n.length?`${n}: `:\"\");e.appendChild(s);const i=(0,w.span)();i.dataset.value=\"\";const o=(0,w.span)({class:M.tooltip_color_block},\" \");o.dataset.swatch=\"\",(0,w.undisplay)(o);const r=(0,w.div)({style:{display:\"table-cell\"},class:M.tooltip_row_value},i,o);e.appendChild(r)}return t}_render_template(e,t,n,s,i){const o=e.cloneNode(!0),r=o.querySelectorAll(\"[data-value]\"),l=o.querySelectorAll(\"[data-swatch]\"),a=/\\$color(\\[.*\\])?:(\\w*)/,c=/\\$swatch:(\\w*)/;for(const[[,e],o]of(0,k.enumerate)(t)){const t=e.match(c),_=e.match(a);if(null!=t||null!=_){if(null!=t){const[,e]=t,i=n.get_column(e);if(null==i)r[o].textContent=`${e} unknown`;else{const e=(0,C.isNumber)(s)?i[s]:null;null!=e&&(l[o].style.backgroundColor=(0,g.color2css)(e),(0,w.display)(l[o]))}}if(null!=_){const[,e=\"\",t]=_,i=n.get_column(t);if(null==i){r[o].textContent=`${t} unknown`;continue}const a=e.indexOf(\"hex\")>=0,c=e.indexOf(\"swatch\")>=0,d=(0,C.isNumber)(s)?i[s]:null;if(null==d){r[o].textContent=\"(null)\";continue}r[o].textContent=a?(0,g.color2hex)(d):(0,g.color2css)(d),c&&(l[o].style.backgroundColor=(0,g.color2css)(d),(0,w.display)(l[o]))}}else{const t=(0,v.replace_placeholders)(e.replace(\"$~\",\"$data_\"),n,s,this.model.formatters,i);if((0,C.isString)(t))r[o].textContent=t;else for(const e of t)r[o].appendChild(e)}}return o}_render_tooltips(e,t,n){var s;const{tooltips:i}=this.model;if((0,C.isString)(i)){const s=(0,v.replace_placeholders)({html:i},e,t,this.model.formatters,n);return(0,w.div)(s)}if((0,C.isFunction)(i))return i(e,n);if(i instanceof V.Template)return this._template_view.update(e,t,n),this._template_view.el;if(null!=i){const o=null!==(s=this._template_el)&&void 0!==s?s:this._template_el=this._create_template(i);return this._render_template(o,i,e,t,n)}return null}}n.HoverToolView=z,z.__name__=\"HoverToolView\";class P extends l.InspectTool{constructor(e){super(e),this.tool_name=\"Hover\",this.icon=$.tool_icon_hover}}n.HoverTool=P,r=P,P.__name__=\"HoverTool\",r.prototype.default_view=z,r.define((({Any:e,Boolean:t,String:n,Array:s,Tuple:i,Dict:o,Or:r,Ref:l,Function:c,Auto:_,Nullable:d})=>({tooltips:[d(r(l(V.Template),n,s(i(n,n)),c())),[[\"index\",\"$index\"],[\"data (x, y)\",\"($x, $y)\"],[\"screen (x, y)\",\"($sx, $sy)\"]]],formatters:[o(r(l(a.CustomJSHover),v.FormatterType)),{}],renderers:[r(s(l(p.DataRenderer)),_),\"auto\"],names:[s(n),[]],mode:[T.HoverMode,\"mouse\"],muted_policy:[T.MutedPolicy,\"show\"],point_policy:[T.PointPolicy,\"snap_to_data\"],line_policy:[T.LinePolicy,\"nearest\"],show_arrow:[t,!0],anchor:[T.Anchor,\"center\"],attachment:[T.TooltipAttachment,\"horizontal\"],callback:[d(e)]}))),r.register_alias(\"hover\",(()=>new P))},\n function _(e,t,s,n,a){n();const l=e(1);var i,_,o,r,c,d,p,u,m,w,f,h,x;const v=e(53),y=e(309),V=e(393);a(\"Styles\",V.Styles);const g=e(43),T=e(42),b=e(226),R=e(113),D=e(8),M=e(13),S=(0,l.__importStar)(e(242)),O=e(152);class C extends b.DOMView{}s.DOMNodeView=C,C.__name__=\"DOMNodeView\";class z extends v.Model{constructor(e){super(e)}}s.DOMNode=z,z.__name__=\"DOMNode\",z.__module__=\"bokeh.models.dom\";class P extends C{render(){super.render(),this.el.textContent=this.model.content}_createElement(){return document.createTextNode(\"\")}}s.TextView=P,P.__name__=\"TextView\";class A extends z{constructor(e){super(e)}}s.Text=A,i=A,A.__name__=\"Text\",i.prototype.default_view=P,i.define((({String:e})=>({content:[e,\"\"]})));class N extends C{}s.PlaceholderView=N,N.__name__=\"PlaceholderView\",N.tag_name=\"span\";class E extends z{constructor(e){super(e)}}s.Placeholder=E,_=E,E.__name__=\"Placeholder\",_.define((({})=>({})));class G extends N{update(e,t,s){this.el.textContent=t.toString()}}s.IndexView=G,G.__name__=\"IndexView\";class I extends E{constructor(e){super(e)}}s.Index=I,o=I,I.__name__=\"Index\",o.prototype.default_view=G,o.define((({})=>({})));class k extends N{update(e,t,s){const n=(0,O._get_column_value)(this.model.field,e,t),a=null==n?\"???\":`${n}`;this.el.textContent=a}}s.ValueRefView=k,k.__name__=\"ValueRefView\";class $ extends E{constructor(e){super(e)}}s.ValueRef=$,r=$,$.__name__=\"ValueRef\",r.prototype.default_view=k,r.define((({String:e})=>({field:[e]})));class B extends k{render(){super.render(),this.value_el=(0,g.span)(),this.swatch_el=(0,g.span)({class:S.tooltip_color_block},\" \"),this.el.appendChild(this.value_el),this.el.appendChild(this.swatch_el)}update(e,t,s){const n=(0,O._get_column_value)(this.model.field,e,t),a=null==n?\"???\":`${n}`;this.el.textContent=a}}s.ColorRefView=B,B.__name__=\"ColorRefView\";class L extends ${constructor(e){super(e)}}s.ColorRef=L,c=L,L.__name__=\"ColorRef\",c.prototype.default_view=B,c.define((({Boolean:e})=>({hex:[e,!0],swatch:[e,!0]})));class j extends C{constructor(){super(...arguments),this.child_views=new Map}async lazy_initialize(){await super.lazy_initialize();const e=this.model.children.filter((e=>e instanceof v.Model));await(0,R.build_views)(this.child_views,e,{parent:this})}render(){super.render();const{style:e}=this.model;if(null!=e)if(e instanceof V.Styles)for(const t of e){const e=t.get_value();if((0,D.isString)(e)){const s=t.attr.replace(/_/g,\"-\");this.el.style.hasOwnProperty(s)&&this.el.style.setProperty(s,e)}}else for(const[t,s]of(0,M.entries)(e)){const e=t.replace(/_/g,\"-\");this.el.style.hasOwnProperty(e)&&this.el.style.setProperty(e,s)}for(const e of this.model.children)if((0,D.isString)(e)){const t=document.createTextNode(e);this.el.appendChild(t)}else{this.child_views.get(e).renderTo(this.el)}}}s.DOMElementView=j,j.__name__=\"DOMElementView\";class q extends z{constructor(e){super(e)}}s.DOMElement=q,d=q,q.__name__=\"DOMElement\",d.define((({String:e,Array:t,Dict:s,Or:n,Nullable:a,Ref:l})=>({style:[a(n(l(V.Styles),s(e))),null],children:[t(n(e,l(z),l(y.LayoutDOM))),[]]})));class F extends T.View{}s.ActionView=F,F.__name__=\"ActionView\";class H extends v.Model{constructor(e){super(e)}}s.Action=H,p=H,H.__name__=\"Action\",H.__module__=\"bokeh.models.dom\",p.define((({})=>({})));class J extends j{constructor(){super(...arguments),this.action_views=new Map}async lazy_initialize(){await super.lazy_initialize(),await(0,R.build_views)(this.action_views,this.model.actions,{parent:this})}remove(){(0,R.remove_views)(this.action_views),super.remove()}update(e,t,s={}){!function n(a){for(const l of a.child_views.values())l instanceof N?l.update(e,t,s):l instanceof j&&n(l)}(this);for(const n of this.action_views.values())n.update(e,t,s)}}s.TemplateView=J,J.__name__=\"TemplateView\",J.tag_name=\"div\";class K extends q{}s.Template=K,u=K,K.__name__=\"Template\",u.prototype.default_view=J,u.define((({Array:e,Ref:t})=>({actions:[e(t(H)),[]]})));class Q extends j{}s.SpanView=Q,Q.__name__=\"SpanView\",Q.tag_name=\"span\";class U extends q{}s.Span=U,m=U,U.__name__=\"Span\",m.prototype.default_view=Q;class W extends j{}s.DivView=W,W.__name__=\"DivView\",W.tag_name=\"div\";class X extends q{}s.Div=X,w=X,X.__name__=\"Div\",w.prototype.default_view=W;class Y extends j{}s.TableView=Y,Y.__name__=\"TableView\",Y.tag_name=\"table\";class Z extends q{}s.Table=Z,f=Z,Z.__name__=\"Table\",f.prototype.default_view=Y;class ee extends j{}s.TableRowView=ee,ee.__name__=\"TableRowView\",ee.tag_name=\"tr\";class te extends q{}s.TableRow=te,h=te,te.__name__=\"TableRow\",h.prototype.default_view=ee;const se=e(41),ne=e(234);class ae extends F{update(e,t,s){for(const[e,s]of(0,ne.enumerate)(this.model.groups))e.visible=t==s}}s.ToggleGroupView=ae,ae.__name__=\"ToggleGroupView\";class le extends H{constructor(e){super(e)}}s.ToggleGroup=le,x=le,le.__name__=\"ToggleGroup\",x.prototype.default_view=ae,x.define((({Array:e,Ref:t})=>({groups:[e(t(se.RendererGroup)),[]]})))},\n function _(l,n,u,_,e){var t;_();const o=l(53);class r extends o.Model{constructor(l){super(l)}}u.Styles=r,t=r,r.__name__=\"Styles\",r.__module__=\"bokeh.models.css\",t.define((({String:l,Nullable:n})=>({align_content:[n(l),null],align_items:[n(l),null],align_self:[n(l),null],alignment_baseline:[n(l),null],all:[n(l),null],animation:[n(l),null],animation_delay:[n(l),null],animation_direction:[n(l),null],animation_duration:[n(l),null],animation_fill_mode:[n(l),null],animation_iteration_count:[n(l),null],animation_name:[n(l),null],animation_play_state:[n(l),null],animation_timing_function:[n(l),null],backface_visibility:[n(l),null],background:[n(l),null],background_attachment:[n(l),null],background_clip:[n(l),null],background_color:[n(l),null],background_image:[n(l),null],background_origin:[n(l),null],background_position:[n(l),null],background_position_x:[n(l),null],background_position_y:[n(l),null],background_repeat:[n(l),null],background_size:[n(l),null],baseline_shift:[n(l),null],block_size:[n(l),null],border:[n(l),null],border_block_end:[n(l),null],border_block_end_color:[n(l),null],border_block_end_style:[n(l),null],border_block_end_width:[n(l),null],border_block_start:[n(l),null],border_block_start_color:[n(l),null],border_block_start_style:[n(l),null],border_block_start_width:[n(l),null],border_bottom:[n(l),null],border_bottom_color:[n(l),null],border_bottom_left_radius:[n(l),null],border_bottom_right_radius:[n(l),null],border_bottom_style:[n(l),null],border_bottom_width:[n(l),null],border_collapse:[n(l),null],border_color:[n(l),null],border_image:[n(l),null],border_image_outset:[n(l),null],border_image_repeat:[n(l),null],border_image_slice:[n(l),null],border_image_source:[n(l),null],border_image_width:[n(l),null],border_inline_end:[n(l),null],border_inline_end_color:[n(l),null],border_inline_end_style:[n(l),null],border_inline_end_width:[n(l),null],border_inline_start:[n(l),null],border_inline_start_color:[n(l),null],border_inline_start_style:[n(l),null],border_inline_start_width:[n(l),null],border_left:[n(l),null],border_left_color:[n(l),null],border_left_style:[n(l),null],border_left_width:[n(l),null],border_radius:[n(l),null],border_right:[n(l),null],border_right_color:[n(l),null],border_right_style:[n(l),null],border_right_width:[n(l),null],border_spacing:[n(l),null],border_style:[n(l),null],border_top:[n(l),null],border_top_color:[n(l),null],border_top_left_radius:[n(l),null],border_top_right_radius:[n(l),null],border_top_style:[n(l),null],border_top_width:[n(l),null],border_width:[n(l),null],bottom:[n(l),null],box_shadow:[n(l),null],box_sizing:[n(l),null],break_after:[n(l),null],break_before:[n(l),null],break_inside:[n(l),null],caption_side:[n(l),null],caret_color:[n(l),null],clear:[n(l),null],clip:[n(l),null],clip_path:[n(l),null],clip_rule:[n(l),null],color:[n(l),null],color_interpolation:[n(l),null],color_interpolation_filters:[n(l),null],column_count:[n(l),null],column_fill:[n(l),null],column_gap:[n(l),null],column_rule:[n(l),null],column_rule_color:[n(l),null],column_rule_style:[n(l),null],column_rule_width:[n(l),null],column_span:[n(l),null],column_width:[n(l),null],columns:[n(l),null],content:[n(l),null],counter_increment:[n(l),null],counter_reset:[n(l),null],css_float:[n(l),null],css_text:[n(l),null],cursor:[n(l),null],direction:[n(l),null],display:[n(l),null],dominant_baseline:[n(l),null],empty_cells:[n(l),null],fill:[n(l),null],fill_opacity:[n(l),null],fill_rule:[n(l),null],filter:[n(l),null],flex:[n(l),null],flex_basis:[n(l),null],flex_direction:[n(l),null],flex_flow:[n(l),null],flex_grow:[n(l),null],flex_shrink:[n(l),null],flex_wrap:[n(l),null],float:[n(l),null],flood_color:[n(l),null],flood_opacity:[n(l),null],font:[n(l),null],font_family:[n(l),null],font_feature_settings:[n(l),null],font_kerning:[n(l),null],font_size:[n(l),null],font_size_adjust:[n(l),null],font_stretch:[n(l),null],font_style:[n(l),null],font_synthesis:[n(l),null],font_variant:[n(l),null],font_variant_caps:[n(l),null],font_variant_east_asian:[n(l),null],font_variant_ligatures:[n(l),null],font_variant_numeric:[n(l),null],font_variant_position:[n(l),null],font_weight:[n(l),null],gap:[n(l),null],glyph_orientation_vertical:[n(l),null],grid:[n(l),null],grid_area:[n(l),null],grid_auto_columns:[n(l),null],grid_auto_flow:[n(l),null],grid_auto_rows:[n(l),null],grid_column:[n(l),null],grid_column_end:[n(l),null],grid_column_gap:[n(l),null],grid_column_start:[n(l),null],grid_gap:[n(l),null],grid_row:[n(l),null],grid_row_end:[n(l),null],grid_row_gap:[n(l),null],grid_row_start:[n(l),null],grid_template:[n(l),null],grid_template_areas:[n(l),null],grid_template_columns:[n(l),null],grid_template_rows:[n(l),null],height:[n(l),null],hyphens:[n(l),null],image_orientation:[n(l),null],image_rendering:[n(l),null],inline_size:[n(l),null],justify_content:[n(l),null],justify_items:[n(l),null],justify_self:[n(l),null],left:[n(l),null],letter_spacing:[n(l),null],lighting_color:[n(l),null],line_break:[n(l),null],line_height:[n(l),null],list_style:[n(l),null],list_style_image:[n(l),null],list_style_position:[n(l),null],list_style_type:[n(l),null],margin:[n(l),null],margin_block_end:[n(l),null],margin_block_start:[n(l),null],margin_bottom:[n(l),null],margin_inline_end:[n(l),null],margin_inline_start:[n(l),null],margin_left:[n(l),null],margin_right:[n(l),null],margin_top:[n(l),null],marker:[n(l),null],marker_end:[n(l),null],marker_mid:[n(l),null],marker_start:[n(l),null],mask:[n(l),null],mask_composite:[n(l),null],mask_image:[n(l),null],mask_position:[n(l),null],mask_repeat:[n(l),null],mask_size:[n(l),null],mask_type:[n(l),null],max_block_size:[n(l),null],max_height:[n(l),null],max_inline_size:[n(l),null],max_width:[n(l),null],min_block_size:[n(l),null],min_height:[n(l),null],min_inline_size:[n(l),null],min_width:[n(l),null],object_fit:[n(l),null],object_position:[n(l),null],opacity:[n(l),null],order:[n(l),null],orphans:[n(l),null],outline:[n(l),null],outline_color:[n(l),null],outline_offset:[n(l),null],outline_style:[n(l),null],outline_width:[n(l),null],overflow:[n(l),null],overflow_anchor:[n(l),null],overflow_wrap:[n(l),null],overflow_x:[n(l),null],overflow_y:[n(l),null],overscroll_behavior:[n(l),null],overscroll_behavior_block:[n(l),null],overscroll_behavior_inline:[n(l),null],overscroll_behavior_x:[n(l),null],overscroll_behavior_y:[n(l),null],padding:[n(l),null],padding_block_end:[n(l),null],padding_block_start:[n(l),null],padding_bottom:[n(l),null],padding_inline_end:[n(l),null],padding_inline_start:[n(l),null],padding_left:[n(l),null],padding_right:[n(l),null],padding_top:[n(l),null],page_break_after:[n(l),null],page_break_before:[n(l),null],page_break_inside:[n(l),null],paint_order:[n(l),null],perspective:[n(l),null],perspective_origin:[n(l),null],place_content:[n(l),null],place_items:[n(l),null],place_self:[n(l),null],pointer_events:[n(l),null],position:[n(l),null],quotes:[n(l),null],resize:[n(l),null],right:[n(l),null],rotate:[n(l),null],row_gap:[n(l),null],ruby_align:[n(l),null],ruby_position:[n(l),null],scale:[n(l),null],scroll_behavior:[n(l),null],shape_rendering:[n(l),null],stop_color:[n(l),null],stop_opacity:[n(l),null],stroke:[n(l),null],stroke_dasharray:[n(l),null],stroke_dashoffset:[n(l),null],stroke_linecap:[n(l),null],stroke_linejoin:[n(l),null],stroke_miterlimit:[n(l),null],stroke_opacity:[n(l),null],stroke_width:[n(l),null],tab_size:[n(l),null],table_layout:[n(l),null],text_align:[n(l),null],text_align_last:[n(l),null],text_anchor:[n(l),null],text_combine_upright:[n(l),null],text_decoration:[n(l),null],text_decoration_color:[n(l),null],text_decoration_line:[n(l),null],text_decoration_style:[n(l),null],text_emphasis:[n(l),null],text_emphasis_color:[n(l),null],text_emphasis_position:[n(l),null],text_emphasis_style:[n(l),null],text_indent:[n(l),null],text_justify:[n(l),null],text_orientation:[n(l),null],text_overflow:[n(l),null],text_rendering:[n(l),null],text_shadow:[n(l),null],text_transform:[n(l),null],text_underline_position:[n(l),null],top:[n(l),null],touch_action:[n(l),null],transform:[n(l),null],transform_box:[n(l),null],transform_origin:[n(l),null],transform_style:[n(l),null],transition:[n(l),null],transition_delay:[n(l),null],transition_duration:[n(l),null],transition_property:[n(l),null],transition_timing_function:[n(l),null],translate:[n(l),null],unicode_bidi:[n(l),null],user_select:[n(l),null],vertical_align:[n(l),null],visibility:[n(l),null],white_space:[n(l),null],widows:[n(l),null],width:[n(l),null],will_change:[n(l),null],word_break:[n(l),null],word_spacing:[n(l),null],word_wrap:[n(l),null],writing_mode:[n(l),null],z_index:[n(l),null]})))},\n function _(t,o,e,n,s){var i;n();const l=t(15),c=t(53),r=t(224),a=t(232),u=t(234);class h extends c.Model{constructor(t){super(t)}get button_view(){return this.tools[0].button_view}get event_type(){return this.tools[0].event_type}get tooltip(){return this.tools[0].tooltip}get tool_name(){return this.tools[0].tool_name}get icon(){return this.tools[0].computed_icon}get computed_icon(){return this.icon}get toggleable(){const t=this.tools[0];return t instanceof a.InspectTool&&t.toggleable}initialize(){super.initialize(),this.do=new l.Signal0(this,\"do\")}connect_signals(){super.connect_signals(),this.connect(this.do,(()=>this.doit())),this.connect(this.properties.active.change,(()=>this.set_active()));for(const t of this.tools)this.connect(t.properties.active.change,(()=>{this.active=t.active}))}doit(){for(const t of this.tools)t.do.emit()}set_active(){for(const t of this.tools)t.active=this.active}get menu(){const{menu:t}=this.tools[0];if(null==t)return null;const o=[];for(const[e,n]of(0,u.enumerate)(t))if(null==e)o.push(null);else{const t=()=>{var t,o,e;for(const s of this.tools)null===(e=null===(o=null===(t=s.menu)||void 0===t?void 0:t[n])||void 0===o?void 0:o.handler)||void 0===e||e.call(o)};o.push(Object.assign(Object.assign({},e),{handler:t}))}return o}}e.ToolProxy=h,i=h,h.__name__=\"ToolProxy\",i.define((({Boolean:t,Array:o,Ref:e})=>({tools:[o(e(r.ButtonTool)),[]],active:[t,!1],disabled:[t,!1]})))},\n function _(o,t,s,e,i){var n,r;e();const l=o(20),c=o(9),h=o(13),a=o(233),_=o(221),p=o(394),u=o(309),f=o(207);class y extends a.ToolbarBase{constructor(o){super(o)}initialize(){super.initialize(),this._merge_tools()}_merge_tools(){this._proxied_tools=[];const o={},t={},s={},e=[],i=[];for(const o of this.help)(0,c.includes)(i,o.redirect)||(e.push(o),i.push(o.redirect));this._proxied_tools.push(...e),this.help=e;for(const[o,t]of(0,h.entries)(this.gestures)){o in s||(s[o]={});for(const e of t.tools)e.type in s[o]||(s[o][e.type]=[]),s[o][e.type].push(e)}for(const t of this.inspectors)t.type in o||(o[t.type]=[]),o[t.type].push(t);for(const o of this.actions)o.type in t||(t[o.type]=[]),t[o.type].push(o);const n=(o,t=!1)=>{const s=new p.ToolProxy({tools:o,active:t});return this._proxied_tools.push(s),s};for(const o of(0,h.keys)(s)){const t=this.gestures[o];t.tools=[];for(const e of(0,h.keys)(s[o])){const i=s[o][e];if(i.length>0)if(\"multi\"==o)for(const o of i){const s=n([o]);t.tools.push(s),this.connect(s.properties.active.change,(()=>this._active_change(s)))}else{const o=n(i);t.tools.push(o),this.connect(o.properties.active.change,(()=>this._active_change(o)))}}}this.actions=[];for(const[o,s]of(0,h.entries)(t))if(\"CustomAction\"==o)for(const o of s)this.actions.push(n([o]));else s.length>0&&this.actions.push(n(s));this.inspectors=[];for(const t of(0,h.values)(o))t.length>0&&this.inspectors.push(n(t,!0));for(const[o,t]of(0,h.entries)(this.gestures))0!=t.tools.length&&(t.tools=(0,c.sort_by)(t.tools,(o=>o.default_order)),\"pinch\"!=o&&\"scroll\"!=o&&\"multi\"!=o&&(t.tools[0].active=!0))}}s.ProxyToolbar=y,n=y,y.__name__=\"ProxyToolbar\",n.define((({Array:o,Ref:t})=>({toolbars:[o(t(_.Toolbar)),[]]})));class d extends u.LayoutDOMView{initialize(){this.model.toolbar.toolbar_location=this.model.toolbar_location,super.initialize()}get child_models(){return[this.model.toolbar]}_update_layout(){this.layout=new f.ContentBox(this.child_views[0].el);const{toolbar:o}=this.model;o.horizontal?this.layout.set_sizing({width_policy:\"fit\",min_width:100,height_policy:\"fixed\"}):this.layout.set_sizing({width_policy:\"fixed\",height_policy:\"fit\",min_height:100})}after_layout(){super.after_layout();const o=this.child_views[0];o.layout.bbox=this.layout.bbox,o.render()}}s.ToolbarBoxView=d,d.__name__=\"ToolbarBoxView\";class b extends u.LayoutDOM{constructor(o){super(o)}}s.ToolbarBox=b,r=b,b.__name__=\"ToolbarBox\",r.prototype.default_view=d,r.define((({Ref:o})=>({toolbar:[o(a.ToolbarBase)],toolbar_location:[l.Location,\"right\"]})))},\n function _(e,n,r,t,o){t();const s=e(1),u=e(53),c=(0,s.__importStar)(e(21)),a=e(8),l=e(13);r.resolve_defs=function(e,n){var r,t,o,s;function i(e){return null!=e.module?`${e.module}.${e.name}`:e.name}function f(e){if((0,a.isString)(e))switch(e){case\"Any\":return c.Any;case\"Unknown\":return c.Unknown;case\"Boolean\":return c.Boolean;case\"Number\":return c.Number;case\"Int\":return c.Int;case\"String\":return c.String;case\"Null\":return c.Null}else switch(e[0]){case\"Nullable\":{const[,n]=e;return c.Nullable(f(n))}case\"Or\":{const[,...n]=e;return c.Or(...n.map(f))}case\"Tuple\":{const[,n,...r]=e;return c.Tuple(f(n),...r.map(f))}case\"Array\":{const[,n]=e;return c.Array(f(n))}case\"Struct\":{const[,...n]=e,r=n.map((([e,n])=>[e,f(n)]));return c.Struct((0,l.to_object)(r))}case\"Dict\":{const[,n]=e;return c.Dict(f(n))}case\"Map\":{const[,n,r]=e;return c.Map(f(n),f(r))}case\"Enum\":{const[,...n]=e;return c.Enum(...n)}case\"Ref\":{const[,r]=e,t=n.get(i(r));if(null!=t)return c.Ref(t);throw new Error(`${i(r)} wasn't defined before referencing it`)}case\"AnyRef\":return c.AnyRef()}}for(const c of e){const e=(()=>{if(null==c.extends)return u.Model;{const e=n.get(i(c.extends));if(null!=e)return e;throw new Error(`base model ${i(c.extends)} of ${i(c)} is not defined`)}})(),a=((s=class extends e{}).__name__=c.name,s.__module__=c.module,s);for(const e of null!==(r=c.properties)&&void 0!==r?r:[]){const n=f(null!==(t=e.kind)&&void 0!==t?t:\"Unknown\");a.define({[e.name]:[n,e.default]})}for(const e of null!==(o=c.overrides)&&void 0!==o?o:[])a.override({[e.name]:e.default});n.register(a)}}},\n function _(n,e,t,o,i){o();const d=n(5),c=n(226),s=n(113),a=n(43),l=n(398);t.index={},t.add_document_standalone=async function(n,e,o=[],i=!1){const u=new Map;async function f(i){let d;const f=n.roots().indexOf(i),r=o[f];null!=r?d=r:e.classList.contains(l.BOKEH_ROOT)?d=e:(d=(0,a.div)({class:l.BOKEH_ROOT}),e.appendChild(d));const w=await(0,s.build_view)(i,{parent:null});return w instanceof c.DOMView&&w.renderTo(d),u.set(i,w),t.index[i.id]=w,w}for(const e of n.roots())await f(e);return i&&(window.document.title=n.title()),n.on_change((n=>{n instanceof d.RootAddedEvent?f(n.model):n instanceof d.RootRemovedEvent?function(n){const e=u.get(n);null!=e&&(e.remove(),u.delete(n),delete t.index[n.id])}(n.model):i&&n instanceof d.TitleChangedEvent&&(window.document.title=n.title)})),[...u.values()]}},\n function _(o,e,n,t,r){t();const l=o(43),d=o(44);function u(o){let e=document.getElementById(o);if(null==e)throw new Error(`Error rendering Bokeh model: could not find #${o} HTML tag`);if(!document.body.contains(e))throw new Error(`Error rendering Bokeh model: element #${o} must be under `);if(\"SCRIPT\"==e.tagName){const o=(0,l.div)({class:n.BOKEH_ROOT});(0,l.replaceWith)(e,o),e=o}return e}n.BOKEH_ROOT=d.root,n._resolve_element=function(o){const{elementid:e}=o;return null!=e?u(e):document.body},n._resolve_root_elements=function(o){const e=[];if(null!=o.root_ids&&null!=o.roots)for(const n of o.root_ids)e.push(u(o.roots[n]));return e}},\n function _(n,o,t,s,e){s();const c=n(400),r=n(19),a=n(397);t._get_ws_url=function(n,o){let t,s=\"ws:\";return\"https:\"==window.location.protocol&&(s=\"wss:\"),null!=o?(t=document.createElement(\"a\"),t.href=o):t=window.location,null!=n?\"/\"==n&&(n=\"\"):n=t.pathname.replace(/\\/+$/,\"\"),`${s}//${t.host}${n}/ws`};const i={};t.add_document_from_session=async function(n,o,t,s=[],e=!1){const l=window.location.search.substr(1);let d;try{d=await function(n,o,t){const s=(0,c.parse_token)(o).session_id;n in i||(i[n]={});const e=i[n];return s in e||(e[s]=(0,c.pull_session)(n,o,t)),e[s]}(n,o,l)}catch(n){const t=(0,c.parse_token)(o).session_id;throw r.logger.error(`Failed to load Bokeh session ${t}: ${n}`),n}return(0,a.add_document_standalone)(d.document,t,s,e)}},\n function _(e,s,n,t,o){t();const r=e(19),i=e(5),c=e(401),l=e(402),_=e(403);n.DEFAULT_SERVER_WEBSOCKET_URL=\"ws://localhost:5006/ws\",n.DEFAULT_TOKEN=\"eyJzZXNzaW9uX2lkIjogImRlZmF1bHQifQ\";let h=0;function a(e){let s=e.split(\".\")[0];const n=s.length%4;return 0!=n&&(s+=\"=\".repeat(4-n)),JSON.parse(atob(s.replace(/_/g,\"/\").replace(/-/g,\"+\")))}n.parse_token=a;class d{constructor(e=n.DEFAULT_SERVER_WEBSOCKET_URL,s=n.DEFAULT_TOKEN,t=null){this.url=e,this.token=s,this.args_string=t,this._number=h++,this.socket=null,this.session=null,this.closed_permanently=!1,this._current_handler=null,this._pending_replies=new Map,this._pending_messages=[],this._receiver=new l.Receiver,this.id=a(s).session_id.split(\".\")[0],r.logger.debug(`Creating websocket ${this._number} to '${this.url}' session '${this.id}'`)}async connect(){if(this.closed_permanently)throw new Error(\"Cannot connect() a closed ClientConnection\");if(null!=this.socket)throw new Error(\"Already connected\");this._current_handler=null,this._pending_replies.clear(),this._pending_messages=[];try{let e=`${this.url}`;return null!=this.args_string&&this.args_string.length>0&&(e+=`?${this.args_string}`),this.socket=new WebSocket(e,[\"bokeh\",this.token]),new Promise(((e,s)=>{this.socket.binaryType=\"arraybuffer\",this.socket.onopen=()=>this._on_open(e,s),this.socket.onmessage=e=>this._on_message(e),this.socket.onclose=e=>this._on_close(e,s),this.socket.onerror=()=>this._on_error(s)}))}catch(e){throw r.logger.error(`websocket creation failed to url: ${this.url}`),r.logger.error(` - ${e}`),e}}close(){this.closed_permanently||(r.logger.debug(`Permanently closing websocket connection ${this._number}`),this.closed_permanently=!0,null!=this.socket&&this.socket.close(1e3,`close method called on ClientConnection ${this._number}`),this.session._connection_closed())}_schedule_reconnect(e){setTimeout((()=>{this.closed_permanently||r.logger.info(`Websocket connection ${this._number} disconnected, will not attempt to reconnect`)}),e)}send(e){if(null==this.socket)throw new Error(`not connected so cannot send ${e}`);e.send(this.socket)}async send_with_reply(e){const s=await new Promise(((s,n)=>{this._pending_replies.set(e.msgid(),{resolve:s,reject:n}),this.send(e)}));if(\"ERROR\"===s.msgtype())throw new Error(`Error reply ${s.content.text}`);return s}async _pull_doc_json(){const e=c.Message.create(\"PULL-DOC-REQ\",{}),s=await this.send_with_reply(e);if(!(\"doc\"in s.content))throw new Error(\"No 'doc' field in PULL-DOC-REPLY\");return s.content.doc}async _repull_session_doc(e,s){var n;r.logger.debug(this.session?\"Repulling session\":\"Pulling session for first time\");try{const n=await this._pull_doc_json();if(null==this.session)if(this.closed_permanently)r.logger.debug(\"Got new document after connection was already closed\"),s(new Error(\"The connection has been closed\"));else{const s=i.Document.from_json(n),t=i.Document._compute_patch_since_json(n,s);if(t.events.length>0){r.logger.debug(`Sending ${t.events.length} changes from model construction back to server`);const e=c.Message.create(\"PATCH-DOC\",{},t);this.send(e)}this.session=new _.ClientSession(this,s,this.id);for(const e of this._pending_messages)this.session.handle(e);this._pending_messages=[],r.logger.debug(\"Created a new session from new pulled doc\"),e(this.session)}else this.session.document.replace_with_json(n),r.logger.debug(\"Updated existing session with new pulled doc\")}catch(e){null===(n=console.trace)||void 0===n||n.call(console,e),r.logger.error(`Failed to repull session ${e}`),s(e instanceof Error?e:`${e}`)}}_on_open(e,s){r.logger.info(`Websocket connection ${this._number} is now open`),this._current_handler=n=>{this._awaiting_ack_handler(n,e,s)}}_on_message(e){null==this._current_handler&&r.logger.error(\"Got a message with no current handler set\");try{this._receiver.consume(e.data)}catch(e){this._close_bad_protocol(`${e}`)}const s=this._receiver.message;if(null!=s){const e=s.problem();null!=e&&this._close_bad_protocol(e),this._current_handler(s)}}_on_close(e,s){r.logger.info(`Lost websocket ${this._number} connection, ${e.code} (${e.reason})`),this.socket=null,this._pending_replies.forEach((e=>e.reject(\"Disconnected\"))),this._pending_replies.clear(),this.closed_permanently||this._schedule_reconnect(2e3),s(new Error(`Lost websocket connection, ${e.code} (${e.reason})`))}_on_error(e){r.logger.debug(`Websocket error on socket ${this._number}`);const s=\"Could not open websocket\";r.logger.error(`Failed to connect to Bokeh server: ${s}`),e(new Error(s))}_close_bad_protocol(e){r.logger.error(`Closing connection: ${e}`),null!=this.socket&&this.socket.close(1002,e)}_awaiting_ack_handler(e,s,n){\"ACK\"===e.msgtype()?(this._current_handler=e=>this._steady_state_handler(e),this._repull_session_doc(s,n)):this._close_bad_protocol(\"First message was not an ACK\")}_steady_state_handler(e){const s=e.reqid(),n=this._pending_replies.get(s);n?(this._pending_replies.delete(s),n.resolve(e)):this.session?this.session.handle(e):\"PATCH-DOC\"!=e.msgtype()&&this._pending_messages.push(e)}}n.ClientConnection=d,d.__name__=\"ClientConnection\",n.pull_session=function(e,s,n){return new d(e,s,n).connect()}},\n function _(e,s,t,r,n){r();const i=e(34);class a{constructor(e,s,t){this.header=e,this.metadata=s,this.content=t,this.buffers=new Map}static assemble(e,s,t){const r=JSON.parse(e),n=JSON.parse(s),i=JSON.parse(t);return new a(r,n,i)}assemble_buffer(e,s){const t=null!=this.header.num_buffers?this.header.num_buffers:0;if(t<=this.buffers.size)throw new Error(`too many buffers received, expecting ${t}`);const{id:r}=JSON.parse(e);this.buffers.set(r,s)}static create(e,s,t={}){const r=a.create_header(e);return new a(r,s,t)}static create_header(e){return{msgid:(0,i.uniqueId)(),msgtype:e}}complete(){return null!=this.header&&null!=this.metadata&&null!=this.content&&(null==this.header.num_buffers||this.buffers.size==this.header.num_buffers)}send(e){if((null!=this.header.num_buffers?this.header.num_buffers:0)>0)throw new Error(\"BokehJS only supports receiving buffers, not sending\");const s=JSON.stringify(this.header),t=JSON.stringify(this.metadata),r=JSON.stringify(this.content);e.send(s),e.send(t),e.send(r)}msgid(){return this.header.msgid}msgtype(){return this.header.msgtype}reqid(){return this.header.reqid}problem(){return\"msgid\"in this.header?\"msgtype\"in this.header?null:\"No msgtype in header\":\"No msgid in header\"}}t.Message=a,a.__name__=\"Message\"},\n function _(e,t,s,_,r){_();const i=e(401),h=e(8);class a{constructor(){this.message=null,this._partial=null,this._fragments=[],this._buf_header=null,this._current_consumer=this._HEADER}consume(e){this._current_consumer(e)}_HEADER(e){this._assume_text(e),this.message=null,this._partial=null,this._fragments=[e],this._buf_header=null,this._current_consumer=this._METADATA}_METADATA(e){this._assume_text(e),this._fragments.push(e),this._current_consumer=this._CONTENT}_CONTENT(e){this._assume_text(e),this._fragments.push(e);const[t,s,_]=this._fragments.slice(0,3);this._partial=i.Message.assemble(t,s,_),this._check_complete()}_BUFFER_HEADER(e){this._assume_text(e),this._buf_header=e,this._current_consumer=this._BUFFER_PAYLOAD}_BUFFER_PAYLOAD(e){this._assume_binary(e),this._partial.assemble_buffer(this._buf_header,e),this._check_complete()}_assume_text(e){if(!(0,h.isString)(e))throw new Error(\"Expected text fragment but received binary fragment\")}_assume_binary(e){if(!(e instanceof ArrayBuffer))throw new Error(\"Expected binary fragment but received text fragment\")}_check_complete(){this._partial.complete()?(this.message=this._partial,this._current_consumer=this._HEADER):this._current_consumer=this._BUFFER_HEADER}}s.Receiver=a,a.__name__=\"Receiver\"},\n function _(e,t,n,s,o){s();const c=e(5),i=e(401),_=e(19);class r{constructor(e,t,n){this._connection=e,this.document=t,this.id=n,this._document_listener=e=>{this._document_changed(e)},this.document.on_change(this._document_listener,!0)}handle(e){const t=e.msgtype();\"PATCH-DOC\"===t?this._handle_patch(e):\"OK\"===t?this._handle_ok(e):\"ERROR\"===t?this._handle_error(e):_.logger.debug(`Doing nothing with message ${e.msgtype()}`)}close(){this._connection.close()}_connection_closed(){this.document.remove_on_change(this._document_listener)}async request_server_info(){const e=i.Message.create(\"SERVER-INFO-REQ\",{});return(await this._connection.send_with_reply(e)).content}async force_roundtrip(){await this.request_server_info()}_document_changed(e){if(e.setter_id===this.id)return;const t=e instanceof c.DocumentEventBatch?e.events:[e],n=this.document.create_json_patch(t),s=i.Message.create(\"PATCH-DOC\",{},n);this._connection.send(s)}_handle_patch(e){this.document.apply_json_patch(e.content,e.buffers,this.id)}_handle_ok(e){_.logger.trace(`Unhandled OK reply to ${e.reqid()}`)}_handle_error(e){_.logger.error(`Unhandled ERROR reply to ${e.reqid()}: ${e.content.text}`)}}n.ClientSession=r,r.__name__=\"ClientSession\"},\n function _(e,o,t,n,r){n();const s=e(1),l=e(5),i=e(402),a=e(19),c=e(43),g=e(13),f=e(397),u=e(398),m=(0,s.__importDefault)(e(44)),p=(0,s.__importDefault)(e(240)),d=(0,s.__importDefault)(e(405));function _(e,o){o.buffers.length>0?e.consume(o.buffers[0].buffer):e.consume(o.content.data);const t=e.message;null!=t&&this.apply_json_patch(t.content,t.buffers)}function b(e,o){if(\"undefined\"!=typeof Jupyter&&null!=Jupyter.notebook.kernel){a.logger.info(`Registering Jupyter comms for target ${e}`);const t=Jupyter.notebook.kernel.comm_manager;try{t.register_target(e,(t=>{a.logger.info(`Registering Jupyter comms for target ${e}`);const n=new i.Receiver;t.on_msg(_.bind(o,n))}))}catch(e){a.logger.warn(`Jupyter comms failed to register. push_notebook() will not function. (exception reported: ${e})`)}}else if(o.roots()[0].id in t.kernels){a.logger.info(`Registering JupyterLab comms for target ${e}`);const n=t.kernels[o.roots()[0].id];try{n.registerCommTarget(e,(t=>{a.logger.info(`Registering JupyterLab comms for target ${e}`);const n=new i.Receiver;t.onMsg=_.bind(o,n)}))}catch(e){a.logger.warn(`Jupyter comms failed to register. push_notebook() will not function. (exception reported: ${e})`)}}else if(\"undefined\"!=typeof google&&null!=google.colab.kernel){a.logger.info(`Registering Google Colab comms for target ${e}`);const t=google.colab.kernel.comms;try{t.registerTarget(e,(async t=>{var n,r,l;a.logger.info(`Registering Google Colab comms for target ${e}`);const c=new i.Receiver;try{for(var g,f=(0,s.__asyncValues)(t.messages);!(g=await f.next()).done;){const e=g.value,t={data:e.data},n=[];for(const o of null!==(l=e.buffers)&&void 0!==l?l:[])n.push(new DataView(o));const r={content:t,buffers:n};_.bind(o)(c,r)}}catch(e){n={error:e}}finally{try{g&&!g.done&&(r=f.return)&&await r.call(f)}finally{if(n)throw n.error}}}))}catch(e){a.logger.warn(`Google Colab comms failed to register. push_notebook() will not function. (exception reported: ${e})`)}}else console.warn(\"Jupyter notebooks comms not available. push_notebook() will not function. If running JupyterLab ensure the latest @bokeh/jupyter_bokeh extension is installed. In an exported notebook this warning is expected.\")}c.stylesheet.append(m.default),c.stylesheet.append(p.default),c.stylesheet.append(d.default),t.kernels={},t.embed_items_notebook=function(e,o){if(1!=(0,g.size)(e))throw new Error(\"embed_items_notebook expects exactly one document in docs_json\");const t=l.Document.from_json((0,g.values)(e)[0]);for(const e of o){null!=e.notebook_comms_target&&b(e.notebook_comms_target,t);const o=(0,u._resolve_element)(e),n=(0,u._resolve_root_elements)(e);(0,f.add_document_standalone)(t,o,n)}}},\n function _(t,o,r,e,d){e(),r.root=\"bk-root\",r.tooltip=\"bk-tooltip\",r.default=\".rendered_html .bk-root .bk-tooltip table,.rendered_html .bk-root .bk-tooltip tr,.rendered_html .bk-root .bk-tooltip th,.rendered_html .bk-root .bk-tooltip td{border:none;padding:1px;}\"},\n function _(t,_,o,r,n){r();const a=t(1);(0,a.__exportStar)(t(401),o),(0,a.__exportStar)(t(402),o)},\n function _(e,t,n,s,o){function l(){const e=document.getElementsByTagName(\"body\")[0],t=document.getElementsByClassName(\"bokeh-test-div\");1==t.length&&(e.removeChild(t[0]),delete t[0]);const n=document.createElement(\"div\");n.classList.add(\"bokeh-test-div\"),n.style.display=\"none\",e.insertBefore(n,e.firstChild)}s(),n.results={},n.init=function(){l()},n.record0=function(e,t){n.results[e]=t},n.record=function(e,t){n.results[e]=t,l()},n.count=function(e){null==n.results[e]&&(n.results[e]=0),n.results[e]+=1,l()}},\n function _(e,t,o,n,l){n(),o.safely=function(e,t=!1){try{return e()}catch(e){if(function(e){const t=document.createElement(\"div\");t.style.backgroundColor=\"#f2dede\",t.style.border=\"1px solid #a94442\",t.style.borderRadius=\"4px\",t.style.display=\"inline-block\",t.style.fontFamily=\"sans-serif\",t.style.marginTop=\"5px\",t.style.minWidth=\"200px\",t.style.padding=\"5px 5px 5px 10px\",t.classList.add(\"bokeh-error-box-into-flames\");const o=document.createElement(\"span\");o.style.backgroundColor=\"#a94442\",o.style.borderRadius=\"0px 4px 0px 0px\",o.style.color=\"white\",o.style.cursor=\"pointer\",o.style.cssFloat=\"right\",o.style.fontSize=\"0.8em\",o.style.margin=\"-6px -6px 0px 0px\",o.style.padding=\"2px 5px 4px 5px\",o.title=\"close\",o.setAttribute(\"aria-label\",\"close\"),o.appendChild(document.createTextNode(\"x\")),o.addEventListener(\"click\",(()=>s.removeChild(t)));const n=document.createElement(\"h3\");n.style.color=\"#a94442\",n.style.margin=\"8px 0px 0px 0px\",n.style.padding=\"0px\",n.appendChild(document.createTextNode(\"Bokeh Error\"));const l=document.createElement(\"pre\");l.style.whiteSpace=\"unset\",l.style.overflowX=\"auto\",l.appendChild(document.createTextNode(e)),t.appendChild(o),t.appendChild(n),t.appendChild(l);const s=document.getElementsByTagName(\"body\")[0];s.insertBefore(t,s.firstChild)}(e instanceof Error&&e.stack?e.stack:`${e}`),t)return;throw e}}},\n ], 0, {\"main\":0,\"tslib\":1,\"index\":2,\"version\":3,\"embed/index\":4,\"document/index\":5,\"document/document\":6,\"base\":7,\"core/util/types\":8,\"core/util/array\":9,\"core/util/math\":10,\"core/util/assert\":11,\"core/util/arrayable\":12,\"core/util/object\":13,\"core/has_props\":14,\"core/signaling\":15,\"core/util/defer\":16,\"core/util/refs\":17,\"core/properties\":18,\"core/logging\":19,\"core/enums\":20,\"core/kinds\":21,\"core/util/color\":22,\"core/util/svg_colors\":23,\"core/types\":24,\"core/util/bitset\":25,\"core/util/eq\":26,\"core/util/platform\":27,\"core/settings\":28,\"core/util/ndarray\":29,\"core/serializer\":30,\"core/util/serialization\":31,\"core/util/buffer\":32,\"core/uniforms\":33,\"core/util/string\":34,\"document/events\":35,\"core/util/pretty\":36,\"core/util/cloneable\":37,\"models/index\":38,\"models/annotations/index\":39,\"models/annotations/annotation\":40,\"models/renderers/renderer\":41,\"core/view\":42,\"core/dom\":43,\"styles/root.css\":44,\"core/visuals/index\":45,\"core/visuals/line\":46,\"core/visuals/visual\":47,\"core/property_mixins\":48,\"core/visuals/fill\":49,\"core/visuals/text\":50,\"core/visuals/hatch\":51,\"core/visuals/patterns\":52,\"model\":53,\"models/canvas/coordinates\":54,\"models/scales/scale\":55,\"models/transforms/transform\":56,\"models/ranges/range\":57,\"models/ranges/range1d\":58,\"models/scales/linear_scale\":59,\"models/scales/continuous_scale\":60,\"models/scales/log_scale\":61,\"models/scales/categorical_scale\":62,\"models/ranges/data_range1d\":63,\"models/ranges/data_range\":64,\"core/util/bbox\":65,\"models/util\":66,\"models/ranges/factor_range\":67,\"models/annotations/arrow\":68,\"models/annotations/data_annotation\":69,\"models/sources/columnar_data_source\":70,\"models/sources/data_source\":71,\"models/selections/selection\":72,\"core/selection_manager\":73,\"models/selections/interaction_policy\":74,\"models/sources/column_data_source\":75,\"core/util/typed_array\":76,\"core/util/set\":77,\"core/util/projections\":78,\"models/annotations/arrow_head\":112,\"core/build_views\":113,\"models/annotations/band\":114,\"models/annotations/upper_lower\":115,\"models/annotations/box_annotation\":116,\"models/annotations/color_bar\":117,\"models/annotations/title\":118,\"models/annotations/text_annotation\":119,\"core/graphics\":120,\"core/util/text\":121,\"core/util/affine\":122,\"core/layout/side_panel\":123,\"core/layout/types\":124,\"core/layout/layoutable\":125,\"models/canvas/cartesian_frame\":126,\"models/axes/index\":127,\"models/axes/axis\":128,\"models/renderers/guide_renderer\":129,\"models/tickers/ticker\":130,\"models/formatters/tick_formatter\":131,\"models/policies/labeling\":132,\"models/text/base_text\":133,\"models/text/utils\":134,\"models/text/math_text\":135,\"core/util/image\":136,\"models/text/providers\":137,\"core/util/modules\":138,\"models/text/plain_text\":139,\"models/axes/categorical_axis\":140,\"models/tickers/categorical_ticker\":141,\"models/formatters/categorical_tick_formatter\":142,\"models/axes/continuous_axis\":143,\"models/axes/datetime_axis\":144,\"models/axes/linear_axis\":145,\"models/formatters/basic_tick_formatter\":146,\"models/tickers/basic_ticker\":147,\"models/tickers/adaptive_ticker\":148,\"models/tickers/continuous_ticker\":149,\"models/formatters/datetime_tick_formatter\":150,\"core/util/templating\":152,\"models/tickers/datetime_ticker\":155,\"models/tickers/composite_ticker\":156,\"models/tickers/days_ticker\":157,\"models/tickers/single_interval_ticker\":158,\"models/tickers/util\":159,\"models/tickers/months_ticker\":160,\"models/tickers/years_ticker\":161,\"models/axes/log_axis\":162,\"models/formatters/log_tick_formatter\":163,\"models/tickers/log_ticker\":164,\"models/axes/mercator_axis\":165,\"models/formatters/mercator_tick_formatter\":166,\"models/tickers/mercator_ticker\":167,\"models/tickers/index\":168,\"models/tickers/fixed_ticker\":169,\"models/tickers/binned_ticker\":170,\"models/mappers/scanning_color_mapper\":171,\"models/mappers/continuous_color_mapper\":172,\"models/mappers/color_mapper\":173,\"models/mappers/mapper\":174,\"models/renderers/glyph_renderer\":175,\"models/renderers/data_renderer\":176,\"models/glyphs/line\":177,\"models/glyphs/xy_glyph\":178,\"models/glyphs/glyph\":179,\"core/util/ragged_array\":180,\"core/util/spatial\":181,\"models/glyphs/utils\":184,\"core/hittest\":185,\"models/glyphs/patch\":186,\"models/glyphs/harea\":187,\"models/glyphs/area\":188,\"models/glyphs/varea\":189,\"models/sources/cds_view\":190,\"models/filters/filter\":191,\"models/formatters/index\":192,\"models/formatters/func_tick_formatter\":193,\"models/formatters/numeral_tick_formatter\":194,\"models/formatters/printf_tick_formatter\":195,\"models/mappers/index\":196,\"models/mappers/categorical_color_mapper\":197,\"models/mappers/categorical_mapper\":198,\"models/mappers/categorical_marker_mapper\":199,\"models/mappers/categorical_pattern_mapper\":200,\"models/mappers/linear_color_mapper\":201,\"models/mappers/log_color_mapper\":202,\"models/mappers/eqhist_color_mapper\":203,\"models/scales/index\":204,\"models/scales/linear_interpolation_scale\":205,\"models/ranges/index\":206,\"core/layout/index\":207,\"core/layout/alignments\":208,\"core/layout/grid\":209,\"core/layout/html\":210,\"core/layout/border\":211,\"models/annotations/label\":212,\"models/annotations/label_set\":213,\"models/annotations/legend\":214,\"models/annotations/legend_item\":215,\"core/vectorization\":216,\"models/annotations/poly_annotation\":217,\"models/annotations/slope\":218,\"models/annotations/span\":219,\"models/annotations/toolbar_panel\":220,\"models/tools/toolbar\":221,\"models/tools/tool\":222,\"models/tools/gestures/gesture_tool\":223,\"models/tools/button_tool\":224,\"core/dom_view\":226,\"styles/toolbar.css\":227,\"styles/icons.css\":228,\"styles/menus.css\":229,\"core/util/menus\":230,\"models/tools/on_off_button\":231,\"models/tools/inspectors/inspect_tool\":232,\"models/tools/toolbar_base\":233,\"core/util/iterator\":234,\"core/util/canvas\":235,\"core/util/svg\":236,\"core/util/random\":237,\"models/tools/actions/action_tool\":238,\"models/tools/actions/help_tool\":239,\"styles/logo.css\":240,\"models/annotations/tooltip\":241,\"styles/tooltips.css\":242,\"models/annotations/whisker\":243,\"models/callbacks/index\":244,\"models/callbacks/customjs\":245,\"models/callbacks/callback\":246,\"models/callbacks/open_url\":247,\"models/canvas/index\":248,\"models/canvas/canvas\":249,\"core/ui_events\":250,\"core/bokeh_events\":251,\"core/util/wheel\":252,\"models/expressions/index\":253,\"models/expressions/expression\":254,\"models/expressions/customjs_expr\":255,\"models/expressions/stack\":256,\"models/expressions/cumsum\":257,\"models/expressions/minimum\":258,\"models/expressions/maximum\":259,\"models/expressions/coordinate_transform\":260,\"models/expressions/polar\":261,\"models/filters/index\":262,\"models/filters/boolean_filter\":263,\"models/filters/customjs_filter\":264,\"models/filters/group_filter\":265,\"models/filters/index_filter\":266,\"models/glyphs/index\":267,\"models/glyphs/annular_wedge\":268,\"models/glyphs/annulus\":269,\"models/glyphs/arc\":270,\"models/glyphs/bezier\":271,\"models/glyphs/circle\":272,\"models/glyphs/ellipse\":273,\"models/glyphs/ellipse_oval\":274,\"models/glyphs/center_rotatable\":275,\"models/glyphs/hbar\":276,\"models/glyphs/box\":277,\"models/glyphs/hex_tile\":278,\"models/glyphs/image\":279,\"models/glyphs/image_base\":280,\"models/glyphs/image_rgba\":281,\"models/glyphs/image_url\":282,\"models/glyphs/multi_line\":283,\"models/glyphs/multi_polygons\":284,\"models/glyphs/oval\":285,\"models/glyphs/patches\":286,\"models/glyphs/quad\":287,\"models/glyphs/quadratic\":288,\"models/glyphs/ray\":289,\"models/glyphs/rect\":290,\"models/glyphs/scatter\":291,\"models/glyphs/marker\":292,\"models/glyphs/defs\":293,\"models/glyphs/segment\":294,\"models/glyphs/spline\":295,\"core/util/interpolation\":296,\"models/glyphs/step\":297,\"models/glyphs/text\":298,\"models/glyphs/vbar\":299,\"models/glyphs/wedge\":300,\"models/graphs/index\":301,\"models/graphs/graph_hit_test_policy\":302,\"models/graphs/layout_provider\":303,\"models/graphs/static_layout_provider\":304,\"models/grids/index\":305,\"models/grids/grid\":306,\"models/layouts/index\":307,\"models/layouts/box\":308,\"models/layouts/layout_dom\":309,\"models/layouts/column\":310,\"models/layouts/grid_box\":311,\"models/layouts/html_box\":312,\"models/layouts/panel\":313,\"models/layouts/row\":314,\"models/layouts/spacer\":315,\"models/layouts/tabs\":316,\"styles/tabs.css\":317,\"styles/buttons.css\":318,\"models/layouts/widget_box\":319,\"models/text/index\":320,\"models/transforms/index\":321,\"models/transforms/customjs_transform\":322,\"models/transforms/dodge\":323,\"models/transforms/range_transform\":324,\"models/transforms/interpolator\":325,\"models/transforms/jitter\":326,\"models/transforms/linear_interpolator\":327,\"models/transforms/step_interpolator\":328,\"models/plots/index\":329,\"models/plots/gmap_plot\":330,\"models/plots/plot\":331,\"models/plots/plot_canvas\":332,\"core/util/throttle\":333,\"models/plots/range_manager\":334,\"models/plots/state_manager\":335,\"models/plots/gmap_plot_canvas\":336,\"models/policies/index\":337,\"models/renderers/index\":338,\"models/renderers/graph_renderer\":339,\"models/selections/index\":340,\"models/sources/index\":341,\"models/sources/server_sent_data_source\":342,\"models/sources/web_data_source\":343,\"models/sources/ajax_data_source\":344,\"models/sources/geojson_data_source\":345,\"models/tiles/index\":346,\"models/tiles/bbox_tile_source\":347,\"models/tiles/mercator_tile_source\":348,\"models/tiles/tile_source\":349,\"models/tiles/tile_utils\":350,\"models/tiles/quadkey_tile_source\":351,\"models/tiles/tile_renderer\":352,\"models/tiles/wmts_tile_source\":353,\"styles/tiles.css\":354,\"models/tiles/tms_tile_source\":355,\"models/textures/index\":356,\"models/textures/canvas_texture\":357,\"models/textures/texture\":358,\"models/textures/image_url_texture\":359,\"models/tools/index\":360,\"models/tools/actions/custom_action\":361,\"models/tools/actions/redo_tool\":362,\"models/tools/actions/reset_tool\":363,\"models/tools/actions/save_tool\":364,\"models/tools/actions/undo_tool\":365,\"models/tools/actions/zoom_in_tool\":366,\"models/tools/actions/zoom_base_tool\":367,\"core/util/zoom\":368,\"models/tools/actions/zoom_out_tool\":369,\"models/tools/edit/edit_tool\":370,\"models/tools/edit/box_edit_tool\":371,\"models/tools/edit/freehand_draw_tool\":372,\"models/tools/edit/point_draw_tool\":373,\"models/tools/edit/poly_draw_tool\":374,\"models/tools/edit/poly_tool\":375,\"models/tools/edit/poly_edit_tool\":376,\"models/tools/gestures/box_select_tool\":377,\"models/tools/gestures/select_tool\":378,\"models/tools/gestures/box_zoom_tool\":379,\"models/tools/gestures/lasso_select_tool\":380,\"models/tools/gestures/poly_select_tool\":381,\"models/tools/edit/line_edit_tool\":382,\"models/tools/edit/line_tool\":383,\"models/tools/gestures/pan_tool\":384,\"models/tools/gestures/range_tool\":385,\"models/tools/gestures/tap_tool\":386,\"models/tools/gestures/wheel_pan_tool\":387,\"models/tools/gestures/wheel_zoom_tool\":388,\"models/tools/inspectors/crosshair_tool\":389,\"models/tools/inspectors/customjs_hover\":390,\"models/tools/inspectors/hover_tool\":391,\"models/dom/index\":392,\"models/dom/styles\":393,\"models/tools/tool_proxy\":394,\"models/tools/toolbar_box\":395,\"document/defs\":396,\"embed/standalone\":397,\"embed/dom\":398,\"embed/server\":399,\"client/connection\":400,\"protocol/message\":401,\"protocol/receiver\":402,\"client/session\":403,\"embed/notebook\":404,\"styles/notebook.css\":405,\"protocol/index\":406,\"testing\":407,\"safely\":408}, {});});\n\n /* END bokeh.min.js */\n },\n function(Bokeh) {\n /* BEGIN bokeh-gl.min.js */\n /*!\n * Copyright (c) 2012 - 2022, Anaconda, Inc., and Bokeh Contributors\n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n * \n * Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n * \n * Neither the name of Anaconda nor the names of any contributors\n * may be used to endorse or promote products derived from this software\n * without specific prior written permission.\n * \n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n * THE POSSIBILITY OF SUCH DAMAGE.\n */\n (function(root, factory) {\n factory(root[\"Bokeh\"], \"2.4.3\");\n })(this, function(Bokeh, version) {\n let define;\n return (function(modules, entry, aliases, externals) {\n const bokeh = typeof Bokeh !== \"undefined\" && (version != null ? Bokeh[version] : Bokeh);\n if (bokeh != null) {\n return bokeh.register_plugin(modules, entry, aliases);\n } else {\n throw new Error(\"Cannot find Bokeh \" + version + \". You have to load it prior to loading plugins.\");\n }\n })\n ({\n 409: function _(n,c,f,i,o){i(),n(410)},\n 410: function _(t,_,r,e,o){e();const a=t(1);o(\"get_regl\",t(411).get_regl),(0,a.__exportStar)(t(419),r),(0,a.__exportStar)(t(423),r),(0,a.__exportStar)(t(425),r),(0,a.__exportStar)(t(426),r),(0,a.__exportStar)(t(427),r),(0,a.__exportStar)(t(428),r),(0,a.__exportStar)(t(429),r),(0,a.__exportStar)(t(424),r)},\n 411: function _(t,i,e,_,a){_();const r=t(1),o=(0,r.__importDefault)(t(412)),n=t(413),s=(0,r.__importDefault)(t(415)),l=(0,r.__importDefault)(t(416)),p=(0,r.__importDefault)(t(417)),h=(0,r.__importDefault)(t(418));let c;e.get_regl=function(t){return null==c&&(c=new u(t)),c};class u{constructor(t){try{this._regl=(0,o.default)({gl:t,extensions:[\"ANGLE_instanced_arrays\",\"EXT_blend_minmax\"]}),this._regl_available=!0,this._line_geometry=this._regl.buffer({usage:\"static\",type:\"float\",data:[[-2,0],[-1,-1],[1,-1],[2,0],[1,1],[-1,1]]}),this._line_triangles=this._regl.elements({usage:\"static\",primitive:\"triangles\",data:[[0,1,5],[1,2,5],[5,2,4],[2,3,4]]})}catch(t){this._regl_available=!1}}buffer(t){return this._regl.buffer(t)}clear(t,i){this._viewport={x:0,y:0,width:t,height:i},this._regl.clear({color:[0,0,0,0]})}get has_webgl(){return this._regl_available}get scissor(){return this._scissor}set_scissor(t,i,e,_){this._scissor={x:t,y:i,width:e,height:_}}get viewport(){return this._viewport}dashed_line(){return null==this._dashed_line&&(this._dashed_line=function(t,i,e){const _={vert:`#define DASHED\\n\\n${s.default}`,frag:`#define DASHED\\n\\n${l.default}`,attributes:{a_position:{buffer:i,divisor:0},a_point_prev:(t,i)=>i.points.to_attribute_config(),a_point_start:(t,i)=>i.points.to_attribute_config(2*Float32Array.BYTES_PER_ELEMENT),a_point_end:(t,i)=>i.points.to_attribute_config(4*Float32Array.BYTES_PER_ELEMENT),a_point_next:(t,i)=>i.points.to_attribute_config(6*Float32Array.BYTES_PER_ELEMENT),a_show_prev:(t,i)=>i.show.to_attribute_config(),a_show_curr:(t,i)=>i.show.to_attribute_config(Uint8Array.BYTES_PER_ELEMENT),a_show_next:(t,i)=>i.show.to_attribute_config(2*Uint8Array.BYTES_PER_ELEMENT),a_length_so_far:(t,i)=>i.length_so_far.to_attribute_config()},uniforms:{u_canvas_size:t.prop(\"canvas_size\"),u_pixel_ratio:t.prop(\"pixel_ratio\"),u_antialias:t.prop(\"antialias\"),u_line_color:t.prop(\"line_color\"),u_linewidth:t.prop(\"linewidth\"),u_miter_limit:t.prop(\"miter_limit\"),u_line_join:t.prop(\"line_join\"),u_line_cap:t.prop(\"line_cap\"),u_dash_tex:t.prop(\"dash_tex\"),u_dash_tex_info:t.prop(\"dash_tex_info\"),u_dash_scale:t.prop(\"dash_scale\"),u_dash_offset:t.prop(\"dash_offset\")},elements:e,instances:t.prop(\"nsegments\"),blend:{enable:!0,equation:\"max\",func:{srcRGB:1,srcAlpha:1,dstRGB:1,dstAlpha:1}},depth:{enable:!1},scissor:{enable:!0,box:t.prop(\"scissor\")},viewport:t.prop(\"viewport\")};return t(_)}(this._regl,this._line_geometry,this._line_triangles)),this._dashed_line}get_dash(t){return null==this._dash_cache&&(this._dash_cache=new n.DashCache(this._regl)),this._dash_cache.get(t)}marker_no_hatch(t){null==this._marker_no_hatch_map&&(this._marker_no_hatch_map=new Map);let i=this._marker_no_hatch_map.get(t);return null==i&&(i=function(t,i){const e={vert:p.default,frag:`#define USE_${i.toUpperCase()}\\n${h.default}`,attributes:{a_position:{buffer:t.buffer([[-.5,-.5],[-.5,.5],[.5,.5],[.5,-.5]]),divisor:0},a_center:(t,i)=>i.center.to_attribute_config(),a_width:(t,i)=>i.width.to_attribute_config(),a_height:(t,i)=>i.height.to_attribute_config(),a_angle:(t,i)=>i.angle.to_attribute_config(),a_linewidth:(t,i)=>i.linewidth.to_attribute_config(),a_line_color:(t,i)=>i.line_color.to_attribute_config(),a_fill_color:(t,i)=>i.fill_color.to_attribute_config(),a_line_cap:(t,i)=>i.line_cap.to_attribute_config(),a_line_join:(t,i)=>i.line_join.to_attribute_config(),a_show:(t,i)=>i.show.to_attribute_config()},uniforms:{u_canvas_size:t.prop(\"canvas_size\"),u_pixel_ratio:t.prop(\"pixel_ratio\"),u_antialias:t.prop(\"antialias\"),u_size_hint:t.prop(\"size_hint\")},count:4,primitive:\"triangle fan\",instances:t.prop(\"nmarkers\"),blend:{enable:!0,func:{srcRGB:\"one\",srcAlpha:\"one\",dstRGB:\"one minus src alpha\",dstAlpha:\"one minus src alpha\"}},depth:{enable:!1},scissor:{enable:!0,box:t.prop(\"scissor\")},viewport:t.prop(\"viewport\")};return t(e)}(this._regl,t),this._marker_no_hatch_map.set(t,i)),i}marker_hatch(t){null==this._marker_hatch_map&&(this._marker_hatch_map=new Map);let i=this._marker_hatch_map.get(t);return null==i&&(i=function(t,i){const e={vert:`#define HATCH\\n${p.default}`,frag:`#define USE_${i.toUpperCase()}\\n#define HATCH\\n${h.default}`,attributes:{a_position:{buffer:t.buffer([[-.5,-.5],[-.5,.5],[.5,.5],[.5,-.5]]),divisor:0},a_center:(t,i)=>i.center.to_attribute_config(),a_width:(t,i)=>i.width.to_attribute_config(),a_height:(t,i)=>i.height.to_attribute_config(),a_angle:(t,i)=>i.angle.to_attribute_config(),a_linewidth:(t,i)=>i.linewidth.to_attribute_config(),a_line_color:(t,i)=>i.line_color.to_attribute_config(),a_fill_color:(t,i)=>i.fill_color.to_attribute_config(),a_line_cap:(t,i)=>i.line_cap.to_attribute_config(),a_line_join:(t,i)=>i.line_join.to_attribute_config(),a_show:(t,i)=>i.show.to_attribute_config(),a_hatch_pattern:(t,i)=>i.hatch_pattern.to_attribute_config(),a_hatch_scale:(t,i)=>i.hatch_scale.to_attribute_config(),a_hatch_weight:(t,i)=>i.hatch_weight.to_attribute_config(),a_hatch_color:(t,i)=>i.hatch_color.to_attribute_config()},uniforms:{u_canvas_size:t.prop(\"canvas_size\"),u_pixel_ratio:t.prop(\"pixel_ratio\"),u_antialias:t.prop(\"antialias\"),u_size_hint:t.prop(\"size_hint\")},count:4,primitive:\"triangle fan\",instances:t.prop(\"nmarkers\"),blend:{enable:!0,func:{srcRGB:\"one\",srcAlpha:\"one\",dstRGB:\"one minus src alpha\",dstAlpha:\"one minus src alpha\"}},depth:{enable:!1},scissor:{enable:!0,box:t.prop(\"scissor\")},viewport:t.prop(\"viewport\")};return t(e)}(this._regl,t),this._marker_hatch_map.set(t,i)),i}solid_line(){return null==this._solid_line&&(this._solid_line=function(t,i,e){const _={vert:s.default,frag:l.default,attributes:{a_position:{buffer:i,divisor:0},a_point_prev:(t,i)=>i.points.to_attribute_config(),a_point_start:(t,i)=>i.points.to_attribute_config(2*Float32Array.BYTES_PER_ELEMENT),a_point_end:(t,i)=>i.points.to_attribute_config(4*Float32Array.BYTES_PER_ELEMENT),a_point_next:(t,i)=>i.points.to_attribute_config(6*Float32Array.BYTES_PER_ELEMENT),a_show_prev:(t,i)=>i.show.to_attribute_config(),a_show_curr:(t,i)=>i.show.to_attribute_config(Uint8Array.BYTES_PER_ELEMENT),a_show_next:(t,i)=>i.show.to_attribute_config(2*Uint8Array.BYTES_PER_ELEMENT)},uniforms:{u_canvas_size:t.prop(\"canvas_size\"),u_pixel_ratio:t.prop(\"pixel_ratio\"),u_antialias:t.prop(\"antialias\"),u_line_color:t.prop(\"line_color\"),u_linewidth:t.prop(\"linewidth\"),u_miter_limit:t.prop(\"miter_limit\"),u_line_join:t.prop(\"line_join\"),u_line_cap:t.prop(\"line_cap\")},elements:e,instances:t.prop(\"nsegments\"),blend:{enable:!0,equation:\"max\",func:{srcRGB:1,srcAlpha:1,dstRGB:1,dstAlpha:1}},depth:{enable:!1},scissor:{enable:!0,box:t.prop(\"scissor\")},viewport:t.prop(\"viewport\")};return t(_)}(this._regl,this._line_geometry,this._line_triangles)),this._solid_line}}e.ReglWrapper=u,u.__name__=\"ReglWrapper\"},\n 412: function _(e,t,r,n,a){var i,o;i=this,o=function(){\"use strict\";var e=function(e){return e instanceof Uint8Array||e instanceof Uint16Array||e instanceof Uint32Array||e instanceof Int8Array||e instanceof Int16Array||e instanceof Int32Array||e instanceof Float32Array||e instanceof Float64Array||e instanceof Uint8ClampedArray},t=function(e,t){for(var r=Object.keys(t),n=0;n=0&&(0|e)===e||n(\"invalid parameter type, (\"+e+\")\"+i(t)+\". must be a nonnegative integer\")},oneOf:f,shaderError:function(e,t,n,i,o){if(!e.getShaderParameter(t,e.COMPILE_STATUS)){var f=e.getShaderInfoLog(t),u=i===e.FRAGMENT_SHADER?\"fragment\":\"vertex\";g(n,\"string\",u+\" shader source must be a string\",o);var c=h(n,o),l=function(e){var t=[];return e.split(\"\\n\").forEach((function(e){if(!(e.length<5)){var r=/^ERROR:\\s+(\\d+):(\\d+):\\s*(.*)$/.exec(e);r?t.push(new d(0|r[1],0|r[2],r[3].trim())):e.length>0&&t.push(new d(\"unknown\",0,e))}})),t}(f);!function(e,t){t.forEach((function(t){var r=e[t.file];if(r){var n=r.index[t.line];if(n)return n.errors.push(t),void(r.hasErrors=!0)}e.unknown.hasErrors=!0,e.unknown.lines[0].errors.push(t)}))}(c,l),Object.keys(c).forEach((function(e){var t=c[e];if(t.hasErrors){var n=[\"\"],a=[\"\"];i(\"file number \"+e+\": \"+t.name+\"\\n\",\"color:red;text-decoration:underline;font-weight:bold\"),t.lines.forEach((function(e){if(e.errors.length>0){i(s(e.number,4)+\"| \",\"background-color:yellow; font-weight:bold\"),i(e.line+r,\"color:red; background-color:yellow; font-weight:bold\");var t=0;e.errors.forEach((function(n){var a=n.message,o=/^\\s*'(.*)'\\s*:\\s*(.*)$/.exec(a);if(o){var f=o[1];a=o[2],\"assign\"===f&&(f=\"=\"),t=Math.max(e.line.indexOf(f,t),0)}else t=0;i(s(\"| \",6)),i(s(\"^^^\",t+3)+r,\"font-weight:bold\"),i(s(\"| \",6)),i(a+r,\"font-weight:bold\")})),i(s(\"| \",6)+r)}else i(s(e.number,4)+\"| \"),i(e.line+r,\"color:red\")})),\"undefined\"==typeof document||window.chrome?console.log(n.join(\"\")):(a[0]=n.join(\"%c\"),console.log.apply(console,a))}function i(e,t){n.push(e),a.push(t||\"\")}})),a.raise(\"Error compiling \"+u+\" shader, \"+c[0].name)}},linkError:function(e,t,n,i,o){if(!e.getProgramParameter(t,e.LINK_STATUS)){var f=e.getProgramInfoLog(t),u=h(n,o),s='Error linking program with vertex shader, \"'+h(i,o)[0].name+'\", and fragment shader \"'+u[0].name+'\"';\"undefined\"!=typeof document?console.log(\"%c\"+s+\"\\n%c\"+f,\"color:red;text-decoration:underline;font-weight:bold\",\"color:red\"):console.log(s+r+f),a.raise(s)}},callSite:p,saveCommandRef:b,saveDrawInfo:function(e,t,r,n){function a(e){return e?n.id(e):0}function i(e,t){Object.keys(t).forEach((function(t){e[n.id(t)]=!0}))}b(e),e._fragId=a(e.static.frag),e._vertId=a(e.static.vert);var o=e._uniformSet={};i(o,t.static),i(o,t.dynamic);var f=e._attributeSet={};i(f,r.static),i(f,r.dynamic),e._hasCount=\"count\"in e.static||\"count\"in e.dynamic||\"elements\"in e.static||\"elements\"in e.dynamic},framebufferFormat:function(e,t,r){e.texture?f(e.texture._texture.internalformat,t,\"unsupported texture format for attachment\"):f(e.renderbuffer._renderbuffer.format,r,\"unsupported renderbuffer format for attachment\")},guessCommand:m,texture2D:function(e,t,r){var n,i=t.width,o=t.height,f=t.channels;a(i>0&&i<=r.maxTextureSize&&o>0&&o<=r.maxTextureSize,\"invalid texture shape\"),e.wrapS===y&&e.wrapT===y||a(A(i)&&A(o),\"incompatible wrap mode for texture, both width and height must be power of 2\"),1===t.mipmask?1!==i&&1!==o&&a(9984!==e.minFilter&&9986!==e.minFilter&&9985!==e.minFilter&&9987!==e.minFilter,\"min filter requires mipmap\"):(a(A(i)&&A(o),\"texture must be a square power of 2 to support mipmapping\"),a(t.mipmask===(i<<1)-1,\"missing or incomplete mipmap data\")),5126===t.type&&(r.extensions.indexOf(\"oes_texture_float_linear\")<0&&a(9728===e.minFilter&&9728===e.magFilter,\"filter not supported, must enable oes_texture_float_linear\"),a(!e.genMipmaps,\"mipmap generation not supported with float textures\"));var u=t.images;for(n=0;n<16;++n)if(u[n]){var s=i>>n,c=o>>n;a(t.mipmask&1<0&&i<=n.maxTextureSize&&o>0&&o<=n.maxTextureSize,\"invalid texture shape\"),a(i===o,\"cube map must be square\"),a(t.wrapS===y&&t.wrapT===y,\"wrap mode not supported by cube map\");for(var u=0;u>l,p=o>>l;a(s.mipmask&1<1&&t===r&&('\"'===t||\"'\"===t))return['\"'+O(e.substr(1,e.length-2))+'\"'];var n=/\\[(false|true|null|\\d+|'[^']*'|\"[^\"]*\")\\]/.exec(e);if(n)return E(e.substr(0,n.index)).concat(E(n[1])).concat(E(e.substr(n.index+n[0].length)));var a=e.split(\".\");if(1===a.length)return['\"'+O(e)+'\"'];for(var i=[],o=0;o0,\"invalid pixel ratio\"))):_.raise(\"invalid arguments to regl\"),r&&(\"canvas\"===r.nodeName.toLowerCase()?a=r:n=r),!i){if(!a){_(\"undefined\"!=typeof document,\"must manually specify webgl context outside of DOM environments\");var h=function(e,r,n){var a,i=document.createElement(\"canvas\");function o(){var t=window.innerWidth,r=window.innerHeight;if(e!==document.body){var a=i.getBoundingClientRect();t=a.right-a.left,r=a.bottom-a.top}i.width=n*t,i.height=n*r}return t(i.style,{border:0,margin:0,padding:0,top:0,left:0,width:\"100%\",height:\"100%\"}),e.appendChild(i),e===document.body&&(i.style.position=\"absolute\",t(e.style,{margin:0,padding:0})),e!==document.body&&\"function\"==typeof ResizeObserver?(a=new ResizeObserver((function(){setTimeout(o)}))).observe(e):window.addEventListener(\"resize\",o,!1),o(),{canvas:i,onDestroy:function(){a?a.disconnect():window.removeEventListener(\"resize\",o),e.removeChild(i)}}}(n||document.body,0,l);if(!h)return null;a=h.canvas,p=h.onDestroy}void 0===u.premultipliedAlpha&&(u.premultipliedAlpha=!0),i=function(e,t){function r(r){try{return e.getContext(r,t)}catch(e){return null}}return r(\"webgl\")||r(\"experimental-webgl\")||r(\"webgl-experimental\")}(a,u)}return i?{gl:i,canvas:a,container:n,extensions:s,optionalExtensions:c,pixelRatio:l,profile:d,onDone:m,onDestroy:p}:(p(),m(\"webgl not supported, try upgrading your browser or graphics drivers http://get.webgl.org\"),null)}function V(e,t){for(var r=Array(e),n=0;n65535)<<4,t|=r=((e>>>=t)>255)<<3,t|=r=((e>>>=r)>15)<<2,(t|=r=((e>>>=r)>3)<<1)|(e>>>=r)>>1}function P(){var e=V(8,(function(){return[]}));function t(t){var r=function(e){for(var t=16;t<=1<<28;t*=16)if(e<=t)return t;return 0}(t),n=e[I(r)>>2];return n.length>0?n.pop():new ArrayBuffer(r)}function r(t){e[I(t.byteLength)>>2].push(t)}return{alloc:t,free:r,allocType:function(e,r){var n=null;switch(e){case 5120:n=new Int8Array(t(r),0,r);break;case 5121:n=new Uint8Array(t(r),0,r);break;case 5122:n=new Int16Array(t(2*r),0,r);break;case 5123:n=new Uint16Array(t(2*r),0,r);break;case 5124:n=new Int32Array(t(4*r),0,r);break;case 5125:n=new Uint32Array(t(4*r),0,r);break;case 5126:n=new Float32Array(t(4*r),0,r);break;default:return null}return n.length!==r?n.subarray(0,r):n},freeType:function(e){r(e.buffer)}}}var L=P();L.zero=P();var R=3553,M=6408,W=5126,U=36160;function G(t){return!!t&&\"object\"==typeof t&&Array.isArray(t.shape)&&Array.isArray(t.stride)&&\"number\"==typeof t.offset&&t.shape.length===t.stride.length&&(Array.isArray(t.data)||e(t.data))}var H=function(e){return Object.keys(e).map((function(t){return e[t]}))},N={shape:function(e){for(var t=[],r=e;r.length;r=r[0])t.push(r.length);return t},flatten:function(e,t,r,n){var a=1;if(t.length)for(var i=0;i>>31<<15,i=(n<<1>>>24)-127,o=n>>13&1023;if(i<-24)t[r]=a;else if(i<-14){var f=-14-i;t[r]=a+(o+1024>>f)}else t[r]=i>15?a+31744:a+(i+15<<10)+o}return t}function me(t){return Array.isArray(t)||e(t)}var pe=function(e){return!(e&e-1||!e)},he=3553,be=34067,ve=34069,ge=6408,ye=6406,xe=6407,we=6409,Ae=6410,_e=32855,ke=6402,Se=34041,Oe=35904,Ee=35906,Te=36193,De=33776,je=33777,Ce=33778,ze=33779,Fe=5121,Be=5123,Ve=5125,Ie=5126,Pe=33071,Le=9728,Re=9984,Me=9987,We=4352,Ue=33984,Ge=[Re,9986,9985,Me],He=[0,we,Ae,xe,ge],Ne={};function qe(e){return\"[object \"+e+\"]\"}Ne[6409]=Ne[6406]=Ne[6402]=1,Ne[34041]=Ne[6410]=2,Ne[6407]=Ne[35904]=3,Ne[6408]=Ne[35906]=4;var Qe=qe(\"HTMLCanvasElement\"),Ye=qe(\"OffscreenCanvas\"),Xe=qe(\"CanvasRenderingContext2D\"),$e=qe(\"ImageBitmap\"),Ke=qe(\"HTMLImageElement\"),Je=qe(\"HTMLVideoElement\"),Ze=Object.keys(Y).concat([Qe,Ye,Xe,$e,Ke,Je]),et=[];et[5121]=1,et[5126]=4,et[36193]=2,et[5123]=2,et[5125]=4;var tt=[];function rt(e){return Array.isArray(e)&&(0===e.length||\"number\"==typeof e[0])}function nt(e){return!!Array.isArray(e)&&!(0===e.length||!me(e[0]))}function at(e){return Object.prototype.toString.call(e)}function it(e){return at(e)===Qe}function ot(e){return at(e)===Ye}function ft(e){if(!e)return!1;var t=at(e);return Ze.indexOf(t)>=0||rt(e)||nt(e)||G(e)}function ut(e){return 0|Y[Object.prototype.toString.call(e)]}function st(e,t){return L.allocType(e.type===Te?Ie:e.type,t)}function ct(e,t){e.type===Te?(e.data=de(t),L.freeType(t)):e.data=t}function lt(e,t,r,n,a,i){var o;if(o=void 0!==tt[e]?tt[e]:Ne[e]*et[t],i&&(o*=6),a){for(var f=0,u=r;u>=1;)f+=o*u*u,u/=2;return f}return o*r*n}function dt(r,n,a,i,o,f,u){var s={\"don't care\":We,\"dont care\":We,nice:4354,fast:4353},c={repeat:10497,clamp:Pe,mirror:33648},l={nearest:Le,linear:9729},d=t({mipmap:Me,\"nearest mipmap nearest\":Re,\"linear mipmap nearest\":9985,\"nearest mipmap linear\":9986,\"linear mipmap linear\":Me},l),m={none:0,browser:37444},p={uint8:Fe,rgba4:32819,rgb565:33635,\"rgb5 a1\":32820},h={alpha:ye,luminance:we,\"luminance alpha\":Ae,rgb:xe,rgba:ge,rgba4:32854,\"rgb5 a1\":_e,rgb565:36194},b={};n.ext_srgb&&(h.srgb=Oe,h.srgba=Ee),n.oes_texture_float&&(p.float32=p.float=Ie),n.oes_texture_half_float&&(p.float16=p[\"half float\"]=Te),n.webgl_depth_texture&&(t(h,{depth:ke,\"depth stencil\":Se}),t(p,{uint16:Be,uint32:Ve,\"depth stencil\":34042})),n.webgl_compressed_texture_s3tc&&t(b,{\"rgb s3tc dxt1\":De,\"rgba s3tc dxt1\":je,\"rgba s3tc dxt3\":Ce,\"rgba s3tc dxt5\":ze}),n.webgl_compressed_texture_atc&&t(b,{\"rgb atc\":35986,\"rgba atc explicit alpha\":35987,\"rgba atc interpolated alpha\":34798}),n.webgl_compressed_texture_pvrtc&&t(b,{\"rgb pvrtc 4bppv1\":35840,\"rgb pvrtc 2bppv1\":35841,\"rgba pvrtc 4bppv1\":35842,\"rgba pvrtc 2bppv1\":35843}),n.webgl_compressed_texture_etc1&&(b[\"rgb etc1\"]=36196);var v=Array.prototype.slice.call(r.getParameter(34467));Object.keys(b).forEach((function(e){var t=b[e];v.indexOf(t)>=0&&(h[e]=t)}));var g=Object.keys(h);a.textureFormats=g;var y=[];Object.keys(h).forEach((function(e){var t=h[e];y[t]=e}));var x=[];Object.keys(p).forEach((function(e){var t=p[e];x[t]=e}));var w=[];Object.keys(l).forEach((function(e){w[l[e]]=e}));var A=[];Object.keys(d).forEach((function(e){var t=d[e];A[t]=e}));var k=[];Object.keys(c).forEach((function(e){k[c[e]]=e}));var S=g.reduce((function(e,t){var r=h[t];return r===we||r===ye||r===we||r===Ae||r===ke||r===Se||n.ext_srgb&&(r===Oe||r===Ee)?e[r]=r:r===_e||t.indexOf(\"rgba\")>=0?e[r]=ge:e[r]=xe,e}),{});function O(){this.internalformat=ge,this.format=ge,this.type=Fe,this.compressed=!1,this.premultiplyAlpha=!1,this.flipY=!1,this.unpackAlignment=1,this.colorSpace=37444,this.width=0,this.height=0,this.channels=0}function E(e,t){e.internalformat=t.internalformat,e.format=t.format,e.type=t.type,e.compressed=t.compressed,e.premultiplyAlpha=t.premultiplyAlpha,e.flipY=t.flipY,e.unpackAlignment=t.unpackAlignment,e.colorSpace=t.colorSpace,e.width=t.width,e.height=t.height,e.channels=t.channels}function T(e,t){if(\"object\"==typeof t&&t){if(\"premultiplyAlpha\"in t&&(_.type(t.premultiplyAlpha,\"boolean\",\"invalid premultiplyAlpha\"),e.premultiplyAlpha=t.premultiplyAlpha),\"flipY\"in t&&(_.type(t.flipY,\"boolean\",\"invalid texture flip\"),e.flipY=t.flipY),\"alignment\"in t&&(_.oneOf(t.alignment,[1,2,4,8],\"invalid texture unpack alignment\"),e.unpackAlignment=t.alignment),\"colorSpace\"in t&&(_.parameter(t.colorSpace,m,\"invalid colorSpace\"),e.colorSpace=m[t.colorSpace]),\"type\"in t){var r=t.type;_(n.oes_texture_float||!(\"float\"===r||\"float32\"===r),\"you must enable the OES_texture_float extension in order to use floating point textures.\"),_(n.oes_texture_half_float||!(\"half float\"===r||\"float16\"===r),\"you must enable the OES_texture_half_float extension in order to use 16-bit floating point textures.\"),_(n.webgl_depth_texture||!(\"uint16\"===r||\"uint32\"===r||\"depth stencil\"===r),\"you must enable the WEBGL_depth_texture extension in order to use depth/stencil textures.\"),_.parameter(r,p,\"invalid texture type\"),e.type=p[r]}var i=e.width,o=e.height,f=e.channels,u=!1;\"shape\"in t?(_(Array.isArray(t.shape)&&t.shape.length>=2,\"shape must be an array\"),i=t.shape[0],o=t.shape[1],3===t.shape.length&&(f=t.shape[2],_(f>0&&f<=4,\"invalid number of channels\"),u=!0),_(i>=0&&i<=a.maxTextureSize,\"invalid width\"),_(o>=0&&o<=a.maxTextureSize,\"invalid height\")):(\"radius\"in t&&(i=o=t.radius,_(i>=0&&i<=a.maxTextureSize,\"invalid radius\")),\"width\"in t&&(i=t.width,_(i>=0&&i<=a.maxTextureSize,\"invalid width\")),\"height\"in t&&(o=t.height,_(o>=0&&o<=a.maxTextureSize,\"invalid height\")),\"channels\"in t&&(f=t.channels,_(f>0&&f<=4,\"invalid number of channels\"),u=!0)),e.width=0|i,e.height=0|o,e.channels=0|f;var s=!1;if(\"format\"in t){var c=t.format;_(n.webgl_depth_texture||!(\"depth\"===c||\"depth stencil\"===c),\"you must enable the WEBGL_depth_texture extension in order to use depth/stencil textures.\"),_.parameter(c,h,\"invalid texture format\");var l=e.internalformat=h[c];e.format=S[l],c in p&&(\"type\"in t||(e.type=p[c])),c in b&&(e.compressed=!0),s=!0}!u&&s?e.channels=Ne[e.format]:u&&!s?e.channels!==He[e.format]&&(e.format=e.internalformat=He[e.channels]):s&&u&&_(e.channels===Ne[e.format],\"number of channels inconsistent with specified format\")}}function D(e){r.pixelStorei(37440,e.flipY),r.pixelStorei(37441,e.premultiplyAlpha),r.pixelStorei(37443,e.colorSpace),r.pixelStorei(3317,e.unpackAlignment)}function j(){O.call(this),this.xOffset=0,this.yOffset=0,this.data=null,this.needsFree=!1,this.element=null,this.needsCopy=!1}function C(t,r){var n=null;if(ft(r)?n=r:r&&(_.type(r,\"object\",\"invalid pixel data type\"),T(t,r),\"x\"in r&&(t.xOffset=0|r.x),\"y\"in r&&(t.yOffset=0|r.y),ft(r.data)&&(n=r.data)),_(!t.compressed||n instanceof Uint8Array,\"compressed texture data must be stored in a uint8array\"),r.copy){_(!n,\"can not specify copy and data field for the same texture\");var i=o.viewportWidth,f=o.viewportHeight;t.width=t.width||i-t.xOffset,t.height=t.height||f-t.yOffset,t.needsCopy=!0,_(t.xOffset>=0&&t.xOffset=0&&t.yOffset0&&t.width<=i&&t.height>0&&t.height<=f,\"copy texture read out of bounds\")}else if(n){if(e(n))t.channels=t.channels||4,t.data=n,\"type\"in r||t.type!==Fe||(t.type=ut(n));else if(rt(n))t.channels=t.channels||4,function(e,t){var r=t.length;switch(e.type){case Fe:case Be:case Ve:case Ie:var n=L.allocType(e.type,r);n.set(t),e.data=n;break;case Te:e.data=de(t);break;default:_.raise(\"unsupported texture type, must specify a typed array\")}}(t,n),t.alignment=1,t.needsFree=!0;else if(G(n)){var u=n.data;Array.isArray(u)||t.type!==Fe||(t.type=ut(u));var s,c,l,d,m,p,h=n.shape,b=n.stride;3===h.length?(l=h[2],p=b[2]):(_(2===h.length,\"invalid ndarray pixel data, must be 2 or 3D\"),l=1,p=1),s=h[0],c=h[1],d=b[0],m=b[1],t.alignment=1,t.width=s,t.height=c,t.channels=l,t.format=t.internalformat=He[l],t.needsFree=!0,function(e,t,r,n,a,i){for(var o=e.width,f=e.height,u=e.channels,s=st(e,o*f*u),c=0,l=0;l=0,\"oes_texture_float extension not enabled\"):t.type===Te&&_(a.extensions.indexOf(\"oes_texture_half_float\")>=0,\"oes_texture_half_float extension not enabled\")}function z(e,t,n){var a=e.element,o=e.data,f=e.internalformat,u=e.format,s=e.type,c=e.width,l=e.height;D(e),a?r.texImage2D(t,n,u,u,s,a):e.compressed?r.compressedTexImage2D(t,n,f,c,l,0,o):e.needsCopy?(i(),r.copyTexImage2D(t,n,u,e.xOffset,e.yOffset,c,l,0)):r.texImage2D(t,n,u,c,l,0,u,s,o||null)}function F(e,t,n,a,o){var f=e.element,u=e.data,s=e.internalformat,c=e.format,l=e.type,d=e.width,m=e.height;D(e),f?r.texSubImage2D(t,o,n,a,c,l,f):e.compressed?r.compressedTexSubImage2D(t,o,n,a,s,d,m,u):e.needsCopy?(i(),r.copyTexSubImage2D(t,o,n,a,e.xOffset,e.yOffset,d,m)):r.texSubImage2D(t,o,n,a,d,m,c,l,u)}var B=[];function V(){return B.pop()||new j}function I(e){e.needsFree&&L.freeType(e.data),j.call(e),B.push(e)}function P(){O.call(this),this.genMipmaps=!1,this.mipmapHint=We,this.mipmask=0,this.images=Array(16)}function R(e,t,r){var n=e.images[0]=V();e.mipmask=1,n.width=e.width=t,n.height=e.height=r,n.channels=e.channels=4}function M(e,t){var r=null;if(ft(t))E(r=e.images[0]=V(),e),C(r,t),e.mipmask=1;else if(T(e,t),Array.isArray(t.mipmap))for(var n=t.mipmap,a=0;a>=a,r.height>>=a,C(r,n[a]),e.mipmask|=1<=0&&!(\"faces\"in t)&&(e.genMipmaps=!0)}if(\"mag\"in t){var n=t.mag;_.parameter(n,l),e.magFilter=l[n]}var i=e.wrapS,o=e.wrapT;if(\"wrap\"in t){var f=t.wrap;\"string\"==typeof f?(_.parameter(f,c),i=o=c[f]):Array.isArray(f)&&(_.parameter(f[0],c),_.parameter(f[1],c),i=c[f[0]],o=c[f[1]])}else{if(\"wrapS\"in t){var u=t.wrapS;_.parameter(u,c),i=c[u]}if(\"wrapT\"in t){var m=t.wrapT;_.parameter(m,c),o=c[m]}}if(e.wrapS=i,e.wrapT=o,\"anisotropic\"in t){var p=t.anisotropic;_(\"number\"==typeof p&&p>=1&&p<=a.maxAnisotropic,\"aniso samples must be between 1 and \"),e.anisotropic=t.anisotropic}if(\"mipmap\"in t){var h=!1;switch(typeof t.mipmap){case\"string\":_.parameter(t.mipmap,s,\"invalid mipmap hint\"),e.mipmapHint=s[t.mipmap],e.genMipmaps=!0,h=!0;break;case\"boolean\":h=e.genMipmaps=t.mipmap;break;case\"object\":_(Array.isArray(t.mipmap),\"invalid mipmap type\"),e.genMipmaps=!1,h=!0;break;default:_.raise(\"invalid mipmap type\")}h&&!(\"min\"in t)&&(e.minFilter=Re)}}function $(e,t){r.texParameteri(t,10241,e.minFilter),r.texParameteri(t,10240,e.magFilter),r.texParameteri(t,10242,e.wrapS),r.texParameteri(t,10243,e.wrapT),n.ext_texture_filter_anisotropic&&r.texParameteri(t,34046,e.anisotropic),e.genMipmaps&&(r.hint(33170,e.mipmapHint),r.generateMipmap(t))}var K=0,J={},Z=a.maxTextureUnits,ee=Array(Z).map((function(){return null}));function te(e){O.call(this),this.mipmask=0,this.internalformat=ge,this.id=K++,this.refCount=1,this.target=e,this.texture=r.createTexture(),this.unit=-1,this.bindCount=0,this.texInfo=new Y,u.profile&&(this.stats={size:0})}function re(e){r.activeTexture(Ue),r.bindTexture(e.target,e.texture)}function ne(){var e=ee[0];e?r.bindTexture(e.target,e.texture):r.bindTexture(he,null)}function ae(e){var t=e.texture;_(t,\"must not double destroy texture\");var n=e.unit,a=e.target;n>=0&&(r.activeTexture(Ue+n),r.bindTexture(a,null),ee[n]=null),r.deleteTexture(t),e.texture=null,e.params=null,e.pixels=null,e.refCount=0,delete J[e.id],f.textureCount--}return t(te.prototype,{bind:function(){var e=this;e.bindCount+=1;var t=e.unit;if(t<0){for(var n=0;n0)continue;a.unit=-1}ee[n]=e,t=n;break}t>=Z&&_.raise(\"insufficient number of texture units\"),u.profile&&f.maxTextureUnits>u)-o,s.height=s.height||(n.height>>u)-f,_(n.type===s.type&&n.format===s.format&&n.internalformat===s.internalformat,\"incompatible format for texture.subimage\"),_(o>=0&&f>=0&&o+s.width<=n.width&&f+s.height<=n.height,\"texture.subimage write out of bounds\"),_(n.mipmask&1<>f;++f){var s=a>>f,c=o>>f;if(!s||!c)break;r.texImage2D(he,f,n.format,s,c,0,n.format,n.type,null)}return ne(),u.profile&&(n.stats.size=lt(n.internalformat,n.type,a,o,!1,!1)),i},i._reglType=\"texture2d\",i._texture=n,u.profile&&(i.stats=n.stats),i.destroy=function(){n.decRef()},i},createCube:function(e,t,n,i,o,s){var c=new te(be);J[c.id]=c,f.cubeCount++;var l=new Array(6);function d(e,t,r,n,i,o){var f,s=c.texInfo;for(Y.call(s),f=0;f<6;++f)l[f]=q();if(\"number\"!=typeof e&&e)if(\"object\"==typeof e)if(t)M(l[0],e),M(l[1],t),M(l[2],r),M(l[3],n),M(l[4],i),M(l[5],o);else if(X(s,e),T(c,e),\"faces\"in e){var m=e.faces;for(_(Array.isArray(m)&&6===m.length,\"cube faces must be a length 6 array\"),f=0;f<6;++f)_(\"object\"==typeof m[f]&&!!m[f],\"invalid input for cube map face\"),E(l[f],c),M(l[f],m[f])}else for(f=0;f<6;++f)M(l[f],e);else _.raise(\"invalid arguments to cube map\");else{var p=0|e||1;for(f=0;f<6;++f)R(l[f],p,p)}for(E(c,l[0]),_.optional((function(){a.npotTextureCube||_(pe(c.width)&&pe(c.height),\"your browser does not support non power or two texture dimensions\")})),s.genMipmaps?c.mipmask=(l[0].width<<1)-1:c.mipmask=l[0].mipmask,_.textureCube(c,s,l,a),c.internalformat=l[0].internalformat,d.width=l[0].width,d.height=l[0].height,re(c),f=0;f<6;++f)W(l[f],ve+f);for($(s,be),ne(),u.profile&&(c.stats.size=lt(c.internalformat,c.type,d.width,d.height,s.genMipmaps,!0)),d.format=y[c.internalformat],d.type=x[c.type],d.mag=w[s.magFilter],d.min=A[s.minFilter],d.wrapS=k[s.wrapS],d.wrapT=k[s.wrapT],f=0;f<6;++f)Q(l[f]);return d}return d(e,t,n,i,o,s),d.subimage=function(e,t,r,n,a){_(!!t,\"must specify image data\"),_(\"number\"==typeof e&&e===(0|e)&&e>=0&&e<6,\"invalid face\");var i=0|r,o=0|n,f=0|a,u=V();return E(u,c),u.width=0,u.height=0,C(u,t),u.width=u.width||(c.width>>f)-i,u.height=u.height||(c.height>>f)-o,_(c.type===u.type&&c.format===u.format&&c.internalformat===u.internalformat,\"incompatible format for texture.subimage\"),_(i>=0&&o>=0&&i+u.width<=c.width&&o+u.height<=c.height,\"texture.subimage write out of bounds\"),_(c.mipmask&1<>a;++a)r.texImage2D(ve+n,a,c.format,t>>a,t>>a,0,c.format,c.type,null);return ne(),u.profile&&(c.stats.size=lt(c.internalformat,c.type,d.width,d.height,!1,!0)),d}},d._reglType=\"textureCube\",d._texture=c,u.profile&&(d.stats=c.stats),d.destroy=function(){c.decRef()},d},clear:function(){for(var e=0;e>t,e.height>>t,0,e.internalformat,e.type,null);else for(var n=0;n<6;++n)r.texImage2D(ve+n,t,e.internalformat,e.width>>t,e.height>>t,0,e.internalformat,e.type,null);$(e.texInfo,e.target)}))},refresh:function(){for(var e=0;e=0&&c=0&&l0&&d+c<=a.framebufferWidth,\"invalid width for read pixels\"),_(m>0&&m+l<=a.framebufferHeight,\"invalid height for read pixels\"),n();var h=d*m*4;return p||(s===Dt?p=new Uint8Array(h):s===jt&&(p=p||new Float32Array(h))),_.isTypedArray(p,\"data buffer for regl.read() must be a typedarray\"),_(p.byteLength>=h,\"data buffer for regl.read() too small\"),t.pixelStorei(3333,4),t.readPixels(c,l,d,m,6408,s,p),p}return function(e){return e&&\"framebuffer\"in e?function(e){var t;return r.setFBO({framebuffer:e.framebuffer},(function(){t=u(e)})),t}(e):u(e)}}function zt(e){return Array.prototype.slice.call(e)}function Ft(e){return zt(e).join(\"\")}var Bt=\"xyzw\".split(\"\"),Vt=\"dither\",It=\"blend.enable\",Pt=\"blend.color\",Lt=\"blend.equation\",Rt=\"blend.func\",Mt=\"depth.enable\",Wt=\"depth.func\",Ut=\"depth.range\",Gt=\"depth.mask\",Ht=\"colorMask\",Nt=\"cull.enable\",qt=\"cull.face\",Qt=\"frontFace\",Yt=\"lineWidth\",Xt=\"polygonOffset.enable\",$t=\"polygonOffset.offset\",Kt=\"sample.alpha\",Jt=\"sample.enable\",Zt=\"sample.coverage\",er=\"stencil.enable\",tr=\"stencil.mask\",rr=\"stencil.func\",nr=\"stencil.opFront\",ar=\"stencil.opBack\",ir=\"scissor.enable\",or=\"scissor.box\",fr=\"viewport\",ur=\"profile\",sr=\"framebuffer\",cr=\"vert\",lr=\"frag\",dr=\"elements\",mr=\"primitive\",pr=\"count\",hr=\"offset\",br=\"instances\",vr=\"vao\",gr=\"Width\",yr=\"Height\",xr=sr+gr,wr=sr+yr,Ar=\"drawingBufferWidth\",_r=\"drawingBufferHeight\",kr=[Rt,Lt,rr,nr,ar,Zt,fr,or,$t],Sr=34962,Or=34963,Er=5126,Tr=35664,Dr=35665,jr=35666,Cr=5124,zr=35667,Fr=35668,Br=35669,Vr=35670,Ir=35671,Pr=35672,Lr=35673,Rr=35674,Mr=35675,Wr=35676,Ur=35678,Gr=35680,Hr=1028,Nr=1029,qr=2305,Qr=7680,Yr={0:0,1:1,zero:0,one:1,\"src color\":768,\"one minus src color\":769,\"src alpha\":770,\"one minus src alpha\":771,\"dst color\":774,\"one minus dst color\":775,\"dst alpha\":772,\"one minus dst alpha\":773,\"constant color\":32769,\"one minus constant color\":32770,\"constant alpha\":32771,\"one minus constant alpha\":32772,\"src alpha saturate\":776},Xr=[\"constant color, constant alpha\",\"one minus constant color, constant alpha\",\"constant color, one minus constant alpha\",\"one minus constant color, one minus constant alpha\",\"constant alpha, constant color\",\"constant alpha, one minus constant color\",\"one minus constant alpha, constant color\",\"one minus constant alpha, one minus constant color\"],$r={never:512,less:513,\"<\":513,equal:514,\"=\":514,\"==\":514,\"===\":514,lequal:515,\"<=\":515,greater:516,\">\":516,notequal:517,\"!=\":517,\"!==\":517,gequal:518,\">=\":518,always:519},Kr={0:0,zero:0,keep:7680,replace:7681,increment:7682,decrement:7683,\"increment wrap\":34055,\"decrement wrap\":34056,invert:5386},Jr={frag:35632,vert:35633},Zr={cw:2304,ccw:qr};function en(t){return Array.isArray(t)||e(t)||G(t)}function tn(e){return e.sort((function(e,t){return e===fr?-1:t===fr?1:e=1,n>=2,t)}if(4===r){var a=e.data;return new rn(a.thisDep,a.contextDep,a.propDep,t)}if(5===r)return new rn(!1,!1,!1,t);if(6===r){for(var i=!1,o=!1,f=!1,u=0;u=1&&(o=!0),c>=2&&(f=!0)}else 4===s.type&&(i=i||s.data.thisDep,o=o||s.data.contextDep,f=f||s.data.propDep)}return new rn(i,o,f,t)}return new rn(3===r,2===r,1===r,t)}var fn=new rn(!1,!1,!1,(function(){}));function un(e,r,n,a,i,o,f,u,s,c,l,d,m,p,h){var b=c.Record,v={add:32774,subtract:32778,\"reverse subtract\":32779};n.ext_blend_minmax&&(v.min=32775,v.max=32776);var g=n.angle_instanced_arrays,y=n.webgl_draw_buffers,x=n.oes_vertex_array_object,w={dirty:!0,profile:h.profile},A={},k=[],S={},O={};function E(e){return e.replace(\".\",\"_\")}function T(e,t,r){var n=E(e);k.push(e),A[n]=w[n]=!!r,S[n]=t}function j(e,t,r){var n=E(e);k.push(e),Array.isArray(r)?(w[n]=r.slice(),A[n]=r.slice()):w[n]=A[n]=r,O[n]=t}T(Vt,3024),T(It,3042),j(Pt,\"blendColor\",[0,0,0,0]),j(Lt,\"blendEquationSeparate\",[32774,32774]),j(Rt,\"blendFuncSeparate\",[1,0,1,0]),T(Mt,2929,!0),j(Wt,\"depthFunc\",513),j(Ut,\"depthRange\",[0,1]),j(Gt,\"depthMask\",!0),j(Ht,Ht,[!0,!0,!0,!0]),T(Nt,2884),j(qt,\"cullFace\",Nr),j(Qt,Qt,qr),j(Yt,Yt,1),T(Xt,32823),j($t,\"polygonOffset\",[0,0]),T(Kt,32926),T(Jt,32928),j(Zt,\"sampleCoverage\",[1,!1]),T(er,2960),j(tr,\"stencilMask\",-1),j(rr,\"stencilFunc\",[519,0,-1]),j(nr,\"stencilOpSeparate\",[Hr,Qr,Qr,Qr]),j(ar,\"stencilOpSeparate\",[Nr,Qr,Qr,Qr]),T(ir,3089),j(or,\"scissor\",[0,0,e.drawingBufferWidth,e.drawingBufferHeight]),j(fr,fr,[0,0,e.drawingBufferWidth,e.drawingBufferHeight]);var C={gl:e,context:m,strings:r,next:A,current:w,draw:d,elements:o,buffer:i,shader:l,attributes:c.state,vao:c,uniforms:s,framebuffer:u,extensions:n,timer:p,isBufferArgs:en},z={primTypes:ie,compareFuncs:$r,blendFuncs:Yr,blendEquations:v,stencilOps:Kr,glTypes:X,orientationType:Zr};_.optional((function(){C.isArrayLike=me})),y&&(z.backBuffer=[Nr],z.drawBuffer=V(a.maxDrawbuffers,(function(e){return 0===e?[0]:V(e,(function(e){return 36064+e}))})));var F=0;function B(){var e=function(){var e=0,r=[],n=[];function a(){var r=[],n=[];return t((function(){r.push.apply(r,zt(arguments))}),{def:function(){var t=\"v\"+e++;return n.push(t),arguments.length>0&&(r.push(t,\"=\"),r.push.apply(r,zt(arguments)),r.push(\";\")),t},toString:function(){return Ft([n.length>0?\"var \"+n.join(\",\")+\";\":\"\",Ft(r)])}})}function i(){var e=a(),r=a(),n=e.toString,i=r.toString;function o(t,n){r(t,n,\"=\",e.def(t,n),\";\")}return t((function(){e.apply(e,zt(arguments))}),{def:e.def,entry:e,exit:r,save:o,set:function(t,r,n){o(t,r),e(t,r,\"=\",n,\";\")},toString:function(){return n()+i()}})}var o=a(),f={};return{global:o,link:function(t){for(var a=0;a=0,'unknown parameter \"'+t+'\"',d.commandStr)}))}t(m),t(p)}));var h=function(e,t){var r=e.static;if(\"string\"==typeof r[lr]&&\"string\"==typeof r[cr]){if(Object.keys(t.dynamic).length>0)return null;var n=t.static,a=Object.keys(n);if(a.length>0&&\"number\"==typeof n[a[0]]){for(var i=[],o=0;o=0,\"invalid \"+e,r.commandStr)):u=!1,\"height\"in i?(f=0|i.height,_.command(f>=0,\"invalid \"+e,r.commandStr)):u=!1,new rn(!u&&t&&t.thisDep,!u&&t&&t.contextDep,!u&&t&&t.propDep,(function(e,t){var r=e.shared.context,n=o;\"width\"in i||(n=t.def(r,\".\",xr,\"-\",s));var a=f;return\"height\"in i||(a=t.def(r,\".\",wr,\"-\",c)),[s,c,n,a]}))}if(e in a){var l=a[e],d=on(l,(function(t,r){var n=t.invoke(r,l);_.optional((function(){t.assert(r,n+\"&&typeof \"+n+'===\"object\"',\"invalid \"+e)}));var a=t.shared.context,i=r.def(n,\".x|0\"),o=r.def(n,\".y|0\"),f=r.def('\"width\" in ',n,\"?\",n,\".width|0:\",\"(\",a,\".\",xr,\"-\",i,\")\"),u=r.def('\"height\" in ',n,\"?\",n,\".height|0:\",\"(\",a,\".\",wr,\"-\",o,\")\");return _.optional((function(){t.assert(r,f+\">=0&&\"+u+\">=0\",\"invalid \"+e)})),[i,o,f,u]}));return t&&(d.thisDep=d.thisDep||t.thisDep,d.contextDep=d.contextDep||t.contextDep,d.propDep=d.propDep||t.propDep),d}return t?new rn(t.thisDep,t.contextDep,t.propDep,(function(e,t){var r=e.shared.context;return[0,0,t.def(r,\".\",xr),t.def(r,\".\",wr)]})):null}var o=i(fr);if(o){var f=o;o=new rn(o.thisDep,o.contextDep,o.propDep,(function(e,t){var r=f.append(e,t),n=e.shared.context;return t.set(n,\".viewportWidth\",r[2]),t.set(n,\".viewportHeight\",r[3]),r}))}return{viewport:o,scissor_box:i(or)}}(e,y,d),w=function(e,t){var r=e.static,n=e.dynamic,a={},i=!1,f=function(){if(vr in r){var e=r[vr];return null!==e&&null===c.getVAO(e)&&(e=c.createVAO(e)),i=!0,a.vao=e,an((function(t){var r=c.getVAO(e);return r?t.link(r):\"null\"}))}if(vr in n){i=!0;var t=n[vr];return on(t,(function(e,r){var n=e.invoke(r,t);return r.def(e.shared.vao+\".getVAO(\"+n+\")\")}))}return null}(),u=!1,s=function(){if(dr in r){var e=r[dr];if(a.elements=e,en(e)){var s=a.elements=o.create(e,!0);e=o.getElements(s),u=!0}else e&&(e=o.getElements(e),u=!0,_.command(e,\"invalid elements\",t.commandStr));var c=an((function(t,r){if(e){var n=t.link(e);return t.ELEMENTS=n,n}return t.ELEMENTS=null,null}));return c.value=e,c}if(dr in n){u=!0;var l=n[dr];return on(l,(function(e,t){var r=e.shared,n=r.isBufferArgs,a=r.elements,i=e.invoke(t,l),o=t.def(\"null\"),f=t.def(n,\"(\",i,\")\"),u=e.cond(f).then(o,\"=\",a,\".createStream(\",i,\");\").else(o,\"=\",a,\".getElements(\",i,\");\");return _.optional((function(){e.assert(u.else,\"!\"+i+\"||\"+o,\"invalid elements\")})),t.entry(u),t.exit(e.cond(f).then(a,\".destroyStream(\",o,\");\")),e.ELEMENTS=o,o}))}return i?new rn(f.thisDep,f.contextDep,f.propDep,(function(e,t){return t.def(e.shared.vao+\".currentVAO?\"+e.shared.elements+\".getElements(\"+e.shared.vao+\".currentVAO.elements):null\")})):null}();function l(e,o){if(e in r){var s=0|r[e];return o?a.offset=s:a.instances=s,_.command(!o||s>=0,\"invalid \"+e,t.commandStr),an((function(e,t){return o&&(e.OFFSET=s),s}))}if(e in n){var c=n[e];return on(c,(function(t,r){var n=t.invoke(r,c);return o&&(t.OFFSET=n,_.optional((function(){t.assert(r,n+\">=0\",\"invalid \"+e)}))),n}))}if(o){if(u)return an((function(e,t){return e.OFFSET=0,0}));if(i)return new rn(f.thisDep,f.contextDep,f.propDep,(function(e,t){return t.def(e.shared.vao+\".currentVAO?\"+e.shared.vao+\".currentVAO.offset:0\")}))}else if(i)return new rn(f.thisDep,f.contextDep,f.propDep,(function(e,t){return t.def(e.shared.vao+\".currentVAO?\"+e.shared.vao+\".currentVAO.instances:-1\")}));return null}var d=l(hr,!0),m=function(){if(mr in r){var e=r[mr];return a.primitive=e,_.commandParameter(e,ie,\"invalid primitve\",t.commandStr),an((function(t,r){return ie[e]}))}if(mr in n){var o=n[mr];return on(o,(function(e,t){var r=e.constants.primTypes,n=e.invoke(t,o);return _.optional((function(){e.assert(t,n+\" in \"+r,\"invalid primitive, must be one of \"+Object.keys(ie))})),t.def(r,\"[\",n,\"]\")}))}return u?nn(s)?s.value?an((function(e,t){return t.def(e.ELEMENTS,\".primType\")})):an((function(){return 4})):new rn(s.thisDep,s.contextDep,s.propDep,(function(e,t){var r=e.ELEMENTS;return t.def(r,\"?\",r,\".primType:\",4)})):i?new rn(f.thisDep,f.contextDep,f.propDep,(function(e,t){return t.def(e.shared.vao+\".currentVAO?\"+e.shared.vao+\".currentVAO.primitive:4\")})):null}(),p=function(){if(pr in r){var e=0|r[pr];return a.count=e,_.command(\"number\"==typeof e&&e>=0,\"invalid vertex count\",t.commandStr),an((function(){return e}))}if(pr in n){var o=n[pr];return on(o,(function(e,t){var r=e.invoke(t,o);return _.optional((function(){e.assert(t,\"typeof \"+r+'===\"number\"&&'+r+\">=0&&\"+r+\"===(\"+r+\"|0)\",\"invalid vertex count\")})),r}))}if(u){if(nn(s)){if(s)return d?new rn(d.thisDep,d.contextDep,d.propDep,(function(e,t){var r=t.def(e.ELEMENTS,\".vertCount-\",e.OFFSET);return _.optional((function(){e.assert(t,r+\">=0\",\"invalid vertex offset/element buffer too small\")})),r})):an((function(e,t){return t.def(e.ELEMENTS,\".vertCount\")}));var c=an((function(){return-1}));return _.optional((function(){c.MISSING=!0})),c}var l=new rn(s.thisDep||d.thisDep,s.contextDep||d.contextDep,s.propDep||d.propDep,(function(e,t){var r=e.ELEMENTS;return e.OFFSET?t.def(r,\"?\",r,\".vertCount-\",e.OFFSET,\":-1\"):t.def(r,\"?\",r,\".vertCount:-1\")}));return _.optional((function(){l.DYNAMIC=!0})),l}if(i){var m=new rn(f.thisDep,f.contextDep,f.propDep,(function(e,t){return t.def(e.shared.vao,\".currentVAO?\",e.shared.vao,\".currentVAO.count:-1\")}));return m}return null}(),h=l(br,!1);return{elements:s,primitive:m,count:p,instances:h,offset:d,vao:f,vaoActive:i,elementsActive:u,static:a}}(e,d),A=function(e,t){var r=e.static,n=e.dynamic,i={};return k.forEach((function(e){var o=E(e);function f(t,a){if(e in r){var f=t(r[e]);i[o]=an((function(){return f}))}else if(e in n){var u=n[e];i[o]=on(u,(function(e,t){return a(e,t,e.invoke(t,u))}))}}switch(e){case Nt:case It:case Vt:case er:case Mt:case ir:case Xt:case Kt:case Jt:case Gt:return f((function(r){return _.commandType(r,\"boolean\",e,t.commandStr),r}),(function(t,r,n){return _.optional((function(){t.assert(r,\"typeof \"+n+'===\"boolean\"',\"invalid flag \"+e,t.commandStr)})),n}));case Wt:return f((function(r){return _.commandParameter(r,$r,\"invalid \"+e,t.commandStr),$r[r]}),(function(t,r,n){var a=t.constants.compareFuncs;return _.optional((function(){t.assert(r,n+\" in \"+a,\"invalid \"+e+\", must be one of \"+Object.keys($r))})),r.def(a,\"[\",n,\"]\")}));case Ut:return f((function(e){return _.command(me(e)&&2===e.length&&\"number\"==typeof e[0]&&\"number\"==typeof e[1]&&e[0]<=e[1],\"depth range is 2d array\",t.commandStr),e}),(function(e,t,r){return _.optional((function(){e.assert(t,e.shared.isArrayLike+\"(\"+r+\")&&\"+r+\".length===2&&typeof \"+r+'[0]===\"number\"&&typeof '+r+'[1]===\"number\"&&'+r+\"[0]<=\"+r+\"[1]\",\"depth range must be a 2d array\")})),[t.def(\"+\",r,\"[0]\"),t.def(\"+\",r,\"[1]\")]}));case Rt:return f((function(e){_.commandType(e,\"object\",\"blend.func\",t.commandStr);var r=\"srcRGB\"in e?e.srcRGB:e.src,n=\"srcAlpha\"in e?e.srcAlpha:e.src,a=\"dstRGB\"in e?e.dstRGB:e.dst,i=\"dstAlpha\"in e?e.dstAlpha:e.dst;return _.commandParameter(r,Yr,o+\".srcRGB\",t.commandStr),_.commandParameter(n,Yr,o+\".srcAlpha\",t.commandStr),_.commandParameter(a,Yr,o+\".dstRGB\",t.commandStr),_.commandParameter(i,Yr,o+\".dstAlpha\",t.commandStr),_.command(-1===Xr.indexOf(r+\", \"+a),\"unallowed blending combination (srcRGB, dstRGB) = (\"+r+\", \"+a+\")\",t.commandStr),[Yr[r],Yr[a],Yr[n],Yr[i]]}),(function(t,r,n){var a=t.constants.blendFuncs;function i(i,o){var f=r.def('\"',i,o,'\" in ',n,\"?\",n,\".\",i,o,\":\",n,\".\",i);return _.optional((function(){t.assert(r,f+\" in \"+a,\"invalid \"+e+\".\"+i+o+\", must be one of \"+Object.keys(Yr))})),f}_.optional((function(){t.assert(r,n+\"&&typeof \"+n+'===\"object\"',\"invalid blend func, must be an object\")}));var o=i(\"src\",\"RGB\"),f=i(\"dst\",\"RGB\");_.optional((function(){var e=t.constants.invalidBlendCombinations;t.assert(r,e+\".indexOf(\"+o+'+\", \"+'+f+\") === -1 \",\"unallowed blending combination for (srcRGB, dstRGB)\")}));var u=r.def(a,\"[\",o,\"]\"),s=r.def(a,\"[\",i(\"src\",\"Alpha\"),\"]\");return[u,r.def(a,\"[\",f,\"]\"),s,r.def(a,\"[\",i(\"dst\",\"Alpha\"),\"]\")]}));case Lt:return f((function(r){return\"string\"==typeof r?(_.commandParameter(r,v,\"invalid \"+e,t.commandStr),[v[r],v[r]]):\"object\"==typeof r?(_.commandParameter(r.rgb,v,e+\".rgb\",t.commandStr),_.commandParameter(r.alpha,v,e+\".alpha\",t.commandStr),[v[r.rgb],v[r.alpha]]):void _.commandRaise(\"invalid blend.equation\",t.commandStr)}),(function(t,r,n){var a=t.constants.blendEquations,i=r.def(),o=r.def(),f=t.cond(\"typeof \",n,'===\"string\"');return _.optional((function(){function r(e,r,n){t.assert(e,n+\" in \"+a,\"invalid \"+r+\", must be one of \"+Object.keys(v))}r(f.then,e,n),t.assert(f.else,n+\"&&typeof \"+n+'===\"object\"',\"invalid \"+e),r(f.else,e+\".rgb\",n+\".rgb\"),r(f.else,e+\".alpha\",n+\".alpha\")})),f.then(i,\"=\",o,\"=\",a,\"[\",n,\"];\"),f.else(i,\"=\",a,\"[\",n,\".rgb];\",o,\"=\",a,\"[\",n,\".alpha];\"),r(f),[i,o]}));case Pt:return f((function(e){return _.command(me(e)&&4===e.length,\"blend.color must be a 4d array\",t.commandStr),V(4,(function(t){return+e[t]}))}),(function(e,t,r){return _.optional((function(){e.assert(t,e.shared.isArrayLike+\"(\"+r+\")&&\"+r+\".length===4\",\"blend.color must be a 4d array\")})),V(4,(function(e){return t.def(\"+\",r,\"[\",e,\"]\")}))}));case tr:return f((function(e){return _.commandType(e,\"number\",o,t.commandStr),0|e}),(function(e,t,r){return _.optional((function(){e.assert(t,\"typeof \"+r+'===\"number\"',\"invalid stencil.mask\")})),t.def(r,\"|0\")}));case rr:return f((function(r){_.commandType(r,\"object\",o,t.commandStr);var n=r.cmp||\"keep\",a=r.ref||0,i=\"mask\"in r?r.mask:-1;return _.commandParameter(n,$r,e+\".cmp\",t.commandStr),_.commandType(a,\"number\",e+\".ref\",t.commandStr),_.commandType(i,\"number\",e+\".mask\",t.commandStr),[$r[n],a,i]}),(function(e,t,r){var n=e.constants.compareFuncs;return _.optional((function(){function a(){e.assert(t,Array.prototype.join.call(arguments,\"\"),\"invalid stencil.func\")}a(r+\"&&typeof \",r,'===\"object\"'),a('!(\"cmp\" in ',r,\")||(\",r,\".cmp in \",n,\")\")})),[t.def('\"cmp\" in ',r,\"?\",n,\"[\",r,\".cmp]\",\":\",Qr),t.def(r,\".ref|0\"),t.def('\"mask\" in ',r,\"?\",r,\".mask|0:-1\")]}));case nr:case ar:return f((function(r){_.commandType(r,\"object\",o,t.commandStr);var n=r.fail||\"keep\",a=r.zfail||\"keep\",i=r.zpass||\"keep\";return _.commandParameter(n,Kr,e+\".fail\",t.commandStr),_.commandParameter(a,Kr,e+\".zfail\",t.commandStr),_.commandParameter(i,Kr,e+\".zpass\",t.commandStr),[e===ar?Nr:Hr,Kr[n],Kr[a],Kr[i]]}),(function(t,r,n){var a=t.constants.stencilOps;function i(i){return _.optional((function(){t.assert(r,'!(\"'+i+'\" in '+n+\")||(\"+n+\".\"+i+\" in \"+a+\")\",\"invalid \"+e+\".\"+i+\", must be one of \"+Object.keys(Kr))})),r.def('\"',i,'\" in ',n,\"?\",a,\"[\",n,\".\",i,\"]:\",Qr)}return _.optional((function(){t.assert(r,n+\"&&typeof \"+n+'===\"object\"',\"invalid \"+e)})),[e===ar?Nr:Hr,i(\"fail\"),i(\"zfail\"),i(\"zpass\")]}));case $t:return f((function(e){_.commandType(e,\"object\",o,t.commandStr);var r=0|e.factor,n=0|e.units;return _.commandType(r,\"number\",o+\".factor\",t.commandStr),_.commandType(n,\"number\",o+\".units\",t.commandStr),[r,n]}),(function(t,r,n){return _.optional((function(){t.assert(r,n+\"&&typeof \"+n+'===\"object\"',\"invalid \"+e)})),[r.def(n,\".factor|0\"),r.def(n,\".units|0\")]}));case qt:return f((function(e){var r=0;return\"front\"===e?r=Hr:\"back\"===e&&(r=Nr),_.command(!!r,o,t.commandStr),r}),(function(e,t,r){return _.optional((function(){e.assert(t,r+'===\"front\"||'+r+'===\"back\"',\"invalid cull.face\")})),t.def(r,'===\"front\"?',Hr,\":\",Nr)}));case Yt:return f((function(e){return _.command(\"number\"==typeof e&&e>=a.lineWidthDims[0]&&e<=a.lineWidthDims[1],\"invalid line width, must be a positive number between \"+a.lineWidthDims[0]+\" and \"+a.lineWidthDims[1],t.commandStr),e}),(function(e,t,r){return _.optional((function(){e.assert(t,\"typeof \"+r+'===\"number\"&&'+r+\">=\"+a.lineWidthDims[0]+\"&&\"+r+\"<=\"+a.lineWidthDims[1],\"invalid line width\")})),r}));case Qt:return f((function(e){return _.commandParameter(e,Zr,o,t.commandStr),Zr[e]}),(function(e,t,r){return _.optional((function(){e.assert(t,r+'===\"cw\"||'+r+'===\"ccw\"',\"invalid frontFace, must be one of cw,ccw\")})),t.def(r+'===\"cw\"?2304:'+qr)}));case Ht:return f((function(e){return _.command(me(e)&&4===e.length,\"color.mask must be length 4 array\",t.commandStr),e.map((function(e){return!!e}))}),(function(e,t,r){return _.optional((function(){e.assert(t,e.shared.isArrayLike+\"(\"+r+\")&&\"+r+\".length===4\",\"invalid color.mask\")})),V(4,(function(e){return\"!!\"+r+\"[\"+e+\"]\"}))}));case Zt:return f((function(e){_.command(\"object\"==typeof e&&e,o,t.commandStr);var r=\"value\"in e?e.value:1,n=!!e.invert;return _.command(\"number\"==typeof r&&r>=0&&r<=1,\"sample.coverage.value must be a number between 0 and 1\",t.commandStr),[r,n]}),(function(e,t,r){return _.optional((function(){e.assert(t,r+\"&&typeof \"+r+'===\"object\"',\"invalid sample.coverage\")})),[t.def('\"value\" in ',r,\"?+\",r,\".value:1\"),t.def(\"!!\",r,\".invert\")]}))}})),i}(e,d),S=function(e,t,n){var a=e.static,i=e.dynamic;function o(e){if(e in a){var t=r.id(a[e]);_.optional((function(){l.shader(Jr[e],t,_.guessCommand())}));var n=an((function(){return t}));return n.id=t,n}if(e in i){var o=i[e];return on(o,(function(t,r){var n=t.invoke(r,o),a=r.def(t.shared.strings,\".id(\",n,\")\");return _.optional((function(){r(t.shared.shader,\".shader(\",Jr[e],\",\",a,\",\",t.command,\");\")})),a}))}return null}var f,u=o(lr),s=o(cr),c=null;return nn(u)&&nn(s)?(c=l.program(s.id,u.id,null,n),f=an((function(e,t){return e.link(c)}))):f=new rn(u&&u.thisDep||s&&s.thisDep,u&&u.contextDep||s&&s.contextDep,u&&u.propDep||s&&s.propDep,(function(e,t){var r,n=e.shared.shader;r=u?u.append(e,t):t.def(n,\".\",lr);var a=n+\".program(\"+(s?s.append(e,t):t.def(n,\".\",cr))+\",\"+r;return _.optional((function(){a+=\",\"+e.command})),t.def(a+\")\")})),{frag:u,vert:s,progVar:f,program:c}}(e,0,h);function O(e){var t=x[e];t&&(A[e]=t)}O(fr),O(E(or));var T=Object.keys(A).length>0,D={framebuffer:y,draw:w,shader:S,state:A,dirty:T,scopeVAO:null,drawVAO:null,useVAO:!1,attributes:{}};if(D.profile=function(e){var t,r=e.static,n=e.dynamic;if(ur in r){var a=!!r[ur];(t=an((function(e,t){return a}))).enable=a}else if(ur in n){var i=n[ur];t=on(i,(function(e,t){return e.invoke(t,i)}))}return t}(e),D.uniforms=function(e,t){var r=e.static,n=e.dynamic,a={};return Object.keys(r).forEach((function(e){var n,i=r[e];if(\"number\"==typeof i||\"boolean\"==typeof i)n=an((function(){return i}));else if(\"function\"==typeof i){var o=i._reglType;\"texture2d\"===o||\"textureCube\"===o?n=an((function(e){return e.link(i)})):\"framebuffer\"===o||\"framebufferCube\"===o?(_.command(i.color.length>0,'missing color attachment for framebuffer sent to uniform \"'+e+'\"',t.commandStr),n=an((function(e){return e.link(i.color[0])}))):_.commandRaise('invalid data for uniform \"'+e+'\"',t.commandStr)}else me(i)?n=an((function(t){return t.global.def(\"[\",V(i.length,(function(r){return _.command(\"number\"==typeof i[r]||\"boolean\"==typeof i[r],\"invalid uniform \"+e,t.commandStr),i[r]})),\"]\")})):_.commandRaise('invalid or missing data for uniform \"'+e+'\"',t.commandStr);n.value=i,a[e]=n})),Object.keys(n).forEach((function(e){var t=n[e];a[e]=on(t,(function(e,r){return e.invoke(r,t)}))})),a}(f,d),D.drawVAO=D.scopeVAO=w.vao,!D.drawVAO&&S.program&&!h&&n.angle_instanced_arrays&&w.static.elements){var j=!0,C=S.program.attributes.map((function(e){var r=t.static[e];return j=j&&!!r,r}));if(j&&C.length>0){var z=c.getVAO(c.createVAO({attributes:C,elements:w.static.elements}));D.drawVAO=new rn(null,null,null,(function(e,t){return e.link(z)})),D.useVAO=!0}}return h?D.useVAO=!0:D.attributes=function(e,t){var n=e.static,a=e.dynamic,o={};return Object.keys(n).forEach((function(e){var a=n[e],f=r.id(e),u=new b;if(en(a))u.state=1,u.buffer=i.getBuffer(i.create(a,Sr,!1,!0)),u.type=0;else{var s=i.getBuffer(a);if(s)u.state=1,u.buffer=s,u.type=0;else if(_.command(\"object\"==typeof a&&a,\"invalid data for attribute \"+e,t.commandStr),\"constant\"in a){var c=a.constant;u.buffer=\"null\",u.state=2,\"number\"==typeof c?u.x=c:(_.command(me(c)&&c.length>0&&c.length<=4,\"invalid constant for attribute \"+e,t.commandStr),Bt.forEach((function(e,t){t=0,'invalid offset for attribute \"'+e+'\"',t.commandStr);var d=0|a.stride;_.command(d>=0&&d<256,'invalid stride for attribute \"'+e+'\", must be integer betweeen [0, 255]',t.commandStr);var m=0|a.size;_.command(!(\"size\"in a)||m>0&&m<=4,'invalid size for attribute \"'+e+'\", must be 1,2,3,4',t.commandStr);var p=!!a.normalized,h=0;\"type\"in a&&(_.commandParameter(a.type,X,\"invalid type for attribute \"+e,t.commandStr),h=X[a.type]);var v=0|a.divisor;_.optional((function(){\"divisor\"in a&&(_.command(0===v||g,'cannot specify divisor for attribute \"'+e+'\", instancing not supported',t.commandStr),_.command(v>=0,'invalid divisor for attribute \"'+e+'\"',t.commandStr));var r=t.commandStr,n=[\"buffer\",\"offset\",\"divisor\",\"normalized\",\"type\",\"size\",\"stride\"];Object.keys(a).forEach((function(t){_.command(n.indexOf(t)>=0,'unknown parameter \"'+t+'\" for attribute pointer \"'+e+'\" (valid parameters are '+n+\")\",r)}))})),u.buffer=s,u.state=1,u.size=m,u.normalized=p,u.type=h||s.dtype,u.offset=l,u.stride=d,u.divisor=v}}o[e]=an((function(e,t){var r=e.attribCache;if(f in r)return r[f];var n={isStream:!1};return Object.keys(u).forEach((function(e){n[e]=u[e]})),u.buffer&&(n.buffer=e.link(u.buffer),n.type=n.type||n.buffer+\".dtype\"),r[f]=n,n}))})),Object.keys(a).forEach((function(e){var t=a[e];o[e]=on(t,(function(r,n){var a=r.invoke(n,t),i=r.shared,o=r.constants,f=i.isBufferArgs,u=i.buffer;_.optional((function(){r.assert(n,a+\"&&(typeof \"+a+'===\"object\"||typeof '+a+'===\"function\")&&('+f+\"(\"+a+\")||\"+u+\".getBuffer(\"+a+\")||\"+u+\".getBuffer(\"+a+\".buffer)||\"+f+\"(\"+a+'.buffer)||(\"constant\" in '+a+\"&&(typeof \"+a+'.constant===\"number\"||'+i.isArrayLike+\"(\"+a+\".constant))))\",'invalid dynamic attribute \"'+e+'\"')}));var s={isStream:n.def(!1)},c=new b;c.state=1,Object.keys(c).forEach((function(e){s[e]=n.def(\"\"+c[e])}));var l=s.buffer,d=s.type;function m(e){n(s[e],\"=\",a,\".\",e,\"|0;\")}return n(\"if(\",f,\"(\",a,\")){\",s.isStream,\"=true;\",l,\"=\",u,\".createStream(\",Sr,\",\",a,\");\",d,\"=\",l,\".dtype;\",\"}else{\",l,\"=\",u,\".getBuffer(\",a,\");\",\"if(\",l,\"){\",d,\"=\",l,\".dtype;\",'}else if(\"constant\" in ',a,\"){\",s.state,\"=\",2,\";\",\"if(typeof \"+a+'.constant === \"number\"){',s[Bt[0]],\"=\",a,\".constant;\",Bt.slice(1).map((function(e){return s[e]})).join(\"=\"),\"=0;\",\"}else{\",Bt.map((function(e,t){return s[e]+\"=\"+a+\".constant.length>\"+t+\"?\"+a+\".constant[\"+t+\"]:0;\"})).join(\"\"),\"}}else{\",\"if(\",f,\"(\",a,\".buffer)){\",l,\"=\",u,\".createStream(\",Sr,\",\",a,\".buffer);\",\"}else{\",l,\"=\",u,\".getBuffer(\",a,\".buffer);\",\"}\",d,'=\"type\" in ',a,\"?\",o.glTypes,\"[\",a,\".type]:\",l,\".dtype;\",s.normalized,\"=!!\",a,\".normalized;\"),m(\"size\"),m(\"offset\"),m(\"stride\"),m(\"divisor\"),n(\"}}\"),n.exit(\"if(\",s.isStream,\"){\",u,\".destroyStream(\",l,\");\",\"}\"),s}))})),o}(t,d),D.context=function(e){var t=e.static,r=e.dynamic,n={};return Object.keys(t).forEach((function(e){var r=t[e];n[e]=an((function(e,t){return\"number\"==typeof r||\"boolean\"==typeof r?\"\"+r:e.link(r)}))})),Object.keys(r).forEach((function(e){var t=r[e];n[e]=on(t,(function(e,r){return e.invoke(r,t)}))})),n}(s),D}function P(e,t,r){var n=e.shared.context,a=e.scope();Object.keys(r).forEach((function(i){t.save(n,\".\"+i);var o=r[i].append(e,t);Array.isArray(o)?a(n,\".\",i,\"=[\",o.join(),\"];\"):a(n,\".\",i,\"=\",o,\";\")})),t(a)}function L(e,t,r,n){var a,i=e.shared,o=i.gl,f=i.framebuffer;y&&(a=t.def(i.extensions,\".webgl_draw_buffers\"));var u,s=e.constants,c=s.drawBuffer,l=s.backBuffer;u=r?r.append(e,t):t.def(f,\".next\"),n||t(\"if(\",u,\"!==\",f,\".cur){\"),t(\"if(\",u,\"){\",o,\".bindFramebuffer(\",36160,\",\",u,\".framebuffer);\"),y&&t(a,\".drawBuffersWEBGL(\",c,\"[\",u,\".colorAttachments.length]);\"),t(\"}else{\",o,\".bindFramebuffer(\",36160,\",null);\"),y&&t(a,\".drawBuffersWEBGL(\",l,\");\"),t(\"}\",f,\".cur=\",u,\";\"),n||t(\"}\")}function R(e,t,r){var n=e.shared,a=n.gl,i=e.current,o=e.next,f=n.current,u=n.next,s=e.cond(f,\".dirty\");k.forEach((function(t){var n,c,l=E(t);if(!(l in r.state))if(l in o){n=o[l],c=i[l];var d=V(w[l].length,(function(e){return s.def(n,\"[\",e,\"]\")}));s(e.cond(d.map((function(e,t){return e+\"!==\"+c+\"[\"+t+\"]\"})).join(\"||\")).then(a,\".\",O[l],\"(\",d,\");\",d.map((function(e,t){return c+\"[\"+t+\"]=\"+e})).join(\";\"),\";\"))}else{n=s.def(u,\".\",l);var m=e.cond(n,\"!==\",f,\".\",l);s(m),l in S?m(e.cond(n).then(a,\".enable(\",S[l],\");\").else(a,\".disable(\",S[l],\");\"),f,\".\",l,\"=\",n,\";\"):m(a,\".\",O[l],\"(\",n,\");\",f,\".\",l,\"=\",n,\";\")}})),0===Object.keys(r.state).length&&s(f,\".dirty=false;\"),t(s)}function M(e,t,r,n){var a=e.shared,i=e.current,o=a.current,f=a.gl;tn(Object.keys(r)).forEach((function(a){var u=r[a];if(!n||n(u)){var s=u.append(e,t);if(S[a]){var c=S[a];nn(u)?t(f,s?\".enable(\":\".disable(\",c,\");\"):t(e.cond(s).then(f,\".enable(\",c,\");\").else(f,\".disable(\",c,\");\")),t(o,\".\",a,\"=\",s,\";\")}else if(me(s)){var l=i[a];t(f,\".\",O[a],\"(\",s,\");\",s.map((function(e,t){return l+\"[\"+t+\"]=\"+e})).join(\";\"),\";\")}else t(f,\".\",O[a],\"(\",s,\");\",o,\".\",a,\"=\",s,\";\")}}))}function W(e,t){g&&(e.instancing=t.def(e.shared.extensions,\".angle_instanced_arrays\"))}function U(e,t,r,n,a){var i,o,f,u=e.shared,s=e.stats,c=u.current,l=u.timer,d=r.profile;function m(){return\"undefined\"==typeof performance?\"Date.now()\":\"performance.now()\"}function h(e){e(i=t.def(),\"=\",m(),\";\"),\"string\"==typeof a?e(s,\".count+=\",a,\";\"):e(s,\".count++;\"),p&&(n?e(o=t.def(),\"=\",l,\".getNumPendingQueries();\"):e(l,\".beginQuery(\",s,\");\"))}function b(e){e(s,\".cpuTime+=\",m(),\"-\",i,\";\"),p&&(n?e(l,\".pushScopeStats(\",o,\",\",l,\".getNumPendingQueries(),\",s,\");\"):e(l,\".endQuery();\"))}function v(e){var r=t.def(c,\".profile\");t(c,\".profile=\",e,\";\"),t.exit(c,\".profile=\",r,\";\")}if(d){if(nn(d))return void(d.enable?(h(t),b(t.exit),v(\"true\")):v(\"false\"));v(f=d.append(e,t))}else f=t.def(c,\".profile\");var g=e.block();h(g),t(\"if(\",f,\"){\",g,\"}\");var y=e.block();b(y),t.exit(\"if(\",f,\"){\",y,\"}\")}function G(e,t,r,n,a){var i=e.shared;n.forEach((function(n){var o,f=n.name,u=r.attributes[f];if(u){if(!a(u))return;o=u.append(e,t)}else{if(!a(fn))return;var s=e.scopeAttrib(f);_.optional((function(){e.assert(t,s+\".state\",\"missing attribute \"+f)})),o={},Object.keys(new b).forEach((function(e){o[e]=t.def(s,\".\",e)}))}!function(r,n,a){var o=i.gl,f=t.def(r,\".location\"),u=t.def(i.attributes,\"[\",f,\"]\"),s=a.state,c=a.buffer,l=[a.x,a.y,a.z,a.w],d=[\"buffer\",\"normalized\",\"offset\",\"stride\"];function m(){t(\"if(!\",u,\".buffer){\",o,\".enableVertexAttribArray(\",f,\");}\");var r,i=a.type;if(r=a.size?t.def(a.size,\"||\",n):n,t(\"if(\",u,\".type!==\",i,\"||\",u,\".size!==\",r,\"||\",d.map((function(e){return u+\".\"+e+\"!==\"+a[e]})).join(\"||\"),\"){\",o,\".bindBuffer(\",Sr,\",\",c,\".buffer);\",o,\".vertexAttribPointer(\",[f,r,i,a.normalized,a.stride,a.offset],\");\",u,\".type=\",i,\";\",u,\".size=\",r,\";\",d.map((function(e){return u+\".\"+e+\"=\"+a[e]+\";\"})).join(\"\"),\"}\"),g){var s=a.divisor;t(\"if(\",u,\".divisor!==\",s,\"){\",e.instancing,\".vertexAttribDivisorANGLE(\",[f,s],\");\",u,\".divisor=\",s,\";}\")}}function p(){t(\"if(\",u,\".buffer){\",o,\".disableVertexAttribArray(\",f,\");\",u,\".buffer=null;\",\"}if(\",Bt.map((function(e,t){return u+\".\"+e+\"!==\"+l[t]})).join(\"||\"),\"){\",o,\".vertexAttrib4f(\",f,\",\",l,\");\",Bt.map((function(e,t){return u+\".\"+e+\"=\"+l[t]+\";\"})).join(\"\"),\"}\")}1===s?m():2===s?p():(t(\"if(\",s,\"===\",1,\"){\"),m(),t(\"}else{\"),p(),t(\"}\"))}(e.link(n),function(e){switch(e){case Tr:case zr:case Ir:return 2;case Dr:case Fr:case Pr:return 3;case jr:case Br:case Lr:return 4;default:return 1}}(n.info.type),o)}))}function H(e,t,n,a,i,o){for(var f,u=e.shared,s=u.gl,c={},l=0;l1){if(!b)continue;var v=m.replace(\"[0]\",\"\");if(c[v])continue;c[v]=1}var g,y=e.link(d)+\".location\";if(b){if(!i(b))continue;if(nn(b)){var x=b.value;if(_.command(null!=x,'missing uniform \"'+m+'\"',e.commandStr),p===Ur||p===Gr){_.command(\"function\"==typeof x&&(p===Ur&&(\"texture2d\"===x._reglType||\"framebuffer\"===x._reglType)||p===Gr&&(\"textureCube\"===x._reglType||\"framebufferCube\"===x._reglType)),\"invalid texture for uniform \"+m,e.commandStr);var w=e.link(x._texture||x.color[0]._texture);t(s,\".uniform1i(\",y,\",\",w+\".bind());\"),t.exit(w,\".unbind();\")}else if(p===Rr||p===Mr||p===Wr){_.optional((function(){_.command(me(x),\"invalid matrix for uniform \"+m,e.commandStr),_.command(p===Rr&&4===x.length||p===Mr&&9===x.length||p===Wr&&16===x.length,\"invalid length for matrix uniform \"+m,e.commandStr)}));var A=e.global.def(\"new Float32Array([\"+Array.prototype.slice.call(x)+\"])\"),k=2;p===Mr?k=3:p===Wr&&(k=4),t(s,\".uniformMatrix\",k,\"fv(\",y,\",false,\",A,\");\")}else{switch(p){case Er:1===h?_.commandType(x,\"number\",\"uniform \"+m,e.commandStr):_.command(me(x)&&x.length===h,\"uniform \"+m,e.commandStr),f=\"1f\";break;case Tr:_.command(me(x)&&x.length&&x.length%2==0&&x.length<=2*h,\"uniform \"+m,e.commandStr),f=\"2f\";break;case Dr:_.command(me(x)&&x.length&&x.length%3==0&&x.length<=3*h,\"uniform \"+m,e.commandStr),f=\"3f\";break;case jr:_.command(me(x)&&x.length&&x.length%4==0&&x.length<=4*h,\"uniform \"+m,e.commandStr),f=\"4f\";break;case Vr:1===h?_.commandType(x,\"boolean\",\"uniform \"+m,e.commandStr):_.command(me(x)&&x.length===h,\"uniform \"+m,e.commandStr),f=\"1i\";break;case Cr:1===h?_.commandType(x,\"number\",\"uniform \"+m,e.commandStr):_.command(me(x)&&x.length===h,\"uniform \"+m,e.commandStr),f=\"1i\";break;case Ir:case zr:_.command(me(x)&&x.length&&x.length%2==0&&x.length<=2*h,\"uniform \"+m,e.commandStr),f=\"2i\";break;case Pr:case Fr:_.command(me(x)&&x.length&&x.length%3==0&&x.length<=3*h,\"uniform \"+m,e.commandStr),f=\"3i\";break;case Lr:case Br:_.command(me(x)&&x.length&&x.length%4==0&&x.length<=4*h,\"uniform \"+m,e.commandStr),f=\"4i\"}h>1?(f+=\"v\",x=e.global.def(\"[\"+Array.prototype.slice.call(x)+\"]\")):x=me(x)?Array.prototype.slice.call(x):x,t(s,\".uniform\",f,\"(\",y,\",\",x,\");\")}continue}g=b.append(e,t)}else{if(!i(fn))continue;g=t.def(u.uniforms,\"[\",r.id(m),\"]\")}p===Ur?(_(!Array.isArray(g),\"must specify a scalar prop for textures\"),t(\"if(\",g,\"&&\",g,'._reglType===\"framebuffer\"){',g,\"=\",g,\".color[0];\",\"}\")):p===Gr&&(_(!Array.isArray(g),\"must specify a scalar prop for cube maps\"),t(\"if(\",g,\"&&\",g,'._reglType===\"framebufferCube\"){',g,\"=\",g,\".color[0];\",\"}\")),_.optional((function(){function r(r,n){e.assert(t,r,'bad data or missing for uniform \"'+m+'\". '+n)}function n(e,t){1===t&&_(!Array.isArray(g),\"must not specify an array type for uniform\"),r(\"Array.isArray(\"+g+\") && typeof \"+g+'[0]===\" '+e+'\" || typeof '+g+'===\"'+e+'\"',\"invalid type, expected \"+e)}function a(t,n,a){Array.isArray(g)?_(g.length&&g.length%t==0&&g.length<=t*a,\"must have length of \"+(1===a?\"\":\"n * \")+t):r(u.isArrayLike+\"(\"+g+\")&&\"+g+\".length && \"+g+\".length % \"+t+\" === 0 && \"+g+\".length<=\"+t*a,\"invalid vector, should have length of \"+(1===a?\"\":\"n * \")+t,e.commandStr)}function i(t){_(!Array.isArray(g),\"must not specify a value type\"),r(\"typeof \"+g+'===\"function\"&&'+g+'._reglType===\"texture'+(3553===t?\"2d\":\"Cube\")+'\"',\"invalid texture type\",e.commandStr)}switch(p){case Cr:n(\"number\",h);break;case zr:a(2,0,h);break;case Fr:a(3,0,h);break;case Br:a(4,0,h);break;case Er:n(\"number\",h);break;case Tr:a(2,0,h);break;case Dr:a(3,0,h);break;case jr:a(4,0,h);break;case Vr:n(\"boolean\",h);break;case Ir:a(2,0,h);break;case Pr:a(3,0,h);break;case Lr:case Rr:a(4,0,h);break;case Mr:a(9,0,h);break;case Wr:a(16,0,h);break;case Ur:i(3553);break;case Gr:i(34067)}}));var S=1;switch(p){case Ur:case Gr:var O=t.def(g,\"._texture\");t(s,\".uniform1i(\",y,\",\",O,\".bind());\"),t.exit(O,\".unbind();\");continue;case Cr:case Vr:f=\"1i\";break;case zr:case Ir:f=\"2i\",S=2;break;case Fr:case Pr:f=\"3i\",S=3;break;case Br:case Lr:f=\"4i\",S=4;break;case Er:f=\"1f\";break;case Tr:f=\"2f\",S=2;break;case Dr:f=\"3f\",S=3;break;case jr:f=\"4f\",S=4;break;case Rr:f=\"Matrix2fv\";break;case Mr:f=\"Matrix3fv\";break;case Wr:f=\"Matrix4fv\"}if(-1===f.indexOf(\"Matrix\")&&h>1&&(f+=\"v\",S=1),\"M\"===f.charAt(0)){t(s,\".uniform\",f,\"(\",y,\",\");var E=Math.pow(p-Rr+2,2),T=e.global.def(\"new Float32Array(\",E,\")\");Array.isArray(g)?t(\"false,(\",V(E,(function(e){return T+\"[\"+e+\"]=\"+g[e]})),\",\",T,\")\"):t(\"false,(Array.isArray(\",g,\")||\",g,\" instanceof Float32Array)?\",g,\":(\",V(E,(function(e){return T+\"[\"+e+\"]=\"+g+\"[\"+e+\"]\"})),\",\",T,\")\"),t(\");\")}else if(S>1){for(var D=[],j=[],C=0;C=0\",\"missing vertex count\")}))):(a=u.def(o,\".\",pr),_.optional((function(){e.assert(u,a+\">=0\",\"missing vertex count\")}))),a}();if(\"number\"==typeof p){if(0===p)return}else r(\"if(\",p,\"){\"),r.exit(\"}\");g&&(c=s(br),l=e.instancing);var h=u+\".type\",b=f.elements&&nn(f.elements)&&!f.vaoActive;function v(){function e(){r(l,\".drawElementsInstancedANGLE(\",[d,p,h,m+\"<<((\"+h+\"-5121)>>1)\",c],\");\")}function t(){r(l,\".drawArraysInstancedANGLE(\",[d,m,p,c],\");\")}u&&\"null\"!==u?b?e():(r(\"if(\",u,\"){\"),e(),r(\"}else{\"),t(),r(\"}\")):t()}function y(){function e(){r(i+\".drawElements(\"+[d,p,h,m+\"<<((\"+h+\"-5121)>>1)\"]+\");\")}function t(){r(i+\".drawArrays(\"+[d,m,p]+\");\")}u&&\"null\"!==u?b?e():(r(\"if(\",u,\"){\"),e(),r(\"}else{\"),t(),r(\"}\")):t()}g&&(\"number\"!=typeof c||c>=0)?\"string\"==typeof c?(r(\"if(\",c,\">0){\"),v(),r(\"}else if(\",c,\"<0){\"),y(),r(\"}\")):v():y()}function q(e,t,r,n,a){var i=B(),o=i.proc(\"body\",a);return _.optional((function(){i.commandStr=t.commandStr,i.command=i.link(t.commandStr)})),g&&(i.instancing=o.def(i.shared.extensions,\".angle_instanced_arrays\")),e(i,o,r,n),i.compile().body}function Q(e,t,r,n){W(e,t),r.useVAO?r.drawVAO?t(e.shared.vao,\".setVAO(\",r.drawVAO.append(e,t),\");\"):t(e.shared.vao,\".setVAO(\",e.shared.vao,\".targetVAO);\"):(t(e.shared.vao,\".setVAO(null);\"),G(e,t,r,n.attributes,(function(){return!0}))),H(e,t,r,n.uniforms,(function(){return!0}),!1),N(e,t,t,r)}function Y(e,t,r,n){function a(){return!0}e.batchId=\"a1\",W(e,t),G(e,t,r,n.attributes,a),H(e,t,r,n.uniforms,a,!1),N(e,t,t,r)}function $(e,t,r,n){W(e,t);var a=r.contextDep,i=t.def(),o=t.def();e.shared.props=o,e.batchId=i;var f=e.scope(),u=e.scope();function s(e){return e.contextDep&&a||e.propDep}function c(e){return!s(e)}if(t(f.entry,\"for(\",i,\"=0;\",i,\"<\",\"a1\",\";++\",i,\"){\",o,\"=\",\"a0\",\"[\",i,\"];\",u,\"}\",f.exit),r.needsContext&&P(e,u,r.context),r.needsFramebuffer&&L(e,u,r.framebuffer),M(e,u,r.state,s),r.profile&&s(r.profile)&&U(e,u,r,!1,!0),n)r.useVAO?r.drawVAO?s(r.drawVAO)?u(e.shared.vao,\".setVAO(\",r.drawVAO.append(e,u),\");\"):f(e.shared.vao,\".setVAO(\",r.drawVAO.append(e,f),\");\"):f(e.shared.vao,\".setVAO(\",e.shared.vao,\".targetVAO);\"):(f(e.shared.vao,\".setVAO(null);\"),G(e,f,r,n.attributes,c),G(e,u,r,n.attributes,s)),H(e,f,r,n.uniforms,c,!1),H(e,u,r,n.uniforms,s,!0),N(e,f,u,r);else{var l=e.global.def(\"{}\"),d=r.shader.progVar.append(e,u),m=u.def(d,\".id\"),p=u.def(l,\"[\",m,\"]\");u(e.shared.gl,\".useProgram(\",d,\".program);\",\"if(!\",p,\"){\",p,\"=\",l,\"[\",m,\"]=\",e.link((function(t){return q(Y,e,r,t,2)})),\"(\",d,\");}\",p,\".call(this,a0[\",i,\"],\",i,\");\")}}function K(e,t,r){var n=t.static[r];if(n&&function(e){if(\"object\"==typeof e&&!me(e)){for(var t=Object.keys(e),r=0;r0&&r(e.shared.current,\".dirty=true;\"),e.shared.vao&&r(e.shared.vao,\".setVAO(null);\")}(f,u),function(e,t){var n=e.proc(\"scope\",3);e.batchId=\"a2\";var a=e.shared,i=a.current;function o(r){var i=t.shader[r];i&&n.set(a.shader,\".\"+r,i.append(e,n))}P(e,n,t.context),t.framebuffer&&t.framebuffer.append(e,n),tn(Object.keys(t.state)).forEach((function(r){var i=t.state[r].append(e,n);me(i)?i.forEach((function(t,a){n.set(e.next[r],\"[\"+a+\"]\",t)})):n.set(a.next,\".\"+r,i)})),U(e,n,t,!0,!0),[dr,hr,pr,br,mr].forEach((function(r){var i=t.draw[r];i&&n.set(a.draw,\".\"+r,\"\"+i.append(e,n))})),Object.keys(t.uniforms).forEach((function(i){var o=t.uniforms[i].append(e,n);Array.isArray(o)&&(o=\"[\"+o.join()+\"]\"),n.set(a.uniforms,\"[\"+r.id(i)+\"]\",o)})),Object.keys(t.attributes).forEach((function(r){var a=t.attributes[r].append(e,n),i=e.scopeAttrib(r);Object.keys(new b).forEach((function(e){n.set(i,\".\"+e,a[e])}))})),t.scopeVAO&&n.set(a.vao,\".targetVAO\",t.scopeVAO.append(e,n)),o(cr),o(lr),Object.keys(t.state).length>0&&(n(i,\".dirty=true;\"),n.exit(i,\".dirty=true;\")),n(\"a1(\",e.shared.context,\",a0,\",e.batchId,\");\")}(f,u),function(e,t){var r=e.proc(\"batch\",2);e.batchId=\"0\",W(e,r);var n=!1,a=!0;Object.keys(t.context).forEach((function(e){n=n||t.context[e].propDep})),n||(P(e,r,t.context),a=!1);var i=t.framebuffer,o=!1;function f(e){return e.contextDep&&n||e.propDep}i?(i.propDep?n=o=!0:i.contextDep&&n&&(o=!0),o||L(e,r,i)):L(e,r,null),t.state.viewport&&t.state.viewport.propDep&&(n=!0),R(e,r,t),M(e,r,t.state,(function(e){return!f(e)})),t.profile&&f(t.profile)||U(e,r,t,!1,\"a1\"),t.contextDep=n,t.needsContext=a,t.needsFramebuffer=o;var u=t.shader.progVar;if(u.contextDep&&n||u.propDep)$(e,r,t,null);else{var s=u.append(e,r);if(r(e.shared.gl,\".useProgram(\",s,\".program);\"),t.shader.program)$(e,r,t,t.shader.program);else{r(e.shared.vao,\".setVAO(null);\");var c=e.global.def(\"{}\"),l=r.def(s,\".id\"),d=r.def(c,\"[\",l,\"]\");r(e.cond(d).then(d,\".call(this,a0,a1);\").else(d,\"=\",c,\"[\",l,\"]=\",e.link((function(r){return q($,e,t,r,2)})),\"(\",s,\");\",d,\".call(this,a0,a1);\"))}}Object.keys(t.state).length>0&&r(e.shared.current,\".dirty=true;\"),e.shared.vao&&r(e.shared.vao,\".setVAO(null);\")}(f,u),t(f.compile(),{destroy:function(){u.shader.program.destroy()}})}}}var sn=function(e,t){if(!t.ext_disjoint_timer_query)return null;var r=[];function n(e){r.push(e)}var a=[];function i(){this.startQueryIndex=-1,this.endQueryIndex=-1,this.sum=0,this.stats=null}var o=[];function f(e){o.push(e)}var u=[];function s(e,t,r){var n=o.pop()||new i;n.startQueryIndex=e,n.endQueryIndex=t,n.sum=0,n.stats=r,u.push(n)}var c=[],l=[];return{beginQuery:function(e){var n=r.pop()||t.ext_disjoint_timer_query.createQueryEXT();t.ext_disjoint_timer_query.beginQueryEXT(35007,n),a.push(n),s(a.length-1,a.length,e)},endQuery:function(){t.ext_disjoint_timer_query.endQueryEXT(35007)},pushScopeStats:s,update:function(){var e,r,i=a.length;if(0!==i){l.length=Math.max(l.length,i+1),c.length=Math.max(c.length,i+1),c[0]=0,l[0]=0;var o=0;for(e=0,r=0;r0)if(Array.isArray(r[0])){f=J(r);for(var c=1,l=1;l0)if(\"number\"==typeof t[0]){var i=L.allocType(d.dtype,t.length);ne(i,t),p(i,a),L.freeType(i)}else if(Array.isArray(t[0])||e(t[0])){n=J(t);var o=K(t,n,d.dtype);p(o,a),L.freeType(o)}else _.raise(\"invalid buffer data\")}else if(G(t)){n=t.shape;var f=t.stride,u=0,s=0,c=0,l=0;1===n.length?(u=n[0],s=1,c=f[0],l=0):2===n.length?(u=n[0],s=n[1],c=f[0],l=f[1]):_.raise(\"invalid shape\");var h=Array.isArray(t.data)?d.dtype:re(t.data),b=L.allocType(h,u*s);ae(b,t.data,u,s,c,l,t.offset),p(b,a),L.freeType(b)}else _.raise(\"invalid data for buffer subdata\");return m},n.profile&&(m.stats=d.stats),m.destroy=function(){l(d)},m},createStream:function(e,t){var r=u.pop();return r||(r=new f(e)),r.bind(),c(r,t,35040,0,1,!1),r},destroyStream:function(e){u.push(e)},clear:function(){H(o).forEach(l),u.forEach(l)},getBuffer:function(e){return e&&e._buffer instanceof f?e._buffer:null},restore:function(){H(o).forEach((function(e){e.buffer=t.createBuffer(),t.bindBuffer(e.type,e.buffer),t.bufferData(e.type,e.persistentData||e.byteLength,e.usage)}))},_initBuffer:c}}(a,l,n,(function(e){return A.destroyBuffer(e)})),w=function(t,r,n,a){var i={},o=0,f={uint8:oe,uint16:fe};function u(e){this.id=o++,i[this.id]=this,this.buffer=e,this.primType=4,this.vertCount=0,this.type=0}r.oes_element_index_uint&&(f.uint32=ue),u.prototype.bind=function(){this.buffer.bind()};var s=[];function c(a,i,o,f,u,s,c){var l;if(a.buffer.bind(),i){var d=c;c||e(i)&&(!G(i)||e(i.data))||(d=r.oes_element_index_uint?ue:fe),n._initBuffer(a.buffer,i,o,d,3)}else t.bufferData(se,s,o),a.buffer.dtype=l||oe,a.buffer.usage=o,a.buffer.dimension=3,a.buffer.byteLength=s;if(l=c,!c){switch(a.buffer.dtype){case oe:case 5120:l=oe;break;case fe:case 5122:l=fe;break;case ue:case 5124:l=ue;break;default:_.raise(\"unsupported type for element array\")}a.buffer.dtype=l}a.type=l,_(l!==ue||!!r.oes_element_index_uint,\"32 bit element buffers not supported, enable oes_element_index_uint first\");var m=u;m<0&&(m=a.buffer.byteLength,l===fe?m>>=1:l===ue&&(m>>=2)),a.vertCount=m;var p=f;if(f<0){p=4;var h=a.buffer.dimension;1===h&&(p=0),2===h&&(p=1),3===h&&(p=4)}a.primType=p}function l(e){a.elementsCount--,_(null!==e.buffer,\"must not double destroy elements\"),delete i[e.id],e.buffer.destroy(),e.buffer=null}return{create:function(t,r){var i=n.create(null,se,!0),o=new u(i._buffer);function s(t){if(t)if(\"number\"==typeof t)i(t),o.primType=4,o.vertCount=0|t,o.type=oe;else{var r=null,n=35044,a=-1,u=-1,l=0,d=0;Array.isArray(t)||e(t)||G(t)?r=t:(_.type(t,\"object\",\"invalid arguments for elements\"),\"data\"in t&&(r=t.data,_(Array.isArray(r)||e(r)||G(r),\"invalid data for element buffer\")),\"usage\"in t&&(_.parameter(t.usage,$,\"invalid element buffer usage\"),n=$[t.usage]),\"primitive\"in t&&(_.parameter(t.primitive,ie,\"invalid element buffer primitive\"),a=ie[t.primitive]),\"count\"in t&&(_(\"number\"==typeof t.count&&t.count>=0,\"invalid vertex count for elements\"),u=0|t.count),\"type\"in t&&(_.parameter(t.type,f,\"invalid buffer type\"),d=f[t.type]),\"length\"in t?l=0|t.length:(l=u,d===fe||5122===d?l*=2:d!==ue&&5124!==d||(l*=4))),c(o,r,n,a,u,l,d)}else i(),o.primType=4,o.vertCount=0,o.type=oe;return s}return a.elementsCount++,s(t),s._reglType=\"elements\",s._elements=o,s.subdata=function(e,t){return i.subdata(e,t),s},s.destroy=function(){l(o)},s},createStream:function(e){var t=s.pop();return t||(t=new u(n.create(null,se,!0,!1)._buffer)),c(t,e,35040,-1,-1,0,0),t},destroyStream:function(e){s.push(e)},getElements:function(e){return\"function\"==typeof e&&e._elements instanceof u?e._elements:null},clear:function(){H(i).forEach(l)}}}(a,d,x,l),A=function(t,r,n,a,i,o,f){for(var u=n.maxAttributes,s=new Array(u),c=0;c{for(var e=Object.keys(t),r=0;r=0,'invalid option for vao: \"'+e[r]+'\" valid options are '+Et)})),_(Array.isArray(a),\"attributes must be an array\")}_(a.length0,\"must specify at least one attribute\");var c={},l=n.attributes;l.length=a.length;for(var d=0;d=b.byteLength?m.subdata(b):(m.destroy(),n.buffers[d]=null)),n.buffers[d]||(m=n.buffers[d]=i.create(p,34962,!1,!0)),h.buffer=i.getBuffer(m),h.size=0|h.buffer.dimension,h.normalized=!1,h.type=h.buffer.dtype,h.offset=0,h.stride=0,h.divisor=0,h.state=1,c[d]=1):i.getBuffer(p)?(h.buffer=i.getBuffer(p),h.size=0|h.buffer.dimension,h.normalized=!1,h.type=h.buffer.dtype,h.offset=0,h.stride=0,h.divisor=0,h.state=1):i.getBuffer(p.buffer)?(h.buffer=i.getBuffer(p.buffer),h.size=0|(+p.size||h.buffer.dimension),h.normalized=!!p.normalized||!1,\"type\"in p?(_.parameter(p.type,X,\"invalid buffer type\"),h.type=X[p.type]):h.type=h.buffer.dtype,h.offset=0|(p.offset||0),h.stride=0|(p.stride||0),h.divisor=0|(p.divisor||0),h.state=1,_(h.size>=1&&h.size<=4,\"size must be between 1 and 4\"),_(h.offset>=0,\"invalid offset\"),_(h.stride>=0&&h.stride<=255,\"stride must be between 0 and 255\"),_(h.divisor>=0,\"divisor must be positive\"),_(!h.divisor||!!r.angle_instanced_arrays,\"ANGLE_instanced_arrays must be enabled to use divisor\")):\"x\"in p?(_(d>0,\"first attribute must not be a constant\"),h.x=+p.x||0,h.y=+p.y||0,h.z=+p.z||0,h.w=+p.w||0,h.state=2):_(!1,\"invalid attribute spec for location \"+d)}for(var v=0;v1)for(var v=0;v1&&(y=y.replace(\"[0]\",\"\")),u(b,new f(y,r.id(y),e.getUniformLocation(m,y),c))}var x=e.getProgramParameter(m,35721);a.profile&&(t.stats.attributesCount=x);var w=t.attributes;for(o=0;oe&&(e=t.stats.uniformsCount)})),e},n.getMaxAttributesCount=function(){var e=0;return l.forEach((function(t){t.stats.attributesCount>e&&(e=t.stats.attributesCount)})),e}),{clear:function(){var t=e.deleteShader.bind(e);H(i).forEach(t),i={},H(o).forEach(t),o={},l.forEach((function(t){e.deleteProgram(t.program)})),l.length=0,c={},n.shaderCount=0},program:function(r,a,f,u){_.command(r>=0,\"missing vertex shader\",f),_.command(a>=0,\"missing fragment shader\",f);var s=c[a];s||(s=c[a]={});var d=s[r];if(d&&(d.refCount++,!u))return d;var h=new m(a,r);return n.shaderCount++,p(h,f,u),d||(s[r]=h),l.push(h),t(h,{destroy:function(){if(h.refCount--,h.refCount<=0){e.deleteProgram(h.program);var t=l.indexOf(h);l.splice(t,1),n.shaderCount--}s[h.vertId].refCount<=0&&(e.deleteShader(o[h.vertId]),delete o[h.vertId],delete c[h.fragId][h.vertId]),Object.keys(c[h.fragId]).length||(e.deleteShader(i[h.fragId]),delete i[h.fragId],delete c[h.fragId])}})},restore:function(){i={},o={};for(var e=0;e=2,\"invalid renderbuffer shape\"),f=0|m[0],u=0|m[1]}else\"radius\"in d&&(f=u=0|d.radius),\"width\"in d&&(f=0|d.width),\"height\"in d&&(u=0|d.height);\"format\"in d&&(_.parameter(d.format,i,\"invalid renderbuffer format\"),s=i[d.format])}else\"number\"==typeof t?(f=0|t,u=\"number\"==typeof n?0|n:f):t?_.raise(\"invalid arguments to renderbuffer constructor\"):f=u=1;if(_(f>0&&u>0&&f<=r.maxRenderbufferSize&&u<=r.maxRenderbufferSize,\"invalid renderbuffer size\"),f!==c.width||u!==c.height||s!==c.format)return l.width=c.width=f,l.height=c.height=u,c.format=s,e.bindRenderbuffer(mt,c.renderbuffer),e.renderbufferStorage(mt,s,f,u),_(0===e.getError(),\"invalid render buffer format\"),a.profile&&(c.stats.size=bt(c.format,c.width,c.height)),l.format=o[c.format],l}return u[c.id]=c,n.renderbufferCount++,l(t,f),l.resize=function(t,n){var i=0|t,o=0|n||i;return i===c.width&&o===c.height||(_(i>0&&o>0&&i<=r.maxRenderbufferSize&&o<=r.maxRenderbufferSize,\"invalid renderbuffer size\"),l.width=c.width=i,l.height=c.height=o,e.bindRenderbuffer(mt,c.renderbuffer),e.renderbufferStorage(mt,c.format,i,o),_(0===e.getError(),\"invalid render buffer format\"),a.profile&&(c.stats.size=bt(c.format,c.width,c.height))),l},l._reglType=\"renderbuffer\",l._renderbuffer=c,a.profile&&(l.stats=c.stats),l.destroy=function(){c.decRef()},l},clear:function(){H(u).forEach(c)},restore:function(){H(u).forEach((function(t){t.renderbuffer=e.createRenderbuffer(),e.bindRenderbuffer(mt,t.renderbuffer),e.renderbufferStorage(mt,t.format,t.width,t.height)})),e.bindRenderbuffer(mt,null)}}}(a,d,y,l,n),E=function(e,r,n,a,i,o){var f={cur:null,next:null,dirty:!1,setFBO:null},u=[\"rgba\"],s=[\"rgba4\",\"rgb565\",\"rgb5 a1\"];r.ext_srgb&&s.push(\"srgba\"),r.ext_color_buffer_half_float&&s.push(\"rgba16f\",\"rgb16f\"),r.webgl_color_buffer_float&&s.push(\"rgba32f\");var c=[\"uint8\"];function l(e,t,r){this.target=e,this.texture=t,this.renderbuffer=r;var n=0,a=0;t?(n=t.width,a=t.height):r&&(n=r.width,a=r.height),this.width=n,this.height=a}function d(e){e&&(e.texture&&e.texture._texture.decRef(),e.renderbuffer&&e.renderbuffer._renderbuffer.decRef())}function m(e,t,r){if(e)if(e.texture){var n=e.texture._texture,a=Math.max(1,n.width),i=Math.max(1,n.height);_(a===t&&i===r,\"inconsistent width/height for supplied texture\"),n.refCount+=1}else{var o=e.renderbuffer._renderbuffer;_(o.width===t&&o.height===r,\"inconsistent width/height for renderbuffer\"),o.refCount+=1}}function p(t,r){r&&(r.texture?e.framebufferTexture2D(vt,t,r.target,r.texture._texture.texture,0):e.framebufferRenderbuffer(vt,t,gt,r.renderbuffer._renderbuffer.renderbuffer))}function h(e){var t=yt,r=null,n=null,a=e;\"object\"==typeof e&&(a=e.data,\"target\"in e&&(t=0|e.target)),_.type(a,\"function\",\"invalid attachment data\");var i=a._reglType;return\"texture2d\"===i?(r=a,_(t===yt)):\"textureCube\"===i?(r=a,_(t>=xt&&t<34075,\"invalid cube map target\")):\"renderbuffer\"===i?(n=a,t=gt):_.raise(\"invalid regl object for attachment\"),new l(t,r,n)}function b(e,t,r,n,o){if(r){var f=a.create2D({width:e,height:t,format:n,type:o});return f._texture.refCount=0,new l(yt,f,null)}var u=i.create({width:e,height:t,format:n});return u._renderbuffer.refCount=0,new l(gt,null,u)}function v(e){return e&&(e.texture||e.renderbuffer)}function g(e,t,r){e&&(e.texture?e.texture.resize(t,r):e.renderbuffer&&e.renderbuffer.resize(t,r),e.width=t,e.height=r)}r.oes_texture_half_float&&c.push(\"half float\",\"float16\"),r.oes_texture_float&&c.push(\"float\",\"float32\");var y=0,x={};function w(){this.id=y++,x[this.id]=this,this.framebuffer=e.createFramebuffer(),this.width=0,this.height=0,this.colorAttachments=[],this.depthAttachment=null,this.stencilAttachment=null,this.depthStencilAttachment=null}function A(e){e.colorAttachments.forEach(d),d(e.depthAttachment),d(e.stencilAttachment),d(e.depthStencilAttachment)}function k(t){var r=t.framebuffer;_(r,\"must not double destroy framebuffer\"),e.deleteFramebuffer(r),t.framebuffer=null,o.framebufferCount--,delete x[t.id]}function S(t){var r;e.bindFramebuffer(vt,t.framebuffer);var a=t.colorAttachments;for(r=0;r=2,\"invalid shape for framebuffer\"),o=z[0],d=z[1]}else\"radius\"in C&&(o=d=C.radius),\"width\"in C&&(o=C.width),\"height\"in C&&(d=C.height);(\"color\"in C||\"colors\"in C)&&(y=C.color||C.colors,Array.isArray(y)&&_(1===y.length||r.webgl_draw_buffers,\"multiple render targets not supported\")),y||(\"colorCount\"in C&&(O=0|C.colorCount,_(O>0,\"invalid color buffer count\")),\"colorTexture\"in C&&(x=!!C.colorTexture,w=\"rgba4\"),\"colorType\"in C&&(k=C.colorType,x?(_(r.oes_texture_float||!(\"float\"===k||\"float32\"===k),\"you must enable OES_texture_float in order to use floating point framebuffer objects\"),_(r.oes_texture_half_float||!(\"half float\"===k||\"float16\"===k),\"you must enable OES_texture_half_float in order to use 16-bit floating point framebuffer objects\")):\"half float\"===k||\"float16\"===k?(_(r.ext_color_buffer_half_float,\"you must enable EXT_color_buffer_half_float to use 16-bit render buffers\"),w=\"rgba16f\"):\"float\"!==k&&\"float32\"!==k||(_(r.webgl_color_buffer_float,\"you must enable WEBGL_color_buffer_float in order to use 32-bit floating point renderbuffers\"),w=\"rgba32f\"),_.oneOf(k,c,\"invalid color type\")),\"colorFormat\"in C&&(w=C.colorFormat,u.indexOf(w)>=0?x=!0:s.indexOf(w)>=0?x=!1:_.optional((function(){x?_.oneOf(C.colorFormat,u,\"invalid color format for texture\"):_.oneOf(C.colorFormat,s,\"invalid color format for renderbuffer\")})))),(\"depthTexture\"in C||\"depthStencilTexture\"in C)&&(j=!(!C.depthTexture&&!C.depthStencilTexture),_(!j||r.webgl_depth_texture,\"webgl_depth_texture extension not supported\")),\"depth\"in C&&(\"boolean\"==typeof C.depth?p=C.depth:(E=C.depth,g=!1)),\"stencil\"in C&&(\"boolean\"==typeof C.stencil?g=C.stencil:(T=C.stencil,p=!1)),\"depthStencil\"in C&&(\"boolean\"==typeof C.depthStencil?p=g=C.depthStencil:(D=C.depthStencil,p=!1,g=!1))}else o=d=1;var F=null,B=null,V=null,I=null;if(Array.isArray(y))F=y.map(h);else if(y)F=[h(y)];else for(F=new Array(O),a=0;a=0||F[a].renderbuffer&&kt.indexOf(F[a].renderbuffer._renderbuffer.format)>=0,\"framebuffer color attachment \"+a+\" is invalid\"),F[a]&&F[a].texture){var L=At[F[a].texture._texture.format]*_t[F[a].texture._texture.type];null===P?P=L:_(P===L,\"all color attachments much have the same number of bits per pixel.\")}return m(B,o,d),_(!B||B.texture&&6402===B.texture._texture.format||B.renderbuffer&&33189===B.renderbuffer._renderbuffer.format,\"invalid depth attachment for framebuffer object\"),m(V,o,d),_(!V||V.renderbuffer&&36168===V.renderbuffer._renderbuffer.format,\"invalid stencil attachment for framebuffer object\"),m(I,o,d),_(!I||I.texture&&34041===I.texture._texture.format||I.renderbuffer&&34041===I.renderbuffer._renderbuffer.format,\"invalid depth-stencil attachment for framebuffer object\"),A(i),i.width=o,i.height=d,i.colorAttachments=F,i.depthAttachment=B,i.stencilAttachment=V,i.depthStencilAttachment=I,l.color=F.map(v),l.depth=v(B),l.stencil=v(V),l.depthStencil=v(I),l.width=i.width,l.height=i.height,S(i),l}return o.framebufferCount++,l(e,a),t(l,{resize:function(e,t){_(f.next!==i,\"can not resize a framebuffer which is currently in use\");var r=Math.max(0|e,1),n=Math.max(0|t||r,1);if(r===i.width&&n===i.height)return l;for(var a=i.colorAttachments,o=0;o=2,\"invalid shape for framebuffer\"),_(g[0]===g[1],\"cube framebuffer must be square\"),d=g[0]}else\"radius\"in v&&(d=0|v.radius),\"width\"in v?(d=0|v.width,\"height\"in v&&_(v.height===d,\"must be square\")):\"height\"in v&&(d=0|v.height);(\"color\"in v||\"colors\"in v)&&(m=v.color||v.colors,Array.isArray(m)&&_(1===m.length||r.webgl_draw_buffers,\"multiple render targets not supported\")),m||(\"colorCount\"in v&&(b=0|v.colorCount,_(b>0,\"invalid color buffer count\")),\"colorType\"in v&&(_.oneOf(v.colorType,c,\"invalid color type\"),h=v.colorType),\"colorFormat\"in v&&(p=v.colorFormat,_.oneOf(v.colorFormat,u,\"invalid color format for texture\"))),\"depth\"in v&&(l.depth=v.depth),\"stencil\"in v&&(l.stencil=v.stencil),\"depthStencil\"in v&&(l.depthStencil=v.depthStencil)}else d=1;if(m)if(Array.isArray(m))for(s=[],n=0;n0&&(l.depth=i[0].depth,l.stencil=i[0].stencil,l.depthStencil=i[0].depthStencil),i[n]?i[n](l):i[n]=O(l)}return t(o,{width:d,height:d,color:s})}return o(e),t(o,{faces:i,resize:function(e){var t,r=0|e;if(_(r>0&&r<=n.maxCubeMapSize,\"invalid radius for cube fbo\"),r===o.width)return o;var a=o.color;for(t=0;t=0;--e){var t=I[e];t&&t(v,null,0)}a.flush(),m&&m.update()}function ce(){!Q&&I.length>0&&(Q=j.next(Y))}function le(){Q&&(j.cancel(Y),Q=null)}function de(e){e.preventDefault(),o=!0,le(),P.forEach((function(e){e()}))}function me(e){a.getError(),o=!1,f.restore(),k.restore(),x.restore(),S.restore(),O.restore(),E.restore(),A.restore(),m&&m.restore(),T.procs.refresh(),ce(),N.forEach((function(e){e()}))}function pe(e){function r(e,t){var r={},n={};return Object.keys(e).forEach((function(a){var i=e[a];if(D.isDynamic(i))n[a]=D.unbox(i,a);else{if(t&&Array.isArray(i))for(var o=0;o0)return l.call(this,function(e){for(;m.length=0,\"cannot cancel a frame twice\"),I[t]=function e(){var t=dn(I,e);I[t]=I[I.length-1],I.length-=1,I.length<=0&&le()}}}}function ge(){var e=F.viewport,t=F.scissor_box;e[0]=e[1]=t[0]=t[1]=0,v.viewportWidth=v.framebufferWidth=v.drawingBufferWidth=e[2]=t[2]=a.drawingBufferWidth,v.viewportHeight=v.framebufferHeight=v.drawingBufferHeight=e[3]=t[3]=a.drawingBufferHeight}function ye(){v.tick+=1,v.time=we(),ge(),T.procs.poll()}function xe(){S.refresh(),ge(),T.procs.refresh(),m&&m.update()}function we(){return(C()-p)/1e3}xe();var Ae=t(pe,{clear:function(e){if(_(\"object\"==typeof e&&e,\"regl.clear() takes an object as input\"),\"framebuffer\"in e)if(e.framebuffer&&\"framebufferCube\"===e.framebuffer_reglType)for(var r=0;r<6;++r)he(t({framebuffer:e.framebuffer.faces[r]},e),be);else he(e,be);else be(0,e)},prop:D.define.bind(null,1),context:D.define.bind(null,2),this:D.define.bind(null,3),draw:pe({}),buffer:function(e){return x.create(e,34962,!1,!1)},elements:function(e){return w.create(e,!1)},texture:S.create2D,cube:S.createCube,renderbuffer:O.create,framebuffer:E.create,framebufferCube:E.createCube,vao:A.createVAO,attributes:i,frame:ve,on:function(e,t){var r;switch(_.type(t,\"function\",\"listener callback must be a function\"),e){case\"frame\":return ve(t);case\"lost\":r=P;break;case\"restore\":r=N;break;case\"destroy\":r=q;break;default:_.raise(\"invalid event, must be one of frame,lost,restore,destroy\")}return r.push(t),{cancel:function(){for(var e=0;e=0},read:z,destroy:function(){I.length=0,le(),V&&(V.removeEventListener(cn,de),V.removeEventListener(ln,me)),k.clear(),E.clear(),O.clear(),A.clear(),S.clear(),w.clear(),x.clear(),m&&m.clear(),q.forEach((function(e){e()}))},_gl:a,_refresh:xe,poll:function(){ye(),m&&m.update()},now:we,stats:l});return n.onDone(null,Ae),Ae}},\"object\"==typeof r&&void 0!==t?t.exports=o():\"function\"==typeof define&&define.amd?define(o):i.createREGL=o()},\n 413: function _(t,e,a,s,r){s();const n=t(414),_=t(9),o=t(12);class c{constructor(t){this._regl=t,this._map=new Map}_create_texture(t){const e=t.length;let a=0;const s=[];let r=0,_=0;for(let n=0;nc[f+1]&&f++;const s=t[f],n=c[f]+.5*s;let o=.5*s-Math.abs(a-n);f%2==1&&(o=-o),m[e]=Math.round(255*(o-r)/(_-r))}return[[a,u,r,_],this._regl.texture({shape:[l,1,1],data:m,wrapS:\"repeat\",format:\"alpha\",type:\"uint8\",mag:\"linear\",min:\"linear\"})]}_get_key(t){return t.join(\",\")}_get_or_create(t){const e=this._get_key(t);let a=this._map.get(e);if(null==a){const s=(0,n.gcd)(t);if(s>1){t=(0,o.map)(t,(t=>t/s)),a=this._get_or_create(t);const[r,n,_]=a;a=[r,n,s],this._map.set(e,a)}else{const[r,n]=this._create_texture(t);a=[r,n,s],this._map.set(e,a)}}return a}get(t){return t.length%2==1&&(t=(0,_.concat)([t,t])),this._get_or_create(t)}}a.DashCache=c,c.__name__=\"DashCache\"},\n 414: function _(n,t,e,r,o){function u(n,t){let e,r;n>t?(e=n,r=t):(e=t,r=n);let o=e%r;for(;0!=o;)e=r,r=o,o=e%r;return r}r(),e.gcd=function(n){let t=n[0];for(let e=1;e= 0.0 ? 1.0 : -1.0;\\n}\\n\\nvoid main()\\n{\\n if (a_show_curr < 0.5) {\\n // Line segment has non-finite value at one or both ends, do not render.\\n gl_Position = vec4(-2.0, -2.0, 0.0, 1.0);\\n return;\\n }\\n\\n const float min_miter_factor_round_join_mesh = sqrt(2.0);\\n\\n int join_type = int(u_line_join + 0.5);\\n int cap_type = int(u_line_cap + 0.5);\\n float halfwidth = 0.5*(u_linewidth + u_antialias);\\n vec2 segment_along = normalize(a_point_end - a_point_start); // unit vector.\\n v_segment_length = length(a_point_end - a_point_start);\\n vec2 segment_right = right_vector(segment_along); // unit vector.\\n vec2 xy;\\n\\n bool miter_too_large_start = false;\\n bool miter_too_large_end = false;\\n\\n v_coords.y = a_position.y*halfwidth; // Overwritten later for end points.\\n\\n bool has_start_cap = a_show_prev < 0.5;\\n bool has_end_cap = a_show_next < 0.5;\\n\\n vec2 point_normal_start;\\n float cos_theta_start;\\n float turn_right_start;\\n if (has_start_cap)\\n point_normal_start = segment_right;\\n else {\\n vec2 prev_right = right_vector(normalize(a_point_start - a_point_prev));\\n point_normal_start = normalize(segment_right + prev_right);\\n cos_theta_start = dot(segment_right, point_normal_start); // Always +ve\\n turn_right_start = sign_no_zero(dot(segment_right, a_point_prev - a_point_start));\\n }\\n\\n vec2 point_normal_end;\\n float cos_theta_end;\\n float turn_right_end;\\n if (has_end_cap)\\n point_normal_end = segment_right;\\n else {\\n vec2 next_right = right_vector(normalize(a_point_next - a_point_end));\\n point_normal_end = normalize(segment_right + next_right);\\n cos_theta_end = dot(segment_right, point_normal_end); // Always +ve\\n turn_right_end = sign_no_zero(dot(segment_right, a_point_next - a_point_end));\\n }\\n\\n float miter_factor_start = 1.0 / dot(segment_right, point_normal_start);\\n float miter_factor_end = 1.0 / dot(segment_right, point_normal_end);\\n if (join_type == miter_join) {\\n // If miter too large, use bevel join instead.\\n miter_too_large_start = (miter_factor_start > u_miter_limit);\\n miter_too_large_end = (miter_factor_end > u_miter_limit);\\n }\\n\\n float sign_at_start = -sign(a_position.x); // +ve at segment start, -ve end.\\n vec2 point = sign_at_start > 0.0 ? a_point_start : a_point_end;\\n vec2 adjacent_point =\\n sign_at_start > 0.0 ? (has_start_cap ? a_point_start : a_point_prev)\\n : (has_end_cap ? a_point_end : a_point_next);\\n\\n if ( (has_start_cap && sign_at_start > 0.0) ||\\n (has_end_cap && sign_at_start < 0.0) ) {\\n // Cap.\\n xy = point - segment_right*(halfwidth*a_position.y);\\n if (cap_type == butt_cap)\\n xy -= sign_at_start*0.5*u_antialias*segment_along;\\n else\\n xy -= sign_at_start*halfwidth*segment_along;\\n }\\n else { // Join.\\n // +ve if turning to right, -ve if to left.\\n float turn_sign = sign_at_start > 0.0 ? turn_right_start : turn_right_end;\\n\\n vec2 adjacent_right = sign_at_start*normalize(right_vector(point - adjacent_point));\\n vec2 point_right = normalize(segment_right + adjacent_right);\\n float miter_factor = sign_at_start > 0.0 ? miter_factor_start : miter_factor_end;\\n bool miter_too_large = sign_at_start > 0.0 ? miter_too_large_start : miter_too_large_end;\\n\\n if (abs(a_position.x) > 1.5) {\\n // Outer point, meets prev/next segment.\\n float factor; // multiplied by halfwidth...\\n\\n if (join_type == bevel_join || (join_type == miter_join && miter_too_large))\\n factor = 1.0 / miter_factor; // cos_theta.\\n else if (join_type == round_join &&\\n miter_factor > min_miter_factor_round_join_mesh)\\n factor = 1.0;\\n else // miter, or round (small angle only).\\n factor = miter_factor;\\n\\n xy = point - point_right*(halfwidth*turn_sign*factor);\\n v_coords.y = turn_sign*halfwidth*factor / miter_factor;\\n }\\n else if (turn_sign*a_position.y < 0.0) {\\n // Inner point, meets prev/next segment.\\n float len = halfwidth*miter_factor;\\n float segment_len = v_segment_length;\\n float adjacent_len = distance(point, adjacent_point);\\n\\n if (len <= min(segment_len, adjacent_len))\\n // Normal behaviour.\\n xy = point - point_right*(len*a_position.y);\\n else\\n // For short wide line segments the inner point using the above\\n // calculation can be outside of the line. Here clipping it.\\n xy = point + segment_right*(halfwidth*turn_sign);\\n }\\n else {\\n // Point along outside edge.\\n xy = point - segment_right*(halfwidth*a_position.y);\\n if (join_type == round_join &&\\n miter_factor > min_miter_factor_round_join_mesh) {\\n xy = line_intersection(xy, segment_along,\\n point - turn_sign*point_right*halfwidth,\\n right_vector(point_right));\\n }\\n }\\n }\\n\\n vec2 pos = xy + 0.5; // Bokeh's offset.\\n pos /= u_canvas_size / u_pixel_ratio; // in 0..1\\n gl_Position = vec4(2.0*pos.x - 1.0, 1.0 - 2.0*pos.y, 0.0, 1.0);\\n\\n v_coords.x = dot(xy - a_point_start, segment_along);\\n v_flags = float(int(has_start_cap) +\\n 2*int(has_end_cap) +\\n 4*int(miter_too_large_start) +\\n 8*int(miter_too_large_end));\\n v_cos_theta_turn_right_start = cos_theta_start*turn_right_start;\\n v_cos_theta_turn_right_end = cos_theta_end*turn_right_end;\\n\\n#ifdef DASHED\\n v_length_so_far = a_length_so_far;\\n#endif\\n}\\n\"},\n 416: function _(n,t,a,i,e){i();a.default=\"\\nprecision mediump float;\\n\\nconst int butt_cap = 0;\\nconst int round_cap = 1;\\nconst int square_cap = 2;\\n\\nconst int miter_join = 0;\\nconst int round_join = 1;\\nconst int bevel_join = 2;\\n\\nuniform float u_linewidth;\\nuniform float u_antialias;\\nuniform float u_line_join;\\nuniform float u_line_cap;\\nuniform vec4 u_line_color;\\n#ifdef DASHED\\nuniform sampler2D u_dash_tex;\\nuniform vec4 u_dash_tex_info;\\nuniform float u_dash_scale;\\nuniform float u_dash_offset;\\n#endif\\n\\nvarying float v_segment_length;\\nvarying vec2 v_coords;\\nvarying float v_flags;\\nvarying float v_cos_theta_turn_right_start;\\nvarying float v_cos_theta_turn_right_end;\\n#ifdef DASHED\\nvarying float v_length_so_far;\\n#endif\\n\\nfloat cross_z(in vec2 v0, in vec2 v1)\\n{\\n return v0.x*v1.y - v0.y*v1.x;\\n}\\n\\nfloat point_line_side(in vec2 point, in vec2 start, in vec2 end)\\n{\\n // +ve if point to right of line.\\n // Alternatively could do dot product with right_vector.\\n return cross_z(point - start, end - start);\\n}\\n\\nfloat point_line_distance(in vec2 point, in vec2 start, in vec2 end)\\n{\\n return point_line_side(point, start, end) / distance(start, end);\\n}\\n\\nvec2 right_vector(in vec2 v)\\n{\\n return vec2(v.y, -v.x);\\n}\\n\\nfloat bevel_join_distance(in float sign_start, in float halfwidth)\\n{\\n float cos_theta_turn_right = sign_start > 0.0 ? v_cos_theta_turn_right_start\\n : v_cos_theta_turn_right_end;\\n float cos_theta = abs(cos_theta_turn_right);\\n float turn_right = sign(cos_theta_turn_right);\\n float distance_along = sign_start > 0.0 ? 0.0 : v_segment_length;\\n\\n // In v_coords reference frame (x is along segment, y across).\\n vec2 line_start = vec2(distance_along, halfwidth*turn_right);\\n float sin_alpha = cos_theta;\\n float cos_alpha = sqrt(1.0 - sin_alpha*sin_alpha);\\n vec2 line_along = vec2(-sign_start*turn_right*sin_alpha, -cos_alpha);\\n\\n return halfwidth + sign_start*point_line_distance(\\n v_coords, line_start, line_start+line_along);\\n}\\n\\nfloat cap(in int cap_type, in float x, in float y)\\n{\\n // x is distance along segment in direction away from end of segment,\\n // y is distance across segment.\\n if (cap_type == butt_cap)\\n return max(0.5*u_linewidth - x, abs(y));\\n else if (cap_type == square_cap)\\n return max(-x, abs(y));\\n else // cap_type == round_cap\\n return distance(vec2(min(x, 0.0), y), vec2(0.0, 0.0));\\n}\\n\\nfloat distance_to_alpha(in float dist)\\n{\\n return 1.0 - smoothstep(0.5*(u_linewidth - u_antialias),\\n 0.5*(u_linewidth + u_antialias), dist);\\n}\\n\\n#ifdef DASHED\\nfloat dash_distance(in float x)\\n{\\n // x is in direction of v_coords.x, i.e. along segment.\\n float tex_length = u_dash_tex_info.x;\\n float tex_offset = u_dash_tex_info.y;\\n float tex_dist_min = u_dash_tex_info.z;\\n float tex_dist_max = u_dash_tex_info.w;\\n\\n // Apply offset.\\n x += v_length_so_far - u_dash_scale*tex_offset + u_dash_offset;\\n\\n // Interpolate within texture to obtain distance to dash.\\n float dist = texture2D(u_dash_tex,\\n vec2(x / (tex_length*u_dash_scale), 0.0)).a;\\n\\n // Scale distance within min and max limits.\\n dist = tex_dist_min + dist*(tex_dist_max - tex_dist_min);\\n\\n return u_dash_scale*dist;\\n}\\n\\nfloat clip_dash_distance(in float x, in float offset, in float sign_along)\\n{\\n // Return clipped dash distance, sign_along is +1.0 if looking forward\\n // into next segment and -1.0 if looking backward into previous segment.\\n float half_antialias = 0.5*u_antialias;\\n\\n if (sign_along*x > half_antialias) {\\n // Outside antialias region, use usual dash distance.\\n return dash_distance(offset + x);\\n }\\n else {\\n // Inside antialias region.\\n // Dash distance at edge of antialias region clipped to half_antialias.\\n float edge_dist = min(dash_distance(offset + sign_along*half_antialias), half_antialias);\\n\\n // Physical distance from dash distance at edge of antialias region.\\n return edge_dist + sign_along*x - half_antialias;\\n }\\n}\\n\\nmat2 rotation_matrix(in float sign_start)\\n{\\n // Rotation matrix for v_coords from this segment to prev or next segment.\\n float cos_theta_turn_right = sign_start > 0.0 ? v_cos_theta_turn_right_start\\n : v_cos_theta_turn_right_end;\\n float cos_theta = abs(cos_theta_turn_right);\\n float turn_right = sign(cos_theta_turn_right);\\n\\n float sin_theta = sqrt(1.0 - cos_theta*cos_theta)*sign_start*turn_right;\\n float cos_2theta = 2.0*cos_theta*cos_theta - 1.0;\\n float sin_2theta = 2.0*sin_theta*cos_theta;\\n return mat2(cos_2theta, -sin_2theta, sin_2theta, cos_2theta);\\n}\\n#endif\\n\\nvoid main()\\n{\\n int join_type = int(u_line_join + 0.5);\\n int cap_type = int(u_line_cap + 0.5);\\n float halfwidth = 0.5*(u_linewidth + u_antialias);\\n float half_antialias = 0.5*u_antialias;\\n\\n // Extract flags.\\n int flags = int(v_flags + 0.5);\\n bool miter_too_large_end = (flags / 8 > 0);\\n flags -= 8*int(miter_too_large_end);\\n bool miter_too_large_start = (flags / 4 > 0);\\n flags -= 4*int(miter_too_large_start);\\n bool has_end_cap = (flags / 2 > 0);\\n flags -= 2*int(has_end_cap);\\n bool has_start_cap = flags > 0;\\n\\n float dist = v_coords.y; // For straight segment, and miter join.\\n\\n // Along-segment coords with respect to end of segment, +ve inside segment\\n // so equivalent to v_coords.x at start of segment.\\n float end_coords_x = v_segment_length - v_coords.x;\\n\\n if (v_coords.x <= half_antialias) {\\n // At start of segment, either cap or join.\\n if (has_start_cap)\\n dist = cap(cap_type, v_coords.x, v_coords.y);\\n else if (join_type == round_join)\\n dist = distance(v_coords, vec2(0.0, 0.0));\\n else if (join_type == bevel_join ||\\n (join_type == miter_join && miter_too_large_start))\\n dist = max(abs(dist), bevel_join_distance(1.0, halfwidth));\\n // else a miter join which uses the default dist calculation.\\n }\\n else if (end_coords_x <= half_antialias) {\\n // At end of segment, either cap or join.\\n if (has_end_cap)\\n dist = cap(cap_type, end_coords_x, v_coords.y);\\n else if (join_type == round_join)\\n dist = distance(v_coords, vec2(v_segment_length, 0));\\n else if ((join_type == bevel_join ||\\n (join_type == miter_join && miter_too_large_end)))\\n dist = max(abs(dist), bevel_join_distance(-1.0, halfwidth));\\n // else a miter join which uses the default dist calculation.\\n }\\n\\n float alpha = distance_to_alpha(abs(dist));\\n\\n#ifdef DASHED\\n if (u_dash_tex_info.x >= 0.0) {\\n // Dashes in straight segments (outside of joins) are easily calculated.\\n dist = dash_distance(v_coords.x);\\n\\n if (!has_start_cap && cap_type == butt_cap) {\\n if (v_coords.x < half_antialias) {\\n // Outer of start join rendered solid color or not at all\\n // depending on whether corner point is in dash or gap, with\\n // antialiased ends.\\n if (dash_distance(0.0) > 0.0) {\\n // Corner is solid color.\\n dist = max(dist, min(half_antialias, -v_coords.x));\\n // Avoid visible antialiasing band between corner and dash.\\n dist = max(dist, dash_distance(half_antialias));\\n }\\n else {\\n // Use large negative value so corner not colored.\\n dist = -halfwidth;\\n\\n if (v_coords.x > -half_antialias) {\\n // Consider antialias region of dash after start region.\\n float edge_dist = min(dash_distance(half_antialias), half_antialias);\\n dist = max(dist, edge_dist + v_coords.x - half_antialias);\\n }\\n }\\n }\\n\\n vec2 prev_coords = rotation_matrix(1.0)*v_coords;\\n\\n if (abs(prev_coords.y) < halfwidth && prev_coords.x < half_antialias) {\\n // Extend dashes across from end of previous segment, with antialiased end.\\n float new_dist = clip_dash_distance(prev_coords.x, 0.0, -1.0);\\n new_dist = min(new_dist, 0.5*u_linewidth - abs(prev_coords.y));\\n dist = max(dist, new_dist);\\n }\\n }\\n\\n if (!has_end_cap && cap_type == butt_cap) {\\n if (end_coords_x < half_antialias) {\\n // Similar for end join.\\n if (dash_distance(v_segment_length) > 0.0) {\\n // Corner is solid color.\\n dist = max(dist, min(half_antialias, -end_coords_x));\\n // Avoid visible antialiasing band between corner and dash.\\n dist = max(dist, dash_distance(v_segment_length - half_antialias));\\n }\\n else {\\n // Use large negative value so corner not colored.\\n dist = -halfwidth;\\n\\n if (end_coords_x > -half_antialias) {\\n // Consider antialias region of dash before end region.\\n float edge_dist = min(dash_distance(v_segment_length - half_antialias),\\n half_antialias);\\n dist = max(dist, edge_dist + end_coords_x - half_antialias);\\n }\\n }\\n }\\n\\n vec2 next_coords = rotation_matrix(-1.0)*(v_coords - vec2(v_segment_length, 0.0));\\n\\n if (abs(next_coords.y) < halfwidth && next_coords.x > -half_antialias) {\\n // Extend dashes across from next segment, with antialiased end.\\n float new_dist = clip_dash_distance(next_coords.x, v_segment_length, 1.0);\\n new_dist = min(new_dist, 0.5*u_linewidth - abs(next_coords.y));\\n dist = max(dist, new_dist);\\n }\\n }\\n\\n dist = cap(cap_type, dist, v_coords.y);\\n\\n float dash_alpha = distance_to_alpha(dist);\\n alpha = min(alpha, dash_alpha);\\n }\\n#endif\\n\\n alpha = u_line_color.a*alpha;\\n gl_FragColor = vec4(u_line_color.rgb*alpha, alpha); // Premultiplied alpha.\\n}\\n\"},\n 417: function _(n,i,e,t,a){t();e.default=\"\\nprecision mediump float;\\n\\nattribute vec2 a_position;\\nattribute vec2 a_center;\\nattribute float a_width;\\nattribute float a_height;\\nattribute float a_angle; // In radians\\nattribute float a_linewidth;\\nattribute vec4 a_line_color;\\nattribute vec4 a_fill_color;\\nattribute float a_line_cap;\\nattribute float a_line_join;\\nattribute float a_show;\\n#ifdef HATCH\\nattribute float a_hatch_pattern;\\nattribute float a_hatch_scale;\\nattribute float a_hatch_weight;\\nattribute vec4 a_hatch_color;\\n#endif\\n\\nuniform float u_pixel_ratio;\\nuniform vec2 u_canvas_size;\\nuniform float u_antialias;\\nuniform float u_size_hint;\\n\\nvarying float v_linewidth;\\nvarying vec2 v_size; // 2D size for rects compared to 1D for markers.\\nvarying vec4 v_line_color;\\nvarying vec4 v_fill_color;\\nvarying float v_line_cap;\\nvarying float v_line_join;\\nvarying vec2 v_coords;\\n#ifdef HATCH\\nvarying float v_hatch_pattern;\\nvarying float v_hatch_scale;\\nvarying float v_hatch_weight;\\nvarying vec4 v_hatch_color;\\nvarying vec2 v_hatch_coords;\\n#endif\\n\\nvoid main()\\n{\\n if (a_show < 0.5) {\\n // Do not show this rect.\\n gl_Position = vec4(-2.0, -2.0, 0.0, 1.0);\\n return;\\n }\\n\\n v_size = vec2(a_width, a_height);\\n v_linewidth = a_linewidth;\\n v_line_color = a_line_color;\\n v_fill_color = a_fill_color;\\n v_line_cap = a_line_cap;\\n v_line_join = a_line_join;\\n\\n if (v_linewidth < 1.0) {\\n // Linewidth less than 1 is implemented as 1 but with reduced alpha.\\n v_line_color.a *= v_linewidth;\\n v_linewidth = 1.0;\\n }\\n\\n#ifdef HATCH\\n v_hatch_pattern = a_hatch_pattern;\\n v_hatch_scale = a_hatch_scale;\\n v_hatch_weight = a_hatch_weight;\\n v_hatch_color = a_hatch_color;\\n#endif\\n\\n vec2 enclosing_size;\\n // Need extra size of (v_linewidth+u_antialias) if edge of marker parallel to\\n // edge of bounding box. If symmetric spike towards edge then multiply by\\n // 1/cos(theta) where theta is angle between spike and bbox edges.\\n int size_hint = int(u_size_hint + 0.5);\\n if (size_hint == 1) // Dash\\n enclosing_size = vec2(v_size.x + v_linewidth + u_antialias,\\n v_linewidth + u_antialias);\\n else if (size_hint == 2) // Dot\\n enclosing_size = 0.25*v_size + u_antialias;\\n else if (size_hint == 3) // Diamond\\n enclosing_size = vec2(v_size.x*(2.0/3.0) + (v_linewidth + u_antialias)*1.20185,\\n v_size.y + (v_linewidth + u_antialias)*1.80278);\\n else if (size_hint == 4) // Hex\\n enclosing_size = v_size + (v_linewidth + u_antialias)*vec2(2.0/sqrt(3.0), 1.0);\\n else if (size_hint == 5) // Square pin\\n enclosing_size = v_size + (v_linewidth + u_antialias)*3.1;\\n else if (size_hint == 6) // Triangle\\n enclosing_size = vec2(v_size.x + (v_linewidth + u_antialias)*sqrt(3.0),\\n v_size.y*(2.0/sqrt(3.0)) + (v_linewidth + u_antialias)*2.0);\\n else if (size_hint == 7) // Triangle pin\\n enclosing_size = v_size + (v_linewidth + u_antialias)*vec2(4.8, 6.0);\\n else if (size_hint == 8) // Star\\n enclosing_size = vec2(v_size.x*0.95106 + (v_linewidth + u_antialias)*3.0,\\n v_size.y + (v_linewidth + u_antialias)*3.2);\\n else\\n enclosing_size = v_size + v_linewidth + u_antialias;\\n\\n // Coordinates in rotated frame with respect to center of marker, used for\\n // distance functions in fragment shader.\\n v_coords = a_position*enclosing_size;\\n\\n float c = cos(-a_angle);\\n float s = sin(-a_angle);\\n mat2 rotation = mat2(c, -s, s, c);\\n\\n vec2 pos = a_center + rotation*v_coords;\\n#ifdef HATCH\\n // Coordinates for hatching in unrotated frame of reference.\\n v_hatch_coords = pos - 0.5;\\n#endif\\n pos += 0.5; // Make up for Bokeh's offset.\\n pos /= u_canvas_size / u_pixel_ratio; // 0 to 1.\\n gl_Position = vec4(2.0*pos.x - 1.0, 1.0 - 2.0*pos.y, 0.0, 1.0);\\n}\\n\"},\n 418: function _(n,i,e,t,a){t();e.default=\"\\nprecision mediump float;\\n\\nconst float SQRT2 = sqrt(2.0);\\nconst float SQRT3 = sqrt(3.0);\\nconst float PI = 3.14159265358979323846;\\n\\nconst int butt_cap = 0;\\nconst int round_cap = 1;\\nconst int square_cap = 2;\\n\\nconst int miter_join = 0;\\nconst int round_join = 1;\\nconst int bevel_join = 2;\\n\\n#ifdef HATCH\\nconst int hatch_dot = 1;\\nconst int hatch_ring = 2;\\nconst int hatch_horizontal_line = 3;\\nconst int hatch_vertical_line = 4;\\nconst int hatch_cross = 5;\\nconst int hatch_horizontal_dash = 6;\\nconst int hatch_vertical_dash = 7;\\nconst int hatch_spiral = 8;\\nconst int hatch_right_diagonal_line = 9;\\nconst int hatch_left_diagonal_line = 10;\\nconst int hatch_diagonal_cross = 11;\\nconst int hatch_right_diagonal_dash = 12;\\nconst int hatch_left_diagonal_dash = 13;\\nconst int hatch_horizontal_wave = 14;\\nconst int hatch_vertical_wave = 15;\\nconst int hatch_criss_cross = 16;\\n#endif\\n\\nuniform float u_antialias;\\n\\nvarying float v_linewidth;\\nvarying vec2 v_size;\\nvarying vec4 v_line_color;\\nvarying vec4 v_fill_color;\\nvarying float v_line_cap;\\nvarying float v_line_join;\\nvarying vec2 v_coords;\\n#ifdef HATCH\\nvarying float v_hatch_pattern;\\nvarying float v_hatch_scale;\\nvarying float v_hatch_weight;\\nvarying vec4 v_hatch_color;\\nvarying vec2 v_hatch_coords;\\n#endif\\n\\n// Lines within the marker (dot, cross, x and y) are added at the end as they are\\n// on top of the fill rather than astride it.\\n#if defined(USE_CIRCLE_DOT) || defined(USE_DIAMOND_DOT) || defined(USE_DOT) || defined(USE_HEX_DOT) || defined(USE_SQUARE_DOT) || defined(USE_STAR_DOT) || defined(USE_TRIANGLE_DOT)\\n #define APPEND_DOT\\n#endif\\n\\n#if defined(USE_CIRCLE_CROSS) || defined(USE_SQUARE_CROSS)\\n #define APPEND_CROSS\\n#endif\\n\\n#ifdef USE_DIAMOND_CROSS\\n #define APPEND_CROSS_2\\n#endif\\n\\n#ifdef USE_CIRCLE_X\\n #define APPEND_X\\n #define APPEND_X_LEN (0.5*v_size.x)\\n#endif\\n\\n#ifdef USE_SQUARE_X\\n #define APPEND_X\\n #define APPEND_X_LEN (v_size.x/SQRT2)\\n#endif\\n\\n#ifdef USE_CIRCLE_Y\\n #define APPEND_Y\\n#endif\\n\\n#if defined(USE_ASTERISK) || defined(USE_CROSS) || defined(USE_DASH) || defined(USE_DOT) || defined(USE_X) || defined(USE_Y)\\n // No fill.\\n #define LINE_ONLY\\n#endif\\n\\n#if defined(LINE_ONLY) || defined(APPEND_CROSS) || defined(APPEND_CROSS_2) || defined(APPEND_X) || defined(APPEND_Y)\\nfloat end_cap_distance(in vec2 p, in vec2 end_point, in vec2 unit_direction, in int line_cap)\\n{\\n vec2 offset = p - end_point;\\n if (line_cap == butt_cap)\\n return dot(offset, unit_direction) + 0.5*v_linewidth;\\n else if (line_cap == square_cap)\\n return dot(offset, unit_direction);\\n else if (line_cap == round_cap && dot(offset, unit_direction) > 0.0)\\n return length(offset);\\n else\\n // Default is outside of line and should be -0.5*(v_linewidth+u_antialias) or less,\\n // so here avoid the multiplication.\\n return -v_linewidth-u_antialias;\\n}\\n#endif\\n\\n#if !(defined(LINE_ONLY) || defined(USE_SQUARE_PIN) || defined(USE_TRIANGLE_PIN))\\n// For line join at a vec2 corner where 2 line segments meet, consider bevel points which are the 2\\n// points obtained by moving half a linewidth away from the corner point in the directions normal to\\n// the line segments. The line through these points is the bevel line, characterised by a vec2\\n// unit_normal and offset distance from the corner point. Edge of bevel join straddles this line,\\n// round join occurs outside of this line centred on the corner point. In general\\n// offset = (linewidth/2)*sin(alpha/2)\\n// where alpha is the angle between the 2 line segments at the corner.\\nfloat line_join_distance_no_miter(\\n in vec2 p, in vec2 corner, in vec2 unit_normal, in float offset, in int line_join)\\n{\\n // Simplified version of line_join_distance ignoring miter which most markers do implicitly\\n // as they are composed of straight line segments.\\n float dist_outside = dot((p - corner), unit_normal) - offset;\\n\\n if (line_join == bevel_join && dist_outside > -0.5*u_antialias)\\n return dist_outside + 0.5*v_linewidth;\\n else if (dist_outside > 0.0) // round_join\\n return distance(p, corner);\\n else\\n // Default is outside of line and should be -0.5*(v_linewidth+u_antialias) or less,\\n // so here avoid the multiplication.\\n return -v_linewidth-u_antialias;\\n}\\n#endif\\n\\n#if defined(USE_SQUARE_PIN) || defined(USE_TRIANGLE_PIN)\\n// Line join distance including miter but only one-sided check as assuming use of symmetry in\\n// calling function.\\nfloat line_join_distance_incl_miter(\\n in vec2 p, in vec2 corner, in vec2 unit_normal, in float offset, in int line_join,\\n vec2 miter_unit_normal)\\n{\\n float dist_outside = dot((p - corner), unit_normal) - offset;\\n\\n if (line_join == miter_join && dist_outside > 0.0)\\n return dot((p - corner), miter_unit_normal);\\n else if (line_join == bevel_join && dist_outside > -0.5*u_antialias)\\n return dist_outside + 0.5*v_linewidth;\\n else if (dist_outside > 0.0) // round_join\\n return distance(p, corner);\\n else\\n return -v_linewidth-u_antialias;\\n}\\n#endif\\n\\n#if defined(APPEND_CROSS) || defined(APPEND_X) || defined(USE_ASTERISK) || defined(USE_CROSS) || defined(USE_X)\\nfloat one_cross(in vec2 p, in int line_cap, in float len)\\n{\\n p = abs(p);\\n p = (p.y > p.x) ? p.yx : p.xy;\\n float dist = p.y;\\n float end_dist = end_cap_distance(p, vec2(len, 0.0), vec2(1.0, 0.0), line_cap);\\n return max(dist, end_dist);\\n}\\n#endif\\n\\n#ifdef APPEND_CROSS_2\\nfloat one_cross_2(in vec2 p, in int line_cap, in vec2 lengths)\\n{\\n // Cross with different length in x and y directions.\\n p = abs(p);\\n bool switch_xy = (p.y > p.x);\\n p = switch_xy ? p.yx : p.xy;\\n float len = switch_xy ? lengths.y : lengths.x;\\n float dist = p.y;\\n float end_dist = end_cap_distance(p, vec2(len, 0.0), vec2(1.0, 0.0), line_cap);\\n return max(dist, end_dist);\\n}\\n#endif\\n\\n#if defined(APPEND_Y) || defined(USE_Y)\\nfloat one_y(in vec2 p, in int line_cap, in float len)\\n{\\n p = vec2(abs(p.x), -p.y);\\n\\n // End point of line to right is (1/2, 1/3)*len*SQRT3.\\n // Unit vector along line is (1/2, 1/3)*k where k = 6/SQRT13.\\n const float k = 6.0/sqrt(13.0);\\n vec2 unit_along = vec2(0.5*k, k/3.0);\\n vec2 end_point = vec2(0.5*len*SQRT3, len*SQRT3/3.0);\\n float dist = max(abs(dot(p, vec2(-unit_along.y, unit_along.x))),\\n end_cap_distance(p, end_point, unit_along, line_cap));\\n\\n if (p.y < 0.0) {\\n // Vertical line.\\n float vert_dist = max(p.x,\\n end_cap_distance(p, vec2(0.0, -len), vec2(0.0, -1.0), line_cap));\\n dist = min(dist, vert_dist);\\n }\\n return dist;\\n}\\n#endif\\n\\n// One marker_distance function per marker type.\\n// Distance is zero on edge of marker, +ve outside and -ve inside.\\n\\n#ifdef USE_ASTERISK\\nfloat marker_distance(in vec2 p, in int line_cap, in int line_join)\\n{\\n // Assuming v_size.x == v.size_y\\n vec2 p_diag = vec2((p.x + p.y)/SQRT2, (p.x - p.y)/SQRT2);\\n float len = 0.5*v_size.x;\\n return min(one_cross(p, line_cap, len), // cross\\n one_cross(p_diag, line_cap, len)); // x\\n}\\n#endif\\n\\n#if defined(USE_CIRCLE) || defined(USE_CIRCLE_CROSS) || defined(USE_CIRCLE_DOT) || defined(USE_CIRCLE_X) || defined(USE_CIRCLE_Y)\\nfloat marker_distance(in vec2 p, in int line_cap, in int line_join)\\n{\\n // Assuming v_size.x == v.size_y\\n return length(p) - 0.5*v_size.x;\\n}\\n#endif\\n\\n#ifdef USE_CROSS\\nfloat marker_distance(in vec2 p, in int line_cap, in int line_join)\\n{\\n // Assuming v_size.x == v.size_y\\n return one_cross(p, line_cap, 0.5*v_size.x);\\n}\\n#endif\\n\\n#ifdef USE_DASH\\nfloat marker_distance(in vec2 p, in int line_cap, in int line_join)\\n{\\n p = abs(p);\\n float dist = p.y;\\n float end_dist = end_cap_distance(p, vec2(0.5*v_size.x, 0.0), vec2(1.0, 0.0), line_cap);\\n return max(dist, end_dist);\\n}\\n#endif\\n\\n#if defined(USE_DIAMOND) || defined(USE_DIAMOND_CROSS) || defined(USE_DIAMOND_DOT)\\nfloat marker_distance(in vec2 p, in int line_cap, in int line_join)\\n{\\n // Assuming v_size.x == v.size_y\\n // Only need to consider +ve quadrant, the 2 end points are (2r/3, 0) and (0, r)\\n // where r = radius = v_size.x/2.\\n // Line has outward-facing unit normal vec2(1, 2/3)/k where k = SQRT13/3\\n // hence vec2(3, 2)/SQRT13, and distance from origin of 2r/(3k) = 2r/SQRT13.\\n p = abs(p);\\n float r = 0.5*v_size.x;\\n const float SQRT13 = sqrt(13.0);\\n float dist = dot(p, vec2(3.0, 2.0))/SQRT13 - 2.0*r/SQRT13;\\n\\n if (line_join != miter_join) {\\n dist = max(dist, line_join_distance_no_miter(\\n p, vec2(0.0, r), vec2(0.0, 1.0), v_linewidth/SQRT13, line_join));\\n\\n dist = max(dist, line_join_distance_no_miter(\\n p, vec2(r*2.0/3.0, 0.0), vec2(1.0, 0.0), v_linewidth*(1.5/SQRT13), line_join));\\n }\\n\\n return dist;\\n}\\n#endif\\n\\n#ifdef USE_DOT\\nfloat marker_distance(in vec2 p, in int line_cap, in int line_join)\\n{\\n // Dot is always appended.\\n return v_linewidth+u_antialias;\\n}\\n#endif\\n\\n#if defined(USE_HEX) || defined(USE_HEX_DOT)\\nfloat marker_distance(in vec2 p, in int line_cap, in int line_join)\\n{\\n // A regular hexagon has v_size.x == v.size_y = r where r is the length of\\n // each of the 3 sides of the 6 equilateral triangles that comprise the hex.\\n // Only consider +ve quadrant, the 3 corners are at (0, h), (rx/2, h), (rx, 0)\\n // where rx = 0.5*v_size.x, ry = 0.5*v_size.y and h = ry*SQRT3/2.\\n // Sloping line has outward normal vec2(h, rx/2). Length of this is\\n // len = sqrt(h**2 + rx**2/4) to give unit normal (h, rx/2)/len and distance\\n // from origin of this line is rx*h/len.\\n p = abs(p);\\n float rx = v_size.x/2.0;\\n float h = v_size.y*(SQRT3/4.0);\\n float len_normal = sqrt(h*h + 0.25*rx*rx);\\n vec2 unit_normal = vec2(h, 0.5*rx) / len_normal;\\n float dist = max(dot(p, unit_normal) - rx*h/len_normal, // Distance from sloping line.\\n p.y - h); // Distance from horizontal line.\\n\\n if (line_join != miter_join) {\\n dist = max(dist, line_join_distance_no_miter(\\n p, vec2(rx, 0.0), vec2(1.0, 0.0), 0.5*v_linewidth*unit_normal.x, line_join));\\n\\n unit_normal = normalize(unit_normal + vec2(0.0, 1.0)); // At (rx/2, h) corner.\\n dist = max(dist, line_join_distance_no_miter(\\n p, vec2(0.5*rx, h), unit_normal, 0.5*v_linewidth*unit_normal.y, line_join));\\n }\\n return dist;\\n}\\n#endif\\n\\n#ifdef USE_PLUS\\nfloat marker_distance(in vec2 p, in int line_cap, in int line_join)\\n{\\n // Assuming v_size.x == v.size_y\\n // Only need to consider one octant, the +ve quadrant with x >= y.\\n p = abs(p);\\n p = (p.y > p.x) ? p.yx : p.xy;\\n\\n // 3 corners are (r, 0), (r, 3r/8) and (3r/8, 3r/8).\\n float r = 0.5*v_size.x;\\n p = p - vec2(r, 0.375*r); // Distance with respect to outside corner\\n float dist = max(p.x, p.y);\\n\\n if (line_join != miter_join) {\\n // Outside corner\\n dist = max(dist, line_join_distance_no_miter(\\n p, vec2(0.0, 0.0), vec2(1.0/SQRT2, 1.0/SQRT2), v_linewidth/(2.0*SQRT2), line_join));\\n\\n // Inside corner\\n dist = min(dist, -line_join_distance_no_miter(\\n p, vec2(-5.0*r/8.0, 0.0), vec2(-1.0/SQRT2, -1.0/SQRT2), v_linewidth/(2.0*SQRT2), line_join));\\n }\\n\\n return dist;\\n}\\n#endif\\n\\n#if defined(USE_SQUARE) || defined(USE_SQUARE_CROSS) || defined(USE_SQUARE_DOT) || defined(USE_SQUARE_X)\\nfloat marker_distance(in vec2 p, in int line_cap, in int line_join)\\n{\\n vec2 p2 = abs(p) - v_size/2.0; // Offset from corner\\n float dist = max(p2.x, p2.y);\\n\\n if (line_join != miter_join)\\n dist = max(dist, line_join_distance_no_miter(\\n p2, vec2(0.0, 0.0), vec2(1.0/SQRT2, 1.0/SQRT2), v_linewidth/(2.0*SQRT2), line_join));\\n\\n return dist;\\n}\\n#endif\\n\\n#ifdef USE_SQUARE_PIN\\nfloat marker_distance(in vec2 p, in int line_cap, in int line_join)\\n{\\n // Assuming v_size.x == v.size_y\\n p = abs(p);\\n p = (p.y > p.x) ? p.yx : p.xy;\\n // p is in octant between y=0 and y=x.\\n // Quadratic bezier curve passes through (r, r), (11r/16, 0) and (r, -r).\\n // Circular arc that passes through the same points has center at\\n // x = r + 231r/160 = 2.44275r and y = 0 and hence radius is\\n // x - 11r/16 = 1.75626 precisely.\\n float r = 0.5*v_size.x;\\n float center_x = r*2.44375;\\n float radius = r*1.75626;\\n float dist = radius - distance(p, vec2(center_x, 0.0));\\n\\n // Magic number is 0.5*sin(atan(8/5) - pi/4)\\n dist = max(dist, line_join_distance_incl_miter(\\n p, vec2(r, r), vec2(1.0/SQRT2, 1.0/SQRT2), v_linewidth*0.1124297533493792, line_join,\\n vec2(8.0/sqrt(89.0), -5.0/sqrt(89.0))));\\n\\n return dist;\\n}\\n#endif\\n\\n#if defined(USE_STAR) || defined(USE_STAR_DOT)\\nfloat marker_distance(in vec2 p, in int line_cap, in int line_join)\\n{\\n // Assuming v_size.x == v.size_y\\n const float SQRT5 = sqrt(5.0);\\n const float COS72 = 0.25*(SQRT5 - 1.0);\\n const float SIN72 = sqrt((5.0+SQRT5) / 8.0);\\n\\n float angle = atan(p.x, p.y); // In range -pi to +pi clockwise from +y direction.\\n angle = mod(angle, 0.4*PI) - 0.2*PI; // In range -pi/5 to +pi/5 clockwise from +y direction.\\n p = length(p)*vec2(cos(angle), abs(sin(angle))); // (x,y) in pi/10 (36 degree) sector.\\n\\n // 2 corners are at (r, 0) and (r-a*SIN72, a*COS72) where a = r sqrt(5-2*sqrt(5)).\\n // Line has outward-facing unit normal vec2(COS72, SIN72) and distance from\\n // origin of dot(vec2(r, 0), vec2(COS72, SIN72)) = r*COS72\\n float r = 0.5*v_size.x;\\n float a = r*sqrt(5.0 - 2.0*SQRT5);\\n float dist = dot(p, vec2(COS72, SIN72)) - r*COS72;\\n\\n if (line_join != miter_join) {\\n // Outside corner\\n dist = max(dist, line_join_distance_no_miter(\\n p, vec2(r, 0.0), vec2(1.0, 0.0), v_linewidth*(0.5*COS72), line_join));\\n\\n // Inside corner\\n const float COS36 = sqrt(0.5 + COS72/2.0);\\n const float SIN36 = sqrt(0.5 - COS72/2.0);\\n dist = min(dist, -line_join_distance_no_miter(\\n p, vec2(r-a*SIN72, a*COS72), vec2(-COS36, -SIN36), v_linewidth*(0.5*COS36), line_join));\\n }\\n\\n return dist;\\n}\\n#endif\\n\\n#if defined(USE_TRIANGLE) || defined(USE_TRIANGLE_DOT) || defined(USE_INVERTED_TRIANGLE)\\nfloat marker_distance(in vec2 p, in int line_cap, in int line_join)\\n{\\n // Assuming v_size.x == v.size_y\\n // For normal triangle 3 corners are at (-r, a), (r, a), (0, a-h)=(0, -2h/3)\\n // given r = radius = v_size.x/2, h = SQRT3*r, a = h/3.\\n // Sloping line has outward-facing unit normal vec2(h, -r)/2r = vec2(SQRT3, -1)/2\\n // and distance from origin of a. Horizontal line has outward-facing unit normal\\n // vec2(0, 1) and distance from origin of a.\\n float r = 0.5*v_size.x;\\n float a = r*SQRT3/3.0;\\n\\n // Only need to consider +ve x.\\n#ifdef USE_INVERTED_TRIANGLE\\n p = vec2(abs(p.x), -p.y);\\n#else\\n p = vec2(abs(p.x), p.y);\\n#endif\\n\\n float dist = max(0.5*dot(p, vec2(SQRT3, -1.0)) - a, // Distance from sloping line.\\n p.y - a); // Distance from horizontal line.\\n\\n if (line_join != miter_join) {\\n dist = max(dist, line_join_distance_no_miter(\\n p, vec2(0.0, -(2.0/SQRT3)*r), vec2(0.0, -1.0), v_linewidth*0.25, line_join));\\n\\n dist = max(dist, line_join_distance_no_miter(\\n p, vec2(r, a), vec2(SQRT3/2.0, 0.5), v_linewidth*0.25, line_join));\\n }\\n\\n return dist;\\n}\\n#endif\\n\\n#ifdef USE_TRIANGLE_PIN\\nfloat marker_distance(in vec2 p, in int line_cap, in int line_join)\\n{\\n // Assuming v_size.x == v.size_y\\n float angle = atan(p.x, -p.y); // In range -pi to +pi.\\n angle = mod(angle, PI*2.0/3.0) - PI/3.0; // In range -pi/3 to pi/3.\\n p = length(p)*vec2(cos(angle), abs(sin(angle))); // (x,y) in range 0 to pi/3.\\n // Quadratic bezier curve passes through (a, r), ((a+b)/2, 0) and (a, -r) where\\n // a = r/SQRT3, b = 3a/8 = r SQRT3/8. Circular arc that passes through the same points has\\n // center at (a+x, 0) and radius x+c where c = (a-b)/2 and x = (r**2 - c**2) / (2c).\\n // Ignore r factor until the end so can use const.\\n const float a = 1.0/SQRT3;\\n const float b = SQRT3/8.0;\\n const float c = (a-b)/2.0;\\n const float x = (1.0 - c*c) / (2.0*c);\\n const float center_x = x + a;\\n const float radius = x + c;\\n float r = 0.5*v_size.x;\\n float dist = r*radius - distance(p, vec2(r*center_x, 0.0));\\n\\n // Magic number is 0.5*sin(atan(8*sqrt(3)/5) - pi/3)\\n dist = max(dist, line_join_distance_incl_miter(\\n p, vec2(a*r, r), vec2(0.5, 0.5*SQRT3), v_linewidth*0.0881844526878324, line_join,\\n vec2(8.0*SQRT3, -5.0)/sqrt(217.0)));\\n\\n return dist;\\n}\\n#endif\\n\\n#ifdef USE_X\\nfloat marker_distance(in vec2 p, in int line_cap, in int line_join)\\n{\\n // Assuming v_size.x == v.size_y\\n p = vec2((p.x + p.y)/SQRT2, (p.x - p.y)/SQRT2);\\n return one_cross(p, line_cap, 0.5*v_size.x);\\n}\\n#endif\\n\\n#ifdef USE_Y\\nfloat marker_distance(in vec2 p, in int line_cap, in int line_join)\\n{\\n // Assuming v_size.x == v.size_y\\n return one_y(p, line_cap, 0.5*v_size.x);\\n}\\n#endif\\n\\n// Convert distance from edge of marker to fraction in range 0 to 1, depending\\n// on antialiasing width.\\nfloat distance_to_fraction(in float dist)\\n{\\n return 1.0 - smoothstep(-0.5*u_antialias, 0.5*u_antialias, dist);\\n}\\n\\n// Return fraction from 0 (no fill color) to 1 (full fill color).\\nfloat fill_fraction(in float dist)\\n{\\n return distance_to_fraction(dist);\\n}\\n\\n// Return fraction in range 0 (no line color) to 1 (full line color).\\nfloat line_fraction(in float dist)\\n{\\n return distance_to_fraction(abs(dist) - 0.5*v_linewidth);\\n}\\n\\n// Return fraction (in range 0 to 1) of a color, with premultiplied alpha.\\nvec4 fractional_color(in vec4 color, in float fraction)\\n{\\n color.a *= fraction;\\n color.rgb *= color.a;\\n return color;\\n}\\n\\n// Blend colors that have premultiplied alpha.\\nvec4 blend_colors(in vec4 src, in vec4 dest)\\n{\\n return (1.0 - src.a)*dest + src;\\n}\\n\\n#ifdef APPEND_DOT\\nfloat dot_fraction(in vec2 p)\\n{\\n // Assuming v_size.x == v_size.y\\n float radius = 0.125*v_size.x;\\n float dot_distance = max(length(p) - radius, -0.5*u_antialias);\\n return fill_fraction(dot_distance);\\n}\\n#endif\\n\\n#ifdef HATCH\\n// Wrap coordinate(s) by removing integer part to give distance from center of\\n// repeat, in the range -0.5 to +0.5.\\nfloat wrap(in float x)\\n{\\n return fract(x) - 0.5;\\n}\\n\\nvec2 wrap(in vec2 xy)\\n{\\n return fract(xy) - 0.5;\\n}\\n\\n// Return fraction from 0 (no hatch color) to 1 (full hatch color).\\nfloat hatch_fraction(in vec2 coords, in int hatch_pattern)\\n{\\n float scale = v_hatch_scale; // Hatch repeat distance.\\n\\n // Coordinates and linewidth/halfwidth are scaled to hatch repeat distance.\\n coords = coords / scale;\\n float halfwidth = 0.5*v_hatch_weight / scale; // Half the hatch linewidth.\\n\\n // Default is to return fraction of zero, i.e. no pattern.\\n float dist = u_antialias;\\n\\n if (hatch_pattern == hatch_dot) {\\n const float dot_radius = 0.25;\\n dist = length(wrap(coords)) - dot_radius;\\n }\\n else if (hatch_pattern == hatch_ring) {\\n const float ring_radius = 0.25;\\n dist = abs(length(wrap(coords)) - ring_radius) - halfwidth;\\n }\\n else if (hatch_pattern == hatch_horizontal_line) {\\n dist = abs(wrap(coords.y)) - halfwidth;\\n }\\n else if (hatch_pattern == hatch_vertical_line) {\\n dist = abs(wrap(coords.x)) - halfwidth;\\n }\\n else if (hatch_pattern == hatch_cross) {\\n dist = min(abs(wrap(coords.x)), abs(wrap(coords.y))) - halfwidth;\\n }\\n else if (hatch_pattern == hatch_horizontal_dash) {\\n // Dashes have square caps.\\n const float halflength = 0.25;\\n dist = max(abs(wrap(coords.y)),\\n abs(wrap(coords.x) + 0.25) - halflength) - halfwidth;\\n }\\n else if (hatch_pattern == hatch_vertical_dash) {\\n const float halflength = 0.25;\\n dist = max(abs(wrap(coords.x)),\\n abs(wrap(coords.y) + 0.25) - halflength) - halfwidth;\\n }\\n else if (hatch_pattern == hatch_spiral) {\\n vec2 wrap2 = wrap(coords);\\n float angle = wrap(atan(wrap2.y, wrap2.x) / (2.0*PI));\\n // Canvas spiral radius increases by scale*pi/15 each rotation.\\n const float dr = PI/15.0;\\n float radius = length(wrap2);\\n // At any angle, spiral lines are equally spaced dr apart.\\n // Find distance to nearest of these lines.\\n float frac = fract((radius - dr*angle) / dr); // 0 to 1.\\n dist = dr*(abs(frac - 0.5));\\n dist = min(dist, radius) - halfwidth; // Consider center point also.\\n }\\n else if (hatch_pattern == hatch_right_diagonal_line) {\\n dist = abs(wrap(2.0*coords.x + coords.y))/sqrt(5.0) - halfwidth;\\n }\\n else if (hatch_pattern == hatch_left_diagonal_line) {\\n dist = abs(wrap(2.0*coords.x - coords.y))/sqrt(5.0) - halfwidth;\\n }\\n else if (hatch_pattern == hatch_diagonal_cross) {\\n coords = vec2(coords.x + coords.y + 0.5, coords.x - coords.y + 0.5);\\n dist = min(abs(wrap(coords.x)), abs(wrap(coords.y))) / SQRT2 - halfwidth;\\n }\\n else if (hatch_pattern == hatch_right_diagonal_dash) {\\n float across = coords.x + coords.y + 0.5;\\n dist = abs(wrap(across)) / SQRT2; // Distance to nearest solid line.\\n\\n across = floor(across); // Offset for dash.\\n float along = wrap(0.5*(coords.x - coords.y + across));\\n const float halflength = 0.25;\\n along = abs(along) - halflength; // Distance along line.\\n\\n dist = max(dist, along) - halfwidth;\\n }\\n else if (hatch_pattern == hatch_left_diagonal_dash) {\\n float across = coords.x - coords.y + 0.5;\\n dist = abs(wrap(across)) / SQRT2; // Distance to nearest solid line.\\n\\n across = floor(across); // Offset for dash.\\n float along = wrap(0.5*(coords.x + coords.y + across));\\n const float halflength = 0.25;\\n along = abs(along) - halflength; // Distance along line.\\n\\n dist = max(dist, along) - halfwidth;\\n }\\n else if (hatch_pattern == hatch_horizontal_wave) {\\n float wrapx = wrap(coords.x);\\n float wrapy = wrap(coords.y - 0.25 + abs(wrapx));\\n dist = abs(wrapy) / SQRT2 - halfwidth;\\n }\\n else if (hatch_pattern == hatch_vertical_wave) {\\n float wrapy = wrap(coords.y);\\n float wrapx = wrap(coords.x - 0.25 + abs(wrapy));\\n dist = abs(wrapx) / SQRT2 - halfwidth;\\n }\\n else if (hatch_pattern == hatch_criss_cross) {\\n float plus = min(abs(wrap(coords.x)), abs(wrap(coords.y)));\\n\\n coords = vec2(coords.x + coords.y + 0.5, coords.x - coords.y + 0.5);\\n float X = min(abs(wrap(coords.x)), abs(wrap(coords.y))) / SQRT2;\\n\\n dist = min(plus, X) - halfwidth;\\n }\\n\\n return distance_to_fraction(dist*scale);\\n}\\n#endif\\n\\nvoid main()\\n{\\n int line_cap = int(v_line_cap + 0.5);\\n int line_join = int(v_line_join + 0.5);\\n#ifdef HATCH\\n int hatch_pattern = int(v_hatch_pattern + 0.5);\\n#endif\\n\\n float dist = marker_distance(v_coords, line_cap, line_join);\\n\\n#ifdef LINE_ONLY\\n vec4 color = vec4(0.0, 0.0, 0.0, 0.0);\\n#else\\n float fill_frac = fill_fraction(dist);\\n vec4 color = fractional_color(v_fill_color, fill_frac);\\n#endif\\n\\n#if defined(HATCH) && !defined(LINE_ONLY)\\n if (hatch_pattern > 0 && fill_frac > 0.0) {\\n float hatch_frac = hatch_fraction(v_hatch_coords, hatch_pattern);\\n vec4 hatch_color = fractional_color(v_hatch_color, hatch_frac*fill_frac);\\n color = blend_colors(hatch_color, color);\\n }\\n#endif\\n\\n float line_frac = line_fraction(dist);\\n\\n#ifdef APPEND_DOT\\n line_frac = max(line_frac, dot_fraction(v_coords));\\n#endif\\n#ifdef APPEND_CROSS\\n line_frac = max(line_frac, line_fraction(one_cross(v_coords, line_cap, 0.5*v_size.x)));\\n#endif\\n#ifdef APPEND_CROSS_2\\n vec2 lengths = vec2(v_size.x/3.0, v_size.x/2.0);\\n line_frac = max(line_frac, line_fraction(one_cross_2(v_coords, line_cap, lengths)));\\n#endif\\n#ifdef APPEND_X\\n vec2 p = vec2((v_coords.x + v_coords.y)/SQRT2, (v_coords.x - v_coords.y)/SQRT2);\\n line_frac = max(line_frac, line_fraction(one_cross(p, line_cap, APPEND_X_LEN)));\\n#endif\\n#ifdef APPEND_Y\\n line_frac = max(line_frac, line_fraction(one_y(v_coords, line_cap, 0.5*v_size.x)));\\n#endif\\n\\n if (line_frac > 0.0) {\\n vec4 line_color = fractional_color(v_line_color, line_frac);\\n color = blend_colors(line_color, color);\\n }\\n\\n gl_FragColor = color;\\n}\\n\"},\n 419: function _(t,_,i,h,e){h();const s=t(420),a=t(421),r=t(422);class l extends s.BaseGLGlyph{constructor(t,_){super(t,_),this.glyph=_,this._antialias=1.5,this._show_all=!1}_draw_one_marker_type(t,_,i){const h={scissor:this.regl_wrapper.scissor,viewport:this.regl_wrapper.viewport,canvas_size:[_.width,_.height],pixel_ratio:_.pixel_ratio,center:i._centers,width:i._widths,height:i._heights,angle:i._angles,size_hint:(0,r.marker_type_to_size_hint)(t),nmarkers:i.nvertices,antialias:this._antialias,linewidth:this._linewidths,line_color:this._line_rgba,fill_color:this._fill_rgba,line_cap:this._line_caps,line_join:this._line_joins,show:this._show};if(this._have_hatch){const _=Object.assign(Object.assign({},h),{hatch_pattern:this._hatch_patterns,hatch_scale:this._hatch_scales,hatch_weight:this._hatch_weights,hatch_color:this._hatch_rgba});this.regl_wrapper.marker_hatch(t)(_)}else this.regl_wrapper.marker_no_hatch(t)(h)}_set_visuals(){const t=this._get_visuals(),_=t.fill,i=t.line;if(null==this._linewidths&&(this._linewidths=new a.Float32Buffer(this.regl_wrapper),this._line_caps=new a.Uint8Buffer(this.regl_wrapper),this._line_joins=new a.Uint8Buffer(this.regl_wrapper),this._line_rgba=new a.NormalizedUint8Buffer(this.regl_wrapper),this._fill_rgba=new a.NormalizedUint8Buffer(this.regl_wrapper)),this._linewidths.set_from_prop(i.line_width),this._line_caps.set_from_line_cap(i.line_cap),this._line_joins.set_from_line_join(i.line_join),this._line_rgba.set_from_color(i.line_color,i.line_alpha),this._fill_rgba.set_from_color(_.fill_color,_.fill_alpha),this._have_hatch=t.hatch.doit,this._have_hatch){const _=t.hatch;null==this._hatch_patterns&&(this._hatch_patterns=new a.Uint8Buffer(this.regl_wrapper),this._hatch_scales=new a.Float32Buffer(this.regl_wrapper),this._hatch_weights=new a.Float32Buffer(this.regl_wrapper),this._hatch_rgba=new a.NormalizedUint8Buffer(this.regl_wrapper)),this._hatch_patterns.set_from_hatch_pattern(_.hatch_pattern),this._hatch_scales.set_from_prop(_.hatch_scale),this._hatch_weights.set_from_prop(_.hatch_weight),this._hatch_rgba.set_from_color(_.hatch_color,_.hatch_alpha)}}}i.BaseMarkerGL=l,l.__name__=\"BaseMarkerGL\",l.missing_point=-1e4},\n 420: function _(e,t,s,i,h){i();class a{constructor(e,t){this.glyph=t,this.nvertices=0,this.size_changed=!1,this.data_changed=!1,this.visuals_changed=!1,this.regl_wrapper=e}set_data_changed(){const{data_size:e}=this.glyph;e!=this.nvertices&&(this.nvertices=e,this.size_changed=!0),this.data_changed=!0}set_visuals_changed(){this.visuals_changed=!0}render(e,t,s){if(0==t.length)return!0;const{width:i,height:h}=this.glyph.renderer.plot_view.canvas_view.webgl.canvas,a={pixel_ratio:this.glyph.renderer.plot_view.canvas_view.pixel_ratio,width:i,height:h};return this.draw(t,s,a),!0}}s.BaseGLGlyph=a,a.__name__=\"BaseGLGlyph\"},\n 421: function _(r,t,a,e,s){e();const i=r(422),_=r(22);class n{constructor(r){this.regl_wrapper=r,this.is_scalar=!0}get_sized_array(r){return null!=this.array&&this.array.length==r||(this.array=this.new_array(r)),this.array}is_normalized(){return!1}get length(){return null!=this.array?this.array.length:0}set_from_array(r){const t=r.length,a=this.get_sized_array(t);for(let e=0;e0}_set_data(){const s=this.glyph.sx.length,i=s-1;this._is_closed=s>2&&this.glyph.sx[0]==this.glyph.sx[s-1]&&this.glyph.sy[0]==this.glyph.sy[s-1]&&isFinite(this.glyph.sx[0])&&isFinite(this.glyph.sy[0]),null==this._points&&(this._points=new o.Float32Buffer(this.regl_wrapper));const t=this._points.get_sized_array(2*(s+2));for(let i=1;is/255)),this._linewidth=s.line_width.value,this._linewidth<1&&(this._color[3]*=this._linewidth,this._linewidth=1),this._line_dash=(0,a.resolve_line_dash)(s.line_dash.value),this._is_dashed()&&([this._dash_tex_info,this._dash_tex,this._dash_scale]=this.regl_wrapper.get_dash(this._line_dash),this._dash_offset=s.line_dash_offset.value)}}t.LineGL=r,r.__name__=\"LineGL\"},\n 427: function _(s,t,i,e,r){e();const h=s(421),a=s(424);class n extends a.SingleMarkerGL{constructor(s,t){super(s,t),this.glyph=t}draw(s,t,i){this._draw_impl(s,i,t.glglyph,\"square\")}_get_visuals(){return this.glyph.visuals}_set_data(){const s=this.nvertices;null==this._centers&&(this._centers=new h.Float32Buffer(this.regl_wrapper),this._widths=new h.Float32Buffer(this.regl_wrapper),this._heights=new h.Float32Buffer(this.regl_wrapper),this._angles=new h.Float32Buffer(this.regl_wrapper),this._angles.set_from_scalar(0));const t=this._centers.get_sized_array(2*s),i=this._heights.get_sized_array(s),e=this._widths.get_sized_array(s);for(let r=0;r1||s.length<_){this._show_all=!1,n.fill(0),r=0;for(const e of s)1!=h&&i._marker_types.get(e)!=t||(n[e]=255,r++)}else this._show_all&&a==_||(this._show_all=!0,n.fill(255));this._show.update(),0!=r&&this._draw_one_marker_type(t,e,i)}}_get_visuals(){return this.glyph.visuals}_set_data(){const s=this.nvertices;null==this._centers&&(this._centers=new r.Float32Buffer(this.regl_wrapper),this._widths=new r.Float32Buffer(this.regl_wrapper),this._heights=this._widths,this._angles=new r.Float32Buffer(this.regl_wrapper));const t=this._centers.get_sized_array(2*s);for(let e=0;ethis.render()))}remove(){null!=this.icon_view&&this.icon_view.remove(),super.remove()}styles(){return[...super.styles(),d.default]}_render_button(...t){return(0,c.button)({type:\"button\",disabled:this.model.disabled,class:[h.btn,h[`btn_${this.model.button_type}`]]},...t)}render(){super.render(),this.button_el=this._render_button(this.model.label),this.button_el.addEventListener(\"click\",(()=>this.click())),null!=this.icon_view&&(\"\"!=this.model.label?(0,c.prepend)(this.button_el,this.icon_view.el,(0,c.nbsp)()):(0,c.prepend)(this.button_el,this.icon_view.el),this.icon_view.render()),this.group_el=(0,c.div)({class:h.btn_group},this.button_el),this.el.appendChild(this.group_el)}click(){}}n.AbstractButtonView=b,b.__name__=\"AbstractButtonView\";class p extends _.Control{constructor(t){super(t)}}n.AbstractButton=p,o=p,p.__name__=\"AbstractButton\",o.define((({String:t,Ref:e,Nullable:n})=>({label:[t,\"Button\"],icon:[n(e(a.AbstractIcon)),null],button_type:[r.ButtonType,\"default\"]})))},\n 442: function _(t,e,o,s,n){s();const i=t(512),l=t(43);class c extends i.WidgetView{connect_signals(){super.connect_signals();const t=this.model.properties;this.on_change(t.disabled,(()=>{for(const t of this.controls())(0,l.toggle_attribute)(t,\"disabled\",this.model.disabled)}))}}o.ControlView=c,c.__name__=\"ControlView\";class r extends i.Widget{constructor(t){super(t)}}o.Control=r,r.__name__=\"Control\"},\n 512: function _(i,e,t,n,o){var r;n();const s=i(312);class _ extends s.HTMLBoxView{get orientation(){return\"horizontal\"}get default_size(){return this.model.default_size}_width_policy(){return\"horizontal\"==this.orientation?super._width_policy():\"fixed\"}_height_policy(){return\"horizontal\"==this.orientation?\"fixed\":super._height_policy()}box_sizing(){const i=super.box_sizing();return\"horizontal\"==this.orientation?null==i.width&&(i.width=this.default_size):null==i.height&&(i.height=this.default_size),i}}t.WidgetView=_,_.__name__=\"WidgetView\";class h extends s.HTMLBox{constructor(i){super(i)}}t.Widget=h,r=h,h.__name__=\"Widget\",r.define((({Number:i})=>({default_size:[i,300]}))),r.override({margin:[5,5,5,5]})},\n 444: function _(c,t,s,n,e){n();const o=c(53),_=c(226);class a extends _.DOMView{}s.AbstractIconView=a,a.__name__=\"AbstractIconView\";class r extends o.Model{constructor(c){super(c)}}s.AbstractIcon=r,r.__name__=\"AbstractIcon\"},\n 445: function _(e,t,n,s,i){s();const h=e(1);var o;const _=e(446),u=e(43),r=e(10),c=(0,h.__importStar)(e(229)),a=c;class l extends _.TextInputView{constructor(){super(...arguments),this._open=!1,this._last_value=\"\",this._hover_index=0}styles(){return[...super.styles(),c.default]}render(){super.render(),this.input_el.addEventListener(\"keydown\",(e=>this._keydown(e))),this.input_el.addEventListener(\"keyup\",(e=>this._keyup(e))),this.menu=(0,u.div)({class:[a.menu,a.below]}),this.menu.addEventListener(\"click\",(e=>this._menu_click(e))),this.menu.addEventListener(\"mouseover\",(e=>this._menu_hover(e))),this.el.appendChild(this.menu),(0,u.undisplay)(this.menu)}change_input(){this._open&&this.menu.children.length>0?(this.model.value=this.menu.children[this._hover_index].textContent,this.input_el.focus(),this._hide_menu()):this.model.restrict||super.change_input()}_update_completions(e){(0,u.empty)(this.menu);for(const t of e){const e=(0,u.div)(t);this.menu.appendChild(e)}e.length>0&&this.menu.children[0].classList.add(a.active)}_show_menu(){if(!this._open){this._open=!0,this._hover_index=0,this._last_value=this.model.value,(0,u.display)(this.menu);const e=t=>{const{target:n}=t;n instanceof HTMLElement&&!this.el.contains(n)&&(document.removeEventListener(\"click\",e),this._hide_menu())};document.addEventListener(\"click\",e)}}_hide_menu(){this._open&&(this._open=!1,(0,u.undisplay)(this.menu))}_menu_click(e){e.target!=e.currentTarget&&e.target instanceof Element&&(this.model.value=e.target.textContent,this.input_el.focus(),this._hide_menu())}_menu_hover(e){if(e.target!=e.currentTarget&&e.target instanceof Element){let t=0;for(t=0;t0&&(this.menu.children[this._hover_index].classList.remove(a.active),this._hover_index=(0,r.clamp)(e,0,t-1),this.menu.children[this._hover_index].classList.add(a.active))}_keydown(e){}_keyup(e){switch(e.keyCode){case u.Keys.Enter:this.change_input();break;case u.Keys.Esc:this._hide_menu();break;case u.Keys.Up:this._bump_hover(this._hover_index-1);break;case u.Keys.Down:this._bump_hover(this._hover_index+1);break;default:{const e=this.input_el.value;if(e.lengthe:e=>e.toLowerCase();for(const n of this.model.completions)s(n).startsWith(s(e))&&t.push(n);this._update_completions(t),0==t.length?this._hide_menu():this._show_menu()}}}}n.AutocompleteInputView=l,l.__name__=\"AutocompleteInputView\";class d extends _.TextInput{constructor(e){super(e)}}n.AutocompleteInput=d,o=d,d.__name__=\"AutocompleteInput\",o.prototype.default_view=l,o.define((({Boolean:e,Int:t,String:n,Array:s})=>({completions:[s(n),[]],min_characters:[t,2],case_sensitive:[e,!0],restrict:[e,!0]})))},\n 446: function _(t,e,n,p,_){p();const u=t(1);var i;const s=t(447),r=t(43),x=(0,u.__importStar)(t(449));class a extends s.TextLikeInputView{_render_input(){this.input_el=(0,r.input)({type:\"text\",class:x.input})}}n.TextInputView=a,a.__name__=\"TextInputView\";class c extends s.TextLikeInput{constructor(t){super(t)}}n.TextInput=c,i=c,c.__name__=\"TextInput\",i.prototype.default_view=a},\n 447: function _(e,t,n,i,l){var s;i();const h=e(448);class a extends h.InputWidgetView{connect_signals(){super.connect_signals(),this.connect(this.model.properties.name.change,(()=>{var e;return this.input_el.name=null!==(e=this.model.name)&&void 0!==e?e:\"\"})),this.connect(this.model.properties.value.change,(()=>this.input_el.value=this.model.value)),this.connect(this.model.properties.value_input.change,(()=>this.input_el.value=this.model.value_input)),this.connect(this.model.properties.disabled.change,(()=>this.input_el.disabled=this.model.disabled)),this.connect(this.model.properties.placeholder.change,(()=>this.input_el.placeholder=this.model.placeholder)),this.connect(this.model.properties.max_length.change,(()=>{const{max_length:e}=this.model;null!=e?this.input_el.maxLength=e:this.input_el.removeAttribute(\"maxLength\")}))}render(){var e;super.render(),this._render_input();const{input_el:t}=this;t.name=null!==(e=this.model.name)&&void 0!==e?e:\"\",t.value=this.model.value,t.disabled=this.model.disabled,t.placeholder=this.model.placeholder,null!=this.model.max_length&&(t.maxLength=this.model.max_length),t.addEventListener(\"change\",(()=>this.change_input())),t.addEventListener(\"input\",(()=>this.change_input_value())),this.group_el.appendChild(t)}change_input(){this.model.value=this.input_el.value,super.change_input()}change_input_value(){this.model.value_input=this.input_el.value,super.change_input()}}n.TextLikeInputView=a,a.__name__=\"TextLikeInputView\";class u extends h.InputWidget{constructor(e){super(e)}}n.TextLikeInput=u,s=u,u.__name__=\"TextLikeInput\",s.define((({Int:e,String:t,Nullable:n})=>({value:[t,\"\"],value_input:[t,\"\"],placeholder:[t,\"\"],max_length:[n(e),null]})))},\n 448: function _(e,t,n,s,l){s();const i=e(1);var o;const r=e(442),_=e(43),p=(0,i.__importStar)(e(449)),a=p;class c extends r.ControlView{*controls(){yield this.input_el}connect_signals(){super.connect_signals(),this.connect(this.model.properties.title.change,(()=>{this.label_el.textContent=this.model.title}))}styles(){return[...super.styles(),p.default]}render(){super.render();const{title:e}=this.model;this.label_el=(0,_.label)({style:{display:0==e.length?\"none\":\"\"}},e),this.group_el=(0,_.div)({class:a.input_group},this.label_el),this.el.appendChild(this.group_el)}change_input(){}}n.InputWidgetView=c,c.__name__=\"InputWidgetView\";class d extends r.Control{constructor(e){super(e)}}n.InputWidget=d,o=d,d.__name__=\"InputWidget\",o.define((({String:e})=>({title:[e,\"\"]})))},\n 449: function _(o,p,t,n,i){n(),t.root=\"bk-root\",t.input=\"bk-input\",t.input_group=\"bk-input-group\",t.inline=\"bk-inline\",t.spin_wrapper=\"bk-spin-wrapper\",t.spin_btn=\"bk-spin-btn\",t.spin_btn_up=\"bk-spin-btn-up\",t.spin_btn_down=\"bk-spin-btn-down\",t.default='.bk-root .bk-input{display:inline-block;width:100%;flex-grow:1;min-height:31px;padding:0 12px;background-color:#fff;border:1px solid #ccc;border-radius:4px;}.bk-root .bk-input:focus{border-color:#66afe9;outline:0;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);}.bk-root .bk-input::placeholder,.bk-root .bk-input:-ms-input-placeholder,.bk-root .bk-input::-moz-placeholder,.bk-root .bk-input::-webkit-input-placeholder{color:#999;opacity:1;}.bk-root .bk-input[disabled]{cursor:not-allowed;background-color:#eee;opacity:1;}.bk-root select:not([multiple]).bk-input,.bk-root select:not([size]).bk-input{height:auto;appearance:none;-webkit-appearance:none;background-image:url(\\'data:image/svg+xml;utf8,\\');background-position:right 0.5em center;background-size:8px 6px;background-repeat:no-repeat;}.bk-root select[multiple].bk-input,.bk-root select[size].bk-input,.bk-root textarea.bk-input{height:auto;}.bk-root .bk-input-group{width:100%;height:100%;display:inline-flex;flex-wrap:nowrap;align-items:start;flex-direction:column;white-space:nowrap;}.bk-root .bk-input-group.bk-inline{flex-direction:row;}.bk-root .bk-input-group.bk-inline > *:not(:first-child){margin-left:5px;}.bk-root .bk-input-group input[type=\"checkbox\"] + span,.bk-root .bk-input-group input[type=\"radio\"] + span{position:relative;top:-2px;margin-left:3px;}.bk-root .bk-input-group > .bk-spin-wrapper{display:inherit;width:inherit;height:inherit;position:relative;overflow:hidden;padding:0;vertical-align:middle;}.bk-root .bk-input-group > .bk-spin-wrapper input{padding-right:20px;}.bk-root .bk-input-group > .bk-spin-wrapper > .bk-spin-btn{position:absolute;display:block;height:50%;min-height:0;min-width:0;width:30px;padding:0;margin:0;right:0;border:none;background:none;cursor:pointer;}.bk-root .bk-input-group > .bk-spin-wrapper > .bk-spin-btn:before{content:\"\";display:inline-block;transform:translateY(-50%);border-left:5px solid transparent;border-right:5px solid transparent;}.bk-root .bk-input-group > .bk-spin-wrapper > .bk-spin-btn.bk-spin-btn-up{top:0;}.bk-root .bk-input-group > .bk-spin-wrapper > .bk-spin-btn.bk-spin-btn-up:before{border-bottom:5px solid black;}.bk-root .bk-input-group > .bk-spin-wrapper > .bk-spin-btn.bk-spin-btn-up:disabled:before{border-bottom-color:grey;}.bk-root .bk-input-group > .bk-spin-wrapper > .bk-spin-btn.bk-spin-btn-down{bottom:0;}.bk-root .bk-input-group > .bk-spin-wrapper > .bk-spin-btn.bk-spin-btn-down:before{border-top:5px solid black;}.bk-root .bk-input-group > .bk-spin-wrapper > .bk-spin-btn.bk-spin-btn-down:disabled:before{border-top-color:grey;}'},\n 450: function _(t,e,n,o,c){var s;o();const u=t(441),r=t(251);class i extends u.AbstractButtonView{click(){this.model.trigger_event(new r.ButtonClick),super.click()}}n.ButtonView=i,i.__name__=\"ButtonView\";class _ extends u.AbstractButton{constructor(t){super(t)}}n.Button=_,s=_,_.__name__=\"Button\",s.prototype.default_view=i,s.override({label:\"Button\"})},\n 451: function _(t,e,o,c,a){c();const s=t(1);var n;const i=t(452),r=t(43),u=(0,s.__importStar)(t(318));class _ extends i.ButtonGroupView{get active(){return new Set(this.model.active)}change_active(t){const{active:e}=this;e.has(t)?e.delete(t):e.add(t),this.model.active=[...e].sort()}_update_active(){const{active:t}=this;this._buttons.forEach(((e,o)=>{(0,r.classes)(e).toggle(u.active,t.has(o))}))}}o.CheckboxButtonGroupView=_,_.__name__=\"CheckboxButtonGroupView\";class h extends i.ButtonGroup{constructor(t){super(t)}}o.CheckboxButtonGroup=h,n=h,h.__name__=\"CheckboxButtonGroup\",n.prototype.default_view=_,n.define((({Int:t,Array:e})=>({active:[e(t),[]]})))},\n 452: function _(t,e,n,s,i){s();const o=t(1);var r;const a=t(453),l=t(20),d=t(43),u=(0,o.__importStar)(t(318)),_=u;class c extends a.OrientedControlView{get default_size(){return\"horizontal\"==this.orientation?this.model.default_size:void 0}*controls(){yield*this._buttons}connect_signals(){super.connect_signals();const t=this.model.properties;this.on_change(t.button_type,(()=>this.render())),this.on_change(t.labels,(()=>this.render())),this.on_change(t.active,(()=>this._update_active()))}styles(){return[...super.styles(),u.default]}render(){super.render(),this._buttons=this.model.labels.map(((t,e)=>{const n=(0,d.div)({class:[_.btn,_[`btn_${this.model.button_type}`]],disabled:this.model.disabled},t);return n.addEventListener(\"click\",(()=>this.change_active(e))),n})),this._update_active();const t=\"horizontal\"==this.model.orientation?_.horizontal:_.vertical,e=(0,d.div)({class:[_.btn_group,t]},this._buttons);this.el.appendChild(e)}}n.ButtonGroupView=c,c.__name__=\"ButtonGroupView\";class h extends a.OrientedControl{constructor(t){super(t)}}n.ButtonGroup=h,r=h,h.__name__=\"ButtonGroup\",r.define((({String:t,Array:e})=>({labels:[e(t),[]],button_type:[l.ButtonType,\"default\"]})))},\n 453: function _(n,t,e,o,r){var i;o();const a=n(442),l=n(20);class s extends a.ControlView{get orientation(){return this.model.orientation}}e.OrientedControlView=s,s.__name__=\"OrientedControlView\";class _ extends a.Control{constructor(n){super(n)}}e.OrientedControl=_,i=_,_.__name__=\"OrientedControl\",i.define((()=>({orientation:[l.Orientation,\"horizontal\"]})))},\n 454: function _(e,t,n,i,s){i();const o=e(1);var a;const c=e(455),l=e(43),d=e(9),p=(0,o.__importStar)(e(449));class r extends c.InputGroupView{render(){super.render();const e=(0,l.div)({class:[p.input_group,this.model.inline?p.inline:null]});this.el.appendChild(e);const{active:t,labels:n}=this.model;this._inputs=[];for(let i=0;ithis.change_active(i))),this._inputs.push(s),this.model.disabled&&(s.disabled=!0),(0,d.includes)(t,i)&&(s.checked=!0);const o=(0,l.label)(s,(0,l.span)(n[i]));e.appendChild(o)}}change_active(e){const t=new Set(this.model.active);t.has(e)?t.delete(e):t.add(e),this.model.active=[...t].sort()}}n.CheckboxGroupView=r,r.__name__=\"CheckboxGroupView\";class h extends c.InputGroup{constructor(e){super(e)}}n.CheckboxGroup=h,a=h,h.__name__=\"CheckboxGroup\",a.prototype.default_view=r,a.define((({Boolean:e,Int:t,String:n,Array:i})=>({active:[i(t),[]],labels:[i(n),[]],inline:[e,!1]})))},\n 455: function _(n,t,e,s,o){s();const r=n(1),u=n(442),c=(0,r.__importDefault)(n(449));class _ extends u.ControlView{*controls(){yield*this._inputs}connect_signals(){super.connect_signals(),this.connect(this.model.change,(()=>this.render()))}styles(){return[...super.styles(),c.default]}}e.InputGroupView=_,_.__name__=\"InputGroupView\";class i extends u.Control{constructor(n){super(n)}}e.InputGroup=i,i.__name__=\"InputGroup\"},\n 456: function _(e,t,i,n,o){n();const s=e(1);var l;const r=e(448),c=e(43),a=e(22),d=(0,s.__importStar)(e(449));class h extends r.InputWidgetView{connect_signals(){super.connect_signals(),this.connect(this.model.properties.name.change,(()=>{var e;return this.input_el.name=null!==(e=this.model.name)&&void 0!==e?e:\"\"})),this.connect(this.model.properties.color.change,(()=>this.input_el.value=(0,a.color2hexrgb)(this.model.color))),this.connect(this.model.properties.disabled.change,(()=>this.input_el.disabled=this.model.disabled))}render(){super.render(),this.input_el=(0,c.input)({type:\"color\",class:d.input,name:this.model.name,value:this.model.color,disabled:this.model.disabled}),this.input_el.addEventListener(\"change\",(()=>this.change_input())),this.group_el.appendChild(this.input_el)}change_input(){this.model.color=this.input_el.value,super.change_input()}}i.ColorPickerView=h,h.__name__=\"ColorPickerView\";class p extends r.InputWidget{constructor(e){super(e)}}i.ColorPicker=p,l=p,p.__name__=\"ColorPicker\",l.prototype.default_view=h,l.define((({Color:e})=>({color:[e,\"#000000\"]})))},\n 457: function _(e,t,i,n,s){n();const a=e(1);var l;const o=(0,a.__importDefault)(e(458)),d=e(448),r=e(43),c=e(20),u=e(8),h=(0,a.__importStar)(e(449)),_=(0,a.__importDefault)(e(459));function p(e){const t=[];for(const i of e)if((0,u.isString)(i))t.push(i);else{const[e,n]=i;t.push({from:e,to:n})}return t}class m extends d.InputWidgetView{connect_signals(){super.connect_signals();const{value:e,min_date:t,max_date:i,disabled_dates:n,enabled_dates:s,position:a,inline:l}=this.model.properties;this.connect(e.change,(()=>{var e;return null===(e=this._picker)||void 0===e?void 0:e.setDate(this.model.value)})),this.connect(t.change,(()=>{var e;return null===(e=this._picker)||void 0===e?void 0:e.set(\"minDate\",this.model.min_date)})),this.connect(i.change,(()=>{var e;return null===(e=this._picker)||void 0===e?void 0:e.set(\"maxDate\",this.model.max_date)})),this.connect(n.change,(()=>{var e;return null===(e=this._picker)||void 0===e?void 0:e.set(\"disable\",this.model.disabled_dates)})),this.connect(s.change,(()=>{var e;return null===(e=this._picker)||void 0===e?void 0:e.set(\"enable\",this.model.enabled_dates)})),this.connect(a.change,(()=>{var e;return null===(e=this._picker)||void 0===e?void 0:e.set(\"position\",this.model.position)})),this.connect(l.change,(()=>{var e;return null===(e=this._picker)||void 0===e?void 0:e.set(\"inline\",this.model.inline)}))}remove(){var e;null===(e=this._picker)||void 0===e||e.destroy(),super.remove()}styles(){return[...super.styles(),_.default]}render(){var e,t;null==this._picker&&(super.render(),this.input_el=(0,r.input)({type:\"text\",class:h.input,disabled:this.model.disabled}),this.group_el.appendChild(this.input_el),this._picker=(0,o.default)(this.input_el,{defaultDate:this.model.value,minDate:null!==(e=this.model.min_date)&&void 0!==e?e:void 0,maxDate:null!==(t=this.model.max_date)&&void 0!==t?t:void 0,inline:this.model.inline,position:this.model.position,disable:p(this.model.disabled_dates),enable:p(this.model.enabled_dates),onChange:(e,t,i)=>this._on_change(e,t,i)}))}_on_change(e,t,i){this.model.value=t,this.change_input()}}i.DatePickerView=m,m.__name__=\"DatePickerView\";class v extends d.InputWidget{constructor(e){super(e)}}i.DatePicker=v,l=v,v.__name__=\"DatePicker\",l.prototype.default_view=m,l.define((({Boolean:e,String:t,Array:i,Tuple:n,Or:s,Nullable:a})=>{const l=i(s(t,n(t,t)));return{value:[t],min_date:[a(t),null],max_date:[a(t),null],disabled_dates:[l,[]],enabled_dates:[l,[]],position:[c.CalendarPosition,\"auto\"],inline:[e,!1]}}))},\n 458: function _(e,n,t,a,i){\n /* flatpickr v4.6.6, @license MIT */var o,r;o=this,r=function(){\"use strict\";\n /*! *****************************************************************************\n Copyright (c) Microsoft Corporation.\n \n Permission to use, copy, modify, and/or distribute this software for any\n purpose with or without fee is hereby granted.\n \n THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\n REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\n AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\n INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\n LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\n OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\n PERFORMANCE OF THIS SOFTWARE.\n ***************************************************************************** */var e=function(){return e=Object.assign||function(e){for(var n,t=1,a=arguments.length;t\",noCalendar:!1,now:new Date,onChange:[],onClose:[],onDayCreate:[],onDestroy:[],onKeyDown:[],onMonthChange:[],onOpen:[],onParseConfig:[],onReady:[],onValueUpdate:[],onYearChange:[],onPreCalendarPosition:[],plugins:[],position:\"auto\",positionElement:void 0,prevArrow:\"\",shorthandCurrentMonth:!1,showMonths:1,static:!1,time_24hr:!1,weekNumbers:!1,wrap:!1},i={weekdays:{shorthand:[\"Sun\",\"Mon\",\"Tue\",\"Wed\",\"Thu\",\"Fri\",\"Sat\"],longhand:[\"Sunday\",\"Monday\",\"Tuesday\",\"Wednesday\",\"Thursday\",\"Friday\",\"Saturday\"]},months:{shorthand:[\"Jan\",\"Feb\",\"Mar\",\"Apr\",\"May\",\"Jun\",\"Jul\",\"Aug\",\"Sep\",\"Oct\",\"Nov\",\"Dec\"],longhand:[\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",\"July\",\"August\",\"September\",\"October\",\"November\",\"December\"]},daysInMonth:[31,28,31,30,31,30,31,31,30,31,30,31],firstDayOfWeek:0,ordinal:function(e){var n=e%100;if(n>3&&n<21)return\"th\";switch(n%10){case 1:return\"st\";case 2:return\"nd\";case 3:return\"rd\";default:return\"th\"}},rangeSeparator:\" to \",weekAbbreviation:\"Wk\",scrollTitle:\"Scroll to increment\",toggleTitle:\"Click to toggle\",amPM:[\"AM\",\"PM\"],yearAriaLabel:\"Year\",monthAriaLabel:\"Month\",hourAriaLabel:\"Hour\",minuteAriaLabel:\"Minute\",time_24hr:!1},o=function(e,n){return void 0===n&&(n=2),(\"000\"+e).slice(-1*n)},r=function(e){return!0===e?1:0};function l(e,n,t){var a;return void 0===t&&(t=!1),function(){var i=this,o=arguments;null!==a&&clearTimeout(a),a=window.setTimeout((function(){a=null,t||e.apply(i,o)}),n),t&&!a&&e.apply(i,o)}}var c=function(e){return e instanceof Array?e:[e]};function d(e,n,t){if(!0===t)return e.classList.add(n);e.classList.remove(n)}function s(e,n,t){var a=window.document.createElement(e);return n=n||\"\",t=t||\"\",a.className=n,void 0!==t&&(a.textContent=t),a}function u(e){for(;e.firstChild;)e.removeChild(e.firstChild)}function f(e,n){return n(e)?e:e.parentNode?f(e.parentNode,n):void 0}function m(e,n){var t=s(\"div\",\"numInputWrapper\"),a=s(\"input\",\"numInput \"+e),i=s(\"span\",\"arrowUp\"),o=s(\"span\",\"arrowDown\");if(-1===navigator.userAgent.indexOf(\"MSIE 9.0\")?a.type=\"number\":(a.type=\"text\",a.pattern=\"\\\\d*\"),void 0!==n)for(var r in n)a.setAttribute(r,n[r]);return t.appendChild(a),t.appendChild(i),t.appendChild(o),t}function g(e){try{return\"function\"==typeof e.composedPath?e.composedPath()[0]:e.target}catch(n){return e.target}}var p=function(){},h=function(e,n,t){return t.months[n?\"shorthand\":\"longhand\"][e]},v={D:p,F:function(e,n,t){e.setMonth(t.months.longhand.indexOf(n))},G:function(e,n){e.setHours(parseFloat(n))},H:function(e,n){e.setHours(parseFloat(n))},J:function(e,n){e.setDate(parseFloat(n))},K:function(e,n,t){e.setHours(e.getHours()%12+12*r(new RegExp(t.amPM[1],\"i\").test(n)))},M:function(e,n,t){e.setMonth(t.months.shorthand.indexOf(n))},S:function(e,n){e.setSeconds(parseFloat(n))},U:function(e,n){return new Date(1e3*parseFloat(n))},W:function(e,n,t){var a=parseInt(n),i=new Date(e.getFullYear(),0,2+7*(a-1),0,0,0,0);return i.setDate(i.getDate()-i.getDay()+t.firstDayOfWeek),i},Y:function(e,n){e.setFullYear(parseFloat(n))},Z:function(e,n){return new Date(n)},d:function(e,n){e.setDate(parseFloat(n))},h:function(e,n){e.setHours(parseFloat(n))},i:function(e,n){e.setMinutes(parseFloat(n))},j:function(e,n){e.setDate(parseFloat(n))},l:p,m:function(e,n){e.setMonth(parseFloat(n)-1)},n:function(e,n){e.setMonth(parseFloat(n)-1)},s:function(e,n){e.setSeconds(parseFloat(n))},u:function(e,n){return new Date(parseFloat(n))},w:p,y:function(e,n){e.setFullYear(2e3+parseFloat(n))}},D={D:\"(\\\\w+)\",F:\"(\\\\w+)\",G:\"(\\\\d\\\\d|\\\\d)\",H:\"(\\\\d\\\\d|\\\\d)\",J:\"(\\\\d\\\\d|\\\\d)\\\\w+\",K:\"\",M:\"(\\\\w+)\",S:\"(\\\\d\\\\d|\\\\d)\",U:\"(.+)\",W:\"(\\\\d\\\\d|\\\\d)\",Y:\"(\\\\d{4})\",Z:\"(.+)\",d:\"(\\\\d\\\\d|\\\\d)\",h:\"(\\\\d\\\\d|\\\\d)\",i:\"(\\\\d\\\\d|\\\\d)\",j:\"(\\\\d\\\\d|\\\\d)\",l:\"(\\\\w+)\",m:\"(\\\\d\\\\d|\\\\d)\",n:\"(\\\\d\\\\d|\\\\d)\",s:\"(\\\\d\\\\d|\\\\d)\",u:\"(.+)\",w:\"(\\\\d\\\\d|\\\\d)\",y:\"(\\\\d{2})\"},w={Z:function(e){return e.toISOString()},D:function(e,n,t){return n.weekdays.shorthand[w.w(e,n,t)]},F:function(e,n,t){return h(w.n(e,n,t)-1,!1,n)},G:function(e,n,t){return o(w.h(e,n,t))},H:function(e){return o(e.getHours())},J:function(e,n){return void 0!==n.ordinal?e.getDate()+n.ordinal(e.getDate()):e.getDate()},K:function(e,n){return n.amPM[r(e.getHours()>11)]},M:function(e,n){return h(e.getMonth(),!0,n)},S:function(e){return o(e.getSeconds())},U:function(e){return e.getTime()/1e3},W:function(e,n,t){return t.getWeek(e)},Y:function(e){return o(e.getFullYear(),4)},d:function(e){return o(e.getDate())},h:function(e){return e.getHours()%12?e.getHours()%12:12},i:function(e){return o(e.getMinutes())},j:function(e){return e.getDate()},l:function(e,n){return n.weekdays.longhand[e.getDay()]},m:function(e){return o(e.getMonth()+1)},n:function(e){return e.getMonth()+1},s:function(e){return e.getSeconds()},u:function(e){return e.getTime()},w:function(e){return e.getDay()},y:function(e){return String(e.getFullYear()).substring(2)}},b=function(e){var n=e.config,t=void 0===n?a:n,o=e.l10n,r=void 0===o?i:o,l=e.isMobile,c=void 0!==l&&l;return function(e,n,a){var i=a||r;return void 0===t.formatDate||c?n.split(\"\").map((function(n,a,o){return w[n]&&\"\\\\\"!==o[a-1]?w[n](e,i,t):\"\\\\\"!==n?n:\"\"})).join(\"\"):t.formatDate(e,n,i)}},C=function(e){var n=e.config,t=void 0===n?a:n,o=e.l10n,r=void 0===o?i:o;return function(e,n,i,o){if(0===e||e){var l,c=o||r,d=e;if(e instanceof Date)l=new Date(e.getTime());else if(\"string\"!=typeof e&&void 0!==e.toFixed)l=new Date(e);else if(\"string\"==typeof e){var s=n||(t||a).dateFormat,u=String(e).trim();if(\"today\"===u)l=new Date,i=!0;else if(/Z$/.test(u)||/GMT$/.test(u))l=new Date(e);else if(t&&t.parseDate)l=t.parseDate(e,s);else{l=t&&t.noCalendar?new Date((new Date).setHours(0,0,0,0)):new Date((new Date).getFullYear(),0,1,0,0,0,0);for(var f=void 0,m=[],g=0,p=0,h=\"\";gl&&(u=a===w.hourElement?u-l-r(!w.amPM):i,m&&H(void 0,1,w.hourElement)),w.amPM&&f&&(1===c?u+d===23:Math.abs(u-d)>c)&&(w.amPM.textContent=w.l10n.amPM[r(w.amPM.textContent===w.l10n.amPM[0])]),a.value=o(u)}}(e);var c=w._input.value;I(),be(),w._input.value!==c&&w._debouncedChange()}function I(){if(void 0!==w.hourElement&&void 0!==w.minuteElement){var e,n,t=(parseInt(w.hourElement.value.slice(-2),10)||0)%24,a=(parseInt(w.minuteElement.value,10)||0)%60,i=void 0!==w.secondElement?(parseInt(w.secondElement.value,10)||0)%60:0;void 0!==w.amPM&&(e=t,n=w.amPM.textContent,t=e%12+12*r(n===w.l10n.amPM[1]));var o=void 0!==w.config.minTime||w.config.minDate&&w.minDateHasTime&&w.latestSelectedDateObj&&0===M(w.latestSelectedDateObj,w.config.minDate,!0);if(void 0!==w.config.maxTime||w.config.maxDate&&w.maxDateHasTime&&w.latestSelectedDateObj&&0===M(w.latestSelectedDateObj,w.config.maxDate,!0)){var l=void 0!==w.config.maxTime?w.config.maxTime:w.config.maxDate;(t=Math.min(t,l.getHours()))===l.getHours()&&(a=Math.min(a,l.getMinutes())),a===l.getMinutes()&&(i=Math.min(i,l.getSeconds()))}if(o){var c=void 0!==w.config.minTime?w.config.minTime:w.config.minDate;(t=Math.max(t,c.getHours()))===c.getHours()&&(a=Math.max(a,c.getMinutes())),a===c.getMinutes()&&(i=Math.max(i,c.getSeconds()))}O(t,a,i)}}function S(e){var n=e||w.latestSelectedDateObj;n&&O(n.getHours(),n.getMinutes(),n.getSeconds())}function _(){var e=w.config.defaultHour,n=w.config.defaultMinute,t=w.config.defaultSeconds;if(void 0!==w.config.minDate){var a=w.config.minDate.getHours(),i=w.config.minDate.getMinutes();(e=Math.max(e,a))===a&&(n=Math.max(i,n)),e===a&&n===i&&(t=w.config.minDate.getSeconds())}if(void 0!==w.config.maxDate){var o=w.config.maxDate.getHours(),r=w.config.maxDate.getMinutes();(e=Math.min(e,o))===o&&(n=Math.min(r,n)),e===o&&n===r&&(t=w.config.maxDate.getSeconds())}return{hours:e,minutes:n,seconds:t}}function O(e,n,t){void 0!==w.latestSelectedDateObj&&w.latestSelectedDateObj.setHours(e%24,n,t||0,0),w.hourElement&&w.minuteElement&&!w.isMobile&&(w.hourElement.value=o(w.config.time_24hr?e:(12+e)%12+12*r(e%12==0)),w.minuteElement.value=o(n),void 0!==w.amPM&&(w.amPM.textContent=w.l10n.amPM[r(e>=12)]),void 0!==w.secondElement&&(w.secondElement.value=o(t)))}function F(e){var n=g(e),t=parseInt(n.value)+(e.delta||0);(t/1e3>1||\"Enter\"===e.key&&!/[^\\d]/.test(t.toString()))&&Q(t)}function N(e,n,t,a){return n instanceof Array?n.forEach((function(n){return N(e,n,t,a)})):e instanceof Array?e.forEach((function(e){return N(e,n,t,a)})):(e.addEventListener(n,t,a),void w._handlers.push({element:e,event:n,handler:t,options:a}))}function A(){pe(\"onChange\")}function P(e,n){var t=void 0!==e?w.parseDate(e):w.latestSelectedDateObj||(w.config.minDate&&w.config.minDate>w.now?w.config.minDate:w.config.maxDate&&w.config.maxDate=0&&M(e,w.selectedDates[1])<=0}(n)&&!ve(n)&&o.classList.add(\"inRange\"),w.weekNumbers&&1===w.config.showMonths&&\"prevMonthDay\"!==e&&t%7==1&&w.weekNumbers.insertAdjacentHTML(\"beforeend\",\"\"+w.config.getWeek(n)+\"\"),pe(\"onDayCreate\",o),o}function L(e){e.focus(),\"range\"===w.config.mode&&ae(e)}function W(e){for(var n=e>0?0:w.config.showMonths-1,t=e>0?w.config.showMonths:-1,a=n;a!=t;a+=e)for(var i=w.daysContainer.children[a],o=e>0?0:i.children.length-1,r=e>0?i.children.length:-1,l=o;l!=r;l+=e){var c=i.children[l];if(-1===c.className.indexOf(\"hidden\")&&X(c.dateObj))return c}}function R(e,n){var t=ee(document.activeElement||document.body),a=void 0!==e?e:t?document.activeElement:void 0!==w.selectedDateElem&&ee(w.selectedDateElem)?w.selectedDateElem:void 0!==w.todayDateElem&&ee(w.todayDateElem)?w.todayDateElem:W(n>0?1:-1);void 0===a?w._input.focus():t?function(e,n){for(var t=-1===e.className.indexOf(\"Month\")?e.dateObj.getMonth():w.currentMonth,a=n>0?w.config.showMonths:-1,i=n>0?1:-1,o=t-w.currentMonth;o!=a;o+=i)for(var r=w.daysContainer.children[o],l=t-w.currentMonth===o?e.$i+n:n<0?r.children.length-1:0,c=r.children.length,d=l;d>=0&&d0?c:-1);d+=i){var s=r.children[d];if(-1===s.className.indexOf(\"hidden\")&&X(s.dateObj)&&Math.abs(e.$i-d)>=Math.abs(n))return L(s)}w.changeMonth(i),R(W(i),0)}(a,n):L(a)}function B(e,n){for(var t=(new Date(e,n,1).getDay()-w.l10n.firstDayOfWeek+7)%7,a=w.utils.getDaysInMonth((n-1+12)%12,e),i=w.utils.getDaysInMonth(n,e),o=window.document.createDocumentFragment(),r=w.config.showMonths>1,l=r?\"prevMonthDay hidden\":\"prevMonthDay\",c=r?\"nextMonthDay hidden\":\"nextMonthDay\",d=a+1-t,u=0;d<=a;d++,u++)o.appendChild(j(l,new Date(e,n-1,d),d,u));for(d=1;d<=i;d++,u++)o.appendChild(j(\"\",new Date(e,n,d),d,u));for(var f=i+1;f<=42-t&&(1===w.config.showMonths||u%7!=0);f++,u++)o.appendChild(j(c,new Date(e,n+1,f%i),f,u));var m=s(\"div\",\"dayContainer\");return m.appendChild(o),m}function J(){if(void 0!==w.daysContainer){u(w.daysContainer),w.weekNumbers&&u(w.weekNumbers);for(var e=document.createDocumentFragment(),n=0;n1||\"dropdown\"!==w.config.monthSelectorType)){var e=function(e){return!(void 0!==w.config.minDate&&w.currentYear===w.config.minDate.getFullYear()&&ew.config.maxDate.getMonth())};w.monthsDropdownContainer.tabIndex=-1,w.monthsDropdownContainer.innerHTML=\"\";for(var n=0;n<12;n++)if(e(n)){var t=s(\"option\",\"flatpickr-monthDropdown-month\");t.value=new Date(w.currentYear,n).getMonth().toString(),t.textContent=h(n,w.config.shorthandCurrentMonth,w.l10n),t.tabIndex=-1,w.currentMonth===n&&(t.selected=!0),w.monthsDropdownContainer.appendChild(t)}}}function U(){var e,n=s(\"div\",\"flatpickr-month\"),t=window.document.createDocumentFragment();w.config.showMonths>1||\"static\"===w.config.monthSelectorType?e=s(\"span\",\"cur-month\"):(w.monthsDropdownContainer=s(\"select\",\"flatpickr-monthDropdown-months\"),w.monthsDropdownContainer.setAttribute(\"aria-label\",w.l10n.monthAriaLabel),N(w.monthsDropdownContainer,\"change\",(function(e){var n=g(e),t=parseInt(n.value,10);w.changeMonth(t-w.currentMonth),pe(\"onMonthChange\")})),K(),e=w.monthsDropdownContainer);var a=m(\"cur-year\",{tabindex:\"-1\"}),i=a.getElementsByTagName(\"input\")[0];i.setAttribute(\"aria-label\",w.l10n.yearAriaLabel),w.config.minDate&&i.setAttribute(\"min\",w.config.minDate.getFullYear().toString()),w.config.maxDate&&(i.setAttribute(\"max\",w.config.maxDate.getFullYear().toString()),i.disabled=!!w.config.minDate&&w.config.minDate.getFullYear()===w.config.maxDate.getFullYear());var o=s(\"div\",\"flatpickr-current-month\");return o.appendChild(e),o.appendChild(a),t.appendChild(o),n.appendChild(t),{container:n,yearElement:i,monthElement:e}}function q(){u(w.monthNav),w.monthNav.appendChild(w.prevMonthNav),w.config.showMonths&&(w.yearElements=[],w.monthElements=[]);for(var e=w.config.showMonths;e--;){var n=U();w.yearElements.push(n.yearElement),w.monthElements.push(n.monthElement),w.monthNav.appendChild(n.container)}w.monthNav.appendChild(w.nextMonthNav)}function $(){w.weekdayContainer?u(w.weekdayContainer):w.weekdayContainer=s(\"div\",\"flatpickr-weekdays\");for(var e=w.config.showMonths;e--;){var n=s(\"div\",\"flatpickr-weekdaycontainer\");w.weekdayContainer.appendChild(n)}return z(),w.weekdayContainer}function z(){if(w.weekdayContainer){var e=w.l10n.firstDayOfWeek,t=n(w.l10n.weekdays.shorthand);e>0&&e\\n \"+t.join(\"\")+\"\\n \\n \"}}function G(e,n){void 0===n&&(n=!0);var t=n?e:e-w.currentMonth;t<0&&!0===w._hidePrevMonthArrow||t>0&&!0===w._hideNextMonthArrow||(w.currentMonth+=t,(w.currentMonth<0||w.currentMonth>11)&&(w.currentYear+=w.currentMonth>11?1:-1,w.currentMonth=(w.currentMonth+12)%12,pe(\"onYearChange\"),K()),J(),pe(\"onMonthChange\"),De())}function V(e){return!(!w.config.appendTo||!w.config.appendTo.contains(e))||w.calendarContainer.contains(e)}function Z(e){if(w.isOpen&&!w.config.inline){var n=g(e),t=V(n),a=n===w.input||n===w.altInput||w.element.contains(n)||e.path&&e.path.indexOf&&(~e.path.indexOf(w.input)||~e.path.indexOf(w.altInput)),i=\"blur\"===e.type?a&&e.relatedTarget&&!V(e.relatedTarget):!a&&!t&&!V(e.relatedTarget),o=!w.config.ignoredFocusElements.some((function(e){return e.contains(n)}));i&&o&&(void 0!==w.timeContainer&&void 0!==w.minuteElement&&void 0!==w.hourElement&&\"\"!==w.input.value&&void 0!==w.input.value&&T(),w.close(),w.config&&\"range\"===w.config.mode&&1===w.selectedDates.length&&(w.clear(!1),w.redraw()))}}function Q(e){if(!(!e||w.config.minDate&&ew.config.maxDate.getFullYear())){var n=e,t=w.currentYear!==n;w.currentYear=n||w.currentYear,w.config.maxDate&&w.currentYear===w.config.maxDate.getFullYear()?w.currentMonth=Math.min(w.config.maxDate.getMonth(),w.currentMonth):w.config.minDate&&w.currentYear===w.config.minDate.getFullYear()&&(w.currentMonth=Math.max(w.config.minDate.getMonth(),w.currentMonth)),t&&(w.redraw(),pe(\"onYearChange\"),K())}}function X(e,n){void 0===n&&(n=!0);var t=w.parseDate(e,void 0,n);if(w.config.minDate&&t&&M(t,w.config.minDate,void 0!==n?n:!w.minDateHasTime)<0||w.config.maxDate&&t&&M(t,w.config.maxDate,void 0!==n?n:!w.maxDateHasTime)>0)return!1;if(0===w.config.enable.length&&0===w.config.disable.length)return!0;if(void 0===t)return!1;for(var a=w.config.enable.length>0,i=a?w.config.enable:w.config.disable,o=0,r=void 0;o=r.from.getTime()&&t.getTime()<=r.to.getTime())return a}return!a}function ee(e){return void 0!==w.daysContainer&&-1===e.className.indexOf(\"hidden\")&&-1===e.className.indexOf(\"flatpickr-disabled\")&&w.daysContainer.contains(e)}function ne(e){e.target!==w._input||e.relatedTarget&&V(e.relatedTarget)||w.setDate(w._input.value,!0,e.target===w.altInput?w.config.altFormat:w.config.dateFormat)}function te(e){var n=g(e),t=w.config.wrap?p.contains(n):n===w._input,a=w.config.allowInput,i=w.isOpen&&(!a||!t),o=w.config.inline&&t&&!a;if(13===e.keyCode&&t){if(a)return w.setDate(w._input.value,!0,n===w.altInput?w.config.altFormat:w.config.dateFormat),n.blur();w.open()}else if(V(n)||i||o){var r=!!w.timeContainer&&w.timeContainer.contains(n);switch(e.keyCode){case 13:r?(e.preventDefault(),T(),se()):ue(e);break;case 27:e.preventDefault(),se();break;case 8:case 46:t&&!w.config.allowInput&&(e.preventDefault(),w.clear());break;case 37:case 39:if(r||t)w.hourElement&&w.hourElement.focus();else if(e.preventDefault(),void 0!==w.daysContainer&&(!1===a||document.activeElement&&ee(document.activeElement))){var l=39===e.keyCode?1:-1;e.ctrlKey?(e.stopPropagation(),G(l),R(W(1),0)):R(void 0,l)}break;case 38:case 40:e.preventDefault();var c=40===e.keyCode?1:-1;w.daysContainer&&void 0!==n.$i||n===w.input||n===w.altInput?e.ctrlKey?(e.stopPropagation(),Q(w.currentYear-c),R(W(1),0)):r||R(void 0,7*c):n===w.currentYearElement?Q(w.currentYear-c):w.config.enableTime&&(!r&&w.hourElement&&w.hourElement.focus(),T(e),w._debouncedChange());break;case 9:if(r){var d=[w.hourElement,w.minuteElement,w.secondElement,w.amPM].concat(w.pluginElements).filter((function(e){return e})),s=d.indexOf(n);if(-1!==s){var u=d[s+(e.shiftKey?-1:1)];e.preventDefault(),(u||w._input).focus()}}else!w.config.noCalendar&&w.daysContainer&&w.daysContainer.contains(n)&&e.shiftKey&&(e.preventDefault(),w._input.focus())}}if(void 0!==w.amPM&&n===w.amPM)switch(e.key){case w.l10n.amPM[0].charAt(0):case w.l10n.amPM[0].charAt(0).toLowerCase():w.amPM.textContent=w.l10n.amPM[0],I(),be();break;case w.l10n.amPM[1].charAt(0):case w.l10n.amPM[1].charAt(0).toLowerCase():w.amPM.textContent=w.l10n.amPM[1],I(),be()}(t||V(n))&&pe(\"onKeyDown\",e)}function ae(e){if(1===w.selectedDates.length&&(!e||e.classList.contains(\"flatpickr-day\")&&!e.classList.contains(\"flatpickr-disabled\"))){for(var n=e?e.dateObj.getTime():w.days.firstElementChild.dateObj.getTime(),t=w.parseDate(w.selectedDates[0],void 0,!0).getTime(),a=Math.min(n,w.selectedDates[0].getTime()),i=Math.max(n,w.selectedDates[0].getTime()),o=!1,r=0,l=0,c=a;ca&&cr)?r=c:c>t&&(!l||c0&&m0&&m>l;return g?(f.classList.add(\"notAllowed\"),[\"inRange\",\"startRange\",\"endRange\"].forEach((function(e){f.classList.remove(e)})),\"continue\"):o&&!g?\"continue\":([\"startRange\",\"inRange\",\"endRange\",\"notAllowed\"].forEach((function(e){f.classList.remove(e)})),void(void 0!==e&&(e.classList.add(n<=w.selectedDates[0].getTime()?\"startRange\":\"endRange\"),tn&&m===t&&f.classList.add(\"endRange\"),m>=r&&(0===l||m<=l)&&(d=t,u=n,(c=m)>Math.min(d,u)&&c0||t.getMinutes()>0||t.getSeconds()>0),w.selectedDates&&(w.selectedDates=w.selectedDates.filter((function(e){return X(e)})),w.selectedDates.length||\"min\"!==e||S(t),be()),w.daysContainer&&(de(),void 0!==t?w.currentYearElement[e]=t.getFullYear().toString():w.currentYearElement.removeAttribute(e),w.currentYearElement.disabled=!!a&&void 0!==t&&a.getFullYear()===t.getFullYear())}}function re(){return w.config.wrap?p.querySelector(\"[data-input]\"):p}function le(){\"object\"!=typeof w.config.locale&&void 0===k.l10ns[w.config.locale]&&w.config.errorHandler(new Error(\"flatpickr: invalid locale \"+w.config.locale)),w.l10n=e(e({},k.l10ns.default),\"object\"==typeof w.config.locale?w.config.locale:\"default\"!==w.config.locale?k.l10ns[w.config.locale]:void 0),D.K=\"(\"+w.l10n.amPM[0]+\"|\"+w.l10n.amPM[1]+\"|\"+w.l10n.amPM[0].toLowerCase()+\"|\"+w.l10n.amPM[1].toLowerCase()+\")\",void 0===e(e({},v),JSON.parse(JSON.stringify(p.dataset||{}))).time_24hr&&void 0===k.defaultConfig.time_24hr&&(w.config.time_24hr=w.l10n.time_24hr),w.formatDate=b(w),w.parseDate=C({config:w.config,l10n:w.l10n})}function ce(e){if(void 0!==w.calendarContainer){pe(\"onPreCalendarPosition\");var n=e||w._positionElement,t=Array.prototype.reduce.call(w.calendarContainer.children,(function(e,n){return e+n.offsetHeight}),0),a=w.calendarContainer.offsetWidth,i=w.config.position.split(\" \"),o=i[0],r=i.length>1?i[1]:null,l=n.getBoundingClientRect(),c=window.innerHeight-l.bottom,s=\"above\"===o||\"below\"!==o&&ct,u=window.pageYOffset+l.top+(s?-t-2:n.offsetHeight+2);if(d(w.calendarContainer,\"arrowTop\",!s),d(w.calendarContainer,\"arrowBottom\",s),!w.config.inline){var f=window.pageXOffset+l.left,m=!1,g=!1;\"center\"===r?(f-=(a-l.width)/2,m=!0):\"right\"===r&&(f-=a-l.width,g=!0),d(w.calendarContainer,\"arrowLeft\",!m&&!g),d(w.calendarContainer,\"arrowCenter\",m),d(w.calendarContainer,\"arrowRight\",g);var p=window.document.body.offsetWidth-(window.pageXOffset+l.right),h=f+a>window.document.body.offsetWidth,v=p+a>window.document.body.offsetWidth;if(d(w.calendarContainer,\"rightMost\",h),!w.config.static)if(w.calendarContainer.style.top=u+\"px\",h)if(v){var D=function(){for(var e=null,n=0;nw.currentMonth+w.config.showMonths-1)&&\"range\"!==w.config.mode;if(w.selectedDateElem=t,\"single\"===w.config.mode)w.selectedDates=[a];else if(\"multiple\"===w.config.mode){var o=ve(a);o?w.selectedDates.splice(parseInt(o),1):w.selectedDates.push(a)}else\"range\"===w.config.mode&&(2===w.selectedDates.length&&w.clear(!1,!1),w.latestSelectedDateObj=a,w.selectedDates.push(a),0!==M(a,w.selectedDates[0],!0)&&w.selectedDates.sort((function(e,n){return e.getTime()-n.getTime()})));if(I(),i){var r=w.currentYear!==a.getFullYear();w.currentYear=a.getFullYear(),w.currentMonth=a.getMonth(),r&&(pe(\"onYearChange\"),K()),pe(\"onMonthChange\")}if(De(),J(),be(),i||\"range\"===w.config.mode||1!==w.config.showMonths?void 0!==w.selectedDateElem&&void 0===w.hourElement&&w.selectedDateElem&&w.selectedDateElem.focus():L(t),void 0!==w.hourElement&&void 0!==w.hourElement&&w.hourElement.focus(),w.config.closeOnSelect){var l=\"single\"===w.config.mode&&!w.config.enableTime,c=\"range\"===w.config.mode&&2===w.selectedDates.length&&!w.config.enableTime;(l||c)&&se()}A()}}w.parseDate=C({config:w.config,l10n:w.l10n}),w._handlers=[],w.pluginElements=[],w.loadedPlugins=[],w._bind=N,w._setHoursFromDate=S,w._positionCalendar=ce,w.changeMonth=G,w.changeYear=Q,w.clear=function(e,n){if(void 0===e&&(e=!0),void 0===n&&(n=!0),w.input.value=\"\",void 0!==w.altInput&&(w.altInput.value=\"\"),void 0!==w.mobileInput&&(w.mobileInput.value=\"\"),w.selectedDates=[],w.latestSelectedDateObj=void 0,!0===n&&(w.currentYear=w._initialDate.getFullYear(),w.currentMonth=w._initialDate.getMonth()),!0===w.config.enableTime){var t=_(),a=t.hours,i=t.minutes,o=t.seconds;O(a,i,o)}w.redraw(),e&&pe(\"onChange\")},w.close=function(){w.isOpen=!1,w.isMobile||(void 0!==w.calendarContainer&&w.calendarContainer.classList.remove(\"open\"),void 0!==w._input&&w._input.classList.remove(\"active\")),pe(\"onClose\")},w._createElement=s,w.destroy=function(){void 0!==w.config&&pe(\"onDestroy\");for(var e=w._handlers.length;e--;){var n=w._handlers[e];n.element.removeEventListener(n.event,n.handler,n.options)}if(w._handlers=[],w.mobileInput)w.mobileInput.parentNode&&w.mobileInput.parentNode.removeChild(w.mobileInput),w.mobileInput=void 0;else if(w.calendarContainer&&w.calendarContainer.parentNode)if(w.config.static&&w.calendarContainer.parentNode){var t=w.calendarContainer.parentNode;if(t.lastChild&&t.removeChild(t.lastChild),t.parentNode){for(;t.firstChild;)t.parentNode.insertBefore(t.firstChild,t);t.parentNode.removeChild(t)}}else w.calendarContainer.parentNode.removeChild(w.calendarContainer);w.altInput&&(w.input.type=\"text\",w.altInput.parentNode&&w.altInput.parentNode.removeChild(w.altInput),delete w.altInput),w.input&&(w.input.type=w.input._type,w.input.classList.remove(\"flatpickr-input\"),w.input.removeAttribute(\"readonly\")),[\"_showTimeInput\",\"latestSelectedDateObj\",\"_hideNextMonthArrow\",\"_hidePrevMonthArrow\",\"__hideNextMonthArrow\",\"__hidePrevMonthArrow\",\"isMobile\",\"isOpen\",\"selectedDateElem\",\"minDateHasTime\",\"maxDateHasTime\",\"days\",\"daysContainer\",\"_input\",\"_positionElement\",\"innerContainer\",\"rContainer\",\"monthNav\",\"todayDateElem\",\"calendarContainer\",\"weekdayContainer\",\"prevMonthNav\",\"nextMonthNav\",\"monthsDropdownContainer\",\"currentMonthElement\",\"currentYearElement\",\"navigationCurrentMonth\",\"selectedDateElem\",\"config\"].forEach((function(e){try{delete w[e]}catch(e){}}))},w.isEnabled=X,w.jumpToDate=P,w.open=function(e,n){if(void 0===n&&(n=w._positionElement),!0===w.isMobile){if(e){e.preventDefault();var t=g(e);t&&t.blur()}return void 0!==w.mobileInput&&(w.mobileInput.focus(),w.mobileInput.click()),void pe(\"onOpen\")}if(!w._input.disabled&&!w.config.inline){var a=w.isOpen;w.isOpen=!0,a||(w.calendarContainer.classList.add(\"open\"),w._input.classList.add(\"active\"),pe(\"onOpen\"),ce(n)),!0===w.config.enableTime&&!0===w.config.noCalendar&&(!1!==w.config.allowInput||void 0!==e&&w.timeContainer.contains(e.relatedTarget)||setTimeout((function(){return w.hourElement.select()}),50))}},w.redraw=de,w.set=function(e,n){if(null!==e&&\"object\"==typeof e)for(var a in Object.assign(w.config,e),e)void 0!==fe[a]&&fe[a].forEach((function(e){return e()}));else w.config[e]=n,void 0!==fe[e]?fe[e].forEach((function(e){return e()})):t.indexOf(e)>-1&&(w.config[e]=c(n));w.redraw(),be(!0)},w.setDate=function(e,n,t){if(void 0===n&&(n=!1),void 0===t&&(t=w.config.dateFormat),0!==e&&!e||e instanceof Array&&0===e.length)return w.clear(n);me(e,t),w.latestSelectedDateObj=w.selectedDates[w.selectedDates.length-1],w.redraw(),P(void 0,n),S(),0===w.selectedDates.length&&w.clear(!1),be(n),n&&pe(\"onChange\")},w.toggle=function(e){if(!0===w.isOpen)return w.close();w.open(e)};var fe={locale:[le,z],showMonths:[q,E,$],minDate:[P],maxDate:[P]};function me(e,n){var t=[];if(e instanceof Array)t=e.map((function(e){return w.parseDate(e,n)}));else if(e instanceof Date||\"number\"==typeof e)t=[w.parseDate(e,n)];else if(\"string\"==typeof e)switch(w.config.mode){case\"single\":case\"time\":t=[w.parseDate(e,n)];break;case\"multiple\":t=e.split(w.config.conjunction).map((function(e){return w.parseDate(e,n)}));break;case\"range\":t=e.split(w.l10n.rangeSeparator).map((function(e){return w.parseDate(e,n)}))}else w.config.errorHandler(new Error(\"Invalid date supplied: \"+JSON.stringify(e)));w.selectedDates=w.config.allowInvalidPreload?t:t.filter((function(e){return e instanceof Date&&X(e,!1)})),\"range\"===w.config.mode&&w.selectedDates.sort((function(e,n){return e.getTime()-n.getTime()}))}function ge(e){return e.slice().map((function(e){return\"string\"==typeof e||\"number\"==typeof e||e instanceof Date?w.parseDate(e,void 0,!0):e&&\"object\"==typeof e&&e.from&&e.to?{from:w.parseDate(e.from,void 0),to:w.parseDate(e.to,void 0)}:e})).filter((function(e){return e}))}function pe(e,n){if(void 0!==w.config){var t=w.config[e];if(void 0!==t&&t.length>0)for(var a=0;t[a]&&a1||\"static\"===w.config.monthSelectorType?w.monthElements[n].textContent=h(t.getMonth(),w.config.shorthandCurrentMonth,w.l10n)+\" \":w.monthsDropdownContainer.value=t.getMonth().toString(),e.value=t.getFullYear().toString()})),w._hidePrevMonthArrow=void 0!==w.config.minDate&&(w.currentYear===w.config.minDate.getFullYear()?w.currentMonth<=w.config.minDate.getMonth():w.currentYearw.config.maxDate.getMonth():w.currentYear>w.config.maxDate.getFullYear()))}function we(e){return w.selectedDates.map((function(n){return w.formatDate(n,e)})).filter((function(e,n,t){return\"range\"!==w.config.mode||w.config.enableTime||t.indexOf(e)===n})).join(\"range\"!==w.config.mode?w.config.conjunction:w.l10n.rangeSeparator)}function be(e){void 0===e&&(e=!0),void 0!==w.mobileInput&&w.mobileFormatStr&&(w.mobileInput.value=void 0!==w.latestSelectedDateObj?w.formatDate(w.latestSelectedDateObj,w.mobileFormatStr):\"\"),w.input.value=we(w.config.dateFormat),void 0!==w.altInput&&(w.altInput.value=we(w.config.altFormat)),!1!==e&&pe(\"onValueUpdate\")}function Ce(e){var n=g(e),t=w.prevMonthNav.contains(n),a=w.nextMonthNav.contains(n);t||a?G(t?-1:1):w.yearElements.indexOf(n)>=0?n.select():n.classList.contains(\"arrowUp\")?w.changeYear(w.currentYear+1):n.classList.contains(\"arrowDown\")&&w.changeYear(w.currentYear-1)}return function(){w.element=w.input=p,w.isOpen=!1,function(){var n=[\"wrap\",\"weekNumbers\",\"allowInput\",\"allowInvalidPreload\",\"clickOpens\",\"time_24hr\",\"enableTime\",\"noCalendar\",\"altInput\",\"shorthandCurrentMonth\",\"inline\",\"static\",\"enableSeconds\",\"disableMobile\"],i=e(e({},JSON.parse(JSON.stringify(p.dataset||{}))),v),o={};w.config.parseDate=i.parseDate,w.config.formatDate=i.formatDate,Object.defineProperty(w.config,\"enable\",{get:function(){return w.config._enable},set:function(e){w.config._enable=ge(e)}}),Object.defineProperty(w.config,\"disable\",{get:function(){return w.config._disable},set:function(e){w.config._disable=ge(e)}});var r=\"time\"===i.mode;if(!i.dateFormat&&(i.enableTime||r)){var l=k.defaultConfig.dateFormat||a.dateFormat;o.dateFormat=i.noCalendar||r?\"H:i\"+(i.enableSeconds?\":S\":\"\"):l+\" H:i\"+(i.enableSeconds?\":S\":\"\")}if(i.altInput&&(i.enableTime||r)&&!i.altFormat){var d=k.defaultConfig.altFormat||a.altFormat;o.altFormat=i.noCalendar||r?\"h:i\"+(i.enableSeconds?\":S K\":\" K\"):d+\" h:i\"+(i.enableSeconds?\":S\":\"\")+\" K\"}Object.defineProperty(w.config,\"minDate\",{get:function(){return w.config._minDate},set:oe(\"min\")}),Object.defineProperty(w.config,\"maxDate\",{get:function(){return w.config._maxDate},set:oe(\"max\")});var s=function(e){return function(n){w.config[\"min\"===e?\"_minTime\":\"_maxTime\"]=w.parseDate(n,\"H:i:S\")}};Object.defineProperty(w.config,\"minTime\",{get:function(){return w.config._minTime},set:s(\"min\")}),Object.defineProperty(w.config,\"maxTime\",{get:function(){return w.config._maxTime},set:s(\"max\")}),\"time\"===i.mode&&(w.config.noCalendar=!0,w.config.enableTime=!0),Object.assign(w.config,o,i);for(var u=0;u-1?w.config[m]=c(f[m]).map(x).concat(w.config[m]):void 0===i[m]&&(w.config[m]=f[m])}i.altInputClass||(w.config.altInputClass=re().className+\" \"+w.config.altInputClass),pe(\"onParseConfig\")}(),le(),w.input=re(),w.input?(w.input._type=w.input.type,w.input.type=\"text\",w.input.classList.add(\"flatpickr-input\"),w._input=w.input,w.config.altInput&&(w.altInput=s(w.input.nodeName,w.config.altInputClass),w._input=w.altInput,w.altInput.placeholder=w.input.placeholder,w.altInput.disabled=w.input.disabled,w.altInput.required=w.input.required,w.altInput.tabIndex=w.input.tabIndex,w.altInput.type=\"text\",w.input.setAttribute(\"type\",\"hidden\"),!w.config.static&&w.input.parentNode&&w.input.parentNode.insertBefore(w.altInput,w.input.nextSibling)),w.config.allowInput||w._input.setAttribute(\"readonly\",\"readonly\"),w._positionElement=w.config.positionElement||w._input):w.config.errorHandler(new Error(\"Invalid input element specified\")),function(){w.selectedDates=[],w.now=w.parseDate(w.config.now)||new Date;var e=w.config.defaultDate||(\"INPUT\"!==w.input.nodeName&&\"TEXTAREA\"!==w.input.nodeName||!w.input.placeholder||w.input.value!==w.input.placeholder?w.input.value:null);e&&me(e,w.config.dateFormat),w._initialDate=w.selectedDates.length>0?w.selectedDates[0]:w.config.minDate&&w.config.minDate.getTime()>w.now.getTime()?w.config.minDate:w.config.maxDate&&w.config.maxDate.getTime()0&&(w.latestSelectedDateObj=w.selectedDates[0]),void 0!==w.config.minTime&&(w.config.minTime=w.parseDate(w.config.minTime,\"H:i\")),void 0!==w.config.maxTime&&(w.config.maxTime=w.parseDate(w.config.maxTime,\"H:i\")),w.minDateHasTime=!!w.config.minDate&&(w.config.minDate.getHours()>0||w.config.minDate.getMinutes()>0||w.config.minDate.getSeconds()>0),w.maxDateHasTime=!!w.config.maxDate&&(w.config.maxDate.getHours()>0||w.config.maxDate.getMinutes()>0||w.config.maxDate.getSeconds()>0)}(),w.utils={getDaysInMonth:function(e,n){return void 0===e&&(e=w.currentMonth),void 0===n&&(n=w.currentYear),1===e&&(n%4==0&&n%100!=0||n%400==0)?29:w.l10n.daysInMonth[e]}},w.isMobile||function(){var e=window.document.createDocumentFragment();if(w.calendarContainer=s(\"div\",\"flatpickr-calendar\"),w.calendarContainer.tabIndex=-1,!w.config.noCalendar){if(e.appendChild((w.monthNav=s(\"div\",\"flatpickr-months\"),w.yearElements=[],w.monthElements=[],w.prevMonthNav=s(\"span\",\"flatpickr-prev-month\"),w.prevMonthNav.innerHTML=w.config.prevArrow,w.nextMonthNav=s(\"span\",\"flatpickr-next-month\"),w.nextMonthNav.innerHTML=w.config.nextArrow,q(),Object.defineProperty(w,\"_hidePrevMonthArrow\",{get:function(){return w.__hidePrevMonthArrow},set:function(e){w.__hidePrevMonthArrow!==e&&(d(w.prevMonthNav,\"flatpickr-disabled\",e),w.__hidePrevMonthArrow=e)}}),Object.defineProperty(w,\"_hideNextMonthArrow\",{get:function(){return w.__hideNextMonthArrow},set:function(e){w.__hideNextMonthArrow!==e&&(d(w.nextMonthNav,\"flatpickr-disabled\",e),w.__hideNextMonthArrow=e)}}),w.currentYearElement=w.yearElements[0],De(),w.monthNav)),w.innerContainer=s(\"div\",\"flatpickr-innerContainer\"),w.config.weekNumbers){var n=function(){w.calendarContainer.classList.add(\"hasWeeks\");var e=s(\"div\",\"flatpickr-weekwrapper\");e.appendChild(s(\"span\",\"flatpickr-weekday\",w.l10n.weekAbbreviation));var n=s(\"div\",\"flatpickr-weeks\");return e.appendChild(n),{weekWrapper:e,weekNumbers:n}}(),t=n.weekWrapper,a=n.weekNumbers;w.innerContainer.appendChild(t),w.weekNumbers=a,w.weekWrapper=t}w.rContainer=s(\"div\",\"flatpickr-rContainer\"),w.rContainer.appendChild($()),w.daysContainer||(w.daysContainer=s(\"div\",\"flatpickr-days\"),w.daysContainer.tabIndex=-1),J(),w.rContainer.appendChild(w.daysContainer),w.innerContainer.appendChild(w.rContainer),e.appendChild(w.innerContainer)}w.config.enableTime&&e.appendChild(function(){w.calendarContainer.classList.add(\"hasTime\"),w.config.noCalendar&&w.calendarContainer.classList.add(\"noCalendar\"),w.timeContainer=s(\"div\",\"flatpickr-time\"),w.timeContainer.tabIndex=-1;var e=s(\"span\",\"flatpickr-time-separator\",\":\"),n=m(\"flatpickr-hour\",{\"aria-label\":w.l10n.hourAriaLabel});w.hourElement=n.getElementsByTagName(\"input\")[0];var t=m(\"flatpickr-minute\",{\"aria-label\":w.l10n.minuteAriaLabel});if(w.minuteElement=t.getElementsByTagName(\"input\")[0],w.hourElement.tabIndex=w.minuteElement.tabIndex=-1,w.hourElement.value=o(w.latestSelectedDateObj?w.latestSelectedDateObj.getHours():w.config.time_24hr?w.config.defaultHour:function(e){switch(e%24){case 0:case 12:return 12;default:return e%12}}(w.config.defaultHour)),w.minuteElement.value=o(w.latestSelectedDateObj?w.latestSelectedDateObj.getMinutes():w.config.defaultMinute),w.hourElement.setAttribute(\"step\",w.config.hourIncrement.toString()),w.minuteElement.setAttribute(\"step\",w.config.minuteIncrement.toString()),w.hourElement.setAttribute(\"min\",w.config.time_24hr?\"0\":\"1\"),w.hourElement.setAttribute(\"max\",w.config.time_24hr?\"23\":\"12\"),w.minuteElement.setAttribute(\"min\",\"0\"),w.minuteElement.setAttribute(\"max\",\"59\"),w.timeContainer.appendChild(n),w.timeContainer.appendChild(e),w.timeContainer.appendChild(t),w.config.time_24hr&&w.timeContainer.classList.add(\"time24hr\"),w.config.enableSeconds){w.timeContainer.classList.add(\"hasSeconds\");var a=m(\"flatpickr-second\");w.secondElement=a.getElementsByTagName(\"input\")[0],w.secondElement.value=o(w.latestSelectedDateObj?w.latestSelectedDateObj.getSeconds():w.config.defaultSeconds),w.secondElement.setAttribute(\"step\",w.minuteElement.getAttribute(\"step\")),w.secondElement.setAttribute(\"min\",\"0\"),w.secondElement.setAttribute(\"max\",\"59\"),w.timeContainer.appendChild(s(\"span\",\"flatpickr-time-separator\",\":\")),w.timeContainer.appendChild(a)}return w.config.time_24hr||(w.amPM=s(\"span\",\"flatpickr-am-pm\",w.l10n.amPM[r((w.latestSelectedDateObj?w.hourElement.value:w.config.defaultHour)>11)]),w.amPM.title=w.l10n.toggleTitle,w.amPM.tabIndex=-1,w.timeContainer.appendChild(w.amPM)),w.timeContainer}()),d(w.calendarContainer,\"rangeMode\",\"range\"===w.config.mode),d(w.calendarContainer,\"animate\",!0===w.config.animate),d(w.calendarContainer,\"multiMonth\",w.config.showMonths>1),w.calendarContainer.appendChild(e);var i=void 0!==w.config.appendTo&&void 0!==w.config.appendTo.nodeType;if((w.config.inline||w.config.static)&&(w.calendarContainer.classList.add(w.config.inline?\"inline\":\"static\"),w.config.inline&&(!i&&w.element.parentNode?w.element.parentNode.insertBefore(w.calendarContainer,w._input.nextSibling):void 0!==w.config.appendTo&&w.config.appendTo.appendChild(w.calendarContainer)),w.config.static)){var l=s(\"div\",\"flatpickr-wrapper\");w.element.parentNode&&w.element.parentNode.insertBefore(l,w.element),l.appendChild(w.element),w.altInput&&l.appendChild(w.altInput),l.appendChild(w.calendarContainer)}w.config.static||w.config.inline||(void 0!==w.config.appendTo?w.config.appendTo:window.document.body).appendChild(w.calendarContainer)}(),function(){if(w.config.wrap&&[\"open\",\"close\",\"toggle\",\"clear\"].forEach((function(e){Array.prototype.forEach.call(w.element.querySelectorAll(\"[data-\"+e+\"]\"),(function(n){return N(n,\"click\",w[e])}))})),w.isMobile)!function(){var e=w.config.enableTime?w.config.noCalendar?\"time\":\"datetime-local\":\"date\";w.mobileInput=s(\"input\",w.input.className+\" flatpickr-mobile\"),w.mobileInput.tabIndex=1,w.mobileInput.type=e,w.mobileInput.disabled=w.input.disabled,w.mobileInput.required=w.input.required,w.mobileInput.placeholder=w.input.placeholder,w.mobileFormatStr=\"datetime-local\"===e?\"Y-m-d\\\\TH:i:S\":\"date\"===e?\"Y-m-d\":\"H:i:S\",w.selectedDates.length>0&&(w.mobileInput.defaultValue=w.mobileInput.value=w.formatDate(w.selectedDates[0],w.mobileFormatStr)),w.config.minDate&&(w.mobileInput.min=w.formatDate(w.config.minDate,\"Y-m-d\")),w.config.maxDate&&(w.mobileInput.max=w.formatDate(w.config.maxDate,\"Y-m-d\")),w.input.getAttribute(\"step\")&&(w.mobileInput.step=String(w.input.getAttribute(\"step\"))),w.input.type=\"hidden\",void 0!==w.altInput&&(w.altInput.type=\"hidden\");try{w.input.parentNode&&w.input.parentNode.insertBefore(w.mobileInput,w.input.nextSibling)}catch(e){}N(w.mobileInput,\"change\",(function(e){w.setDate(g(e).value,!1,w.mobileFormatStr),pe(\"onChange\"),pe(\"onClose\")}))}();else{var e=l(ie,50);if(w._debouncedChange=l(A,300),w.daysContainer&&!/iPhone|iPad|iPod/i.test(navigator.userAgent)&&N(w.daysContainer,\"mouseover\",(function(e){\"range\"===w.config.mode&&ae(g(e))})),N(window.document.body,\"keydown\",te),w.config.inline||w.config.static||N(window,\"resize\",e),void 0!==window.ontouchstart?N(window.document,\"touchstart\",Z):N(window.document,\"click\",Z),N(window.document,\"focus\",Z,{capture:!0}),!0===w.config.clickOpens&&(N(w._input,\"focus\",w.open),N(w._input,\"click\",w.open)),void 0!==w.daysContainer&&(N(w.monthNav,\"click\",Ce),N(w.monthNav,[\"keyup\",\"increment\"],F),N(w.daysContainer,\"click\",ue)),void 0!==w.timeContainer&&void 0!==w.minuteElement&&void 0!==w.hourElement){var n=function(e){return g(e).select()};N(w.timeContainer,[\"increment\"],T),N(w.timeContainer,\"blur\",T,{capture:!0}),N(w.timeContainer,\"click\",Y),N([w.hourElement,w.minuteElement],[\"focus\",\"click\"],n),void 0!==w.secondElement&&N(w.secondElement,\"focus\",(function(){return w.secondElement&&w.secondElement.select()})),void 0!==w.amPM&&N(w.amPM,\"click\",(function(e){T(e),A()}))}w.config.allowInput&&N(w._input,\"blur\",ne)}}(),(w.selectedDates.length||w.config.noCalendar)&&(w.config.enableTime&&S(w.config.noCalendar?w.latestSelectedDateObj||w.config.minDate:void 0),be(!1)),E();var n=/^((?!chrome|android).)*safari/i.test(navigator.userAgent);!w.isMobile&&n&&ce(),pe(\"onReady\")}(),w}function E(e,n){for(var t=Array.prototype.slice.call(e).filter((function(e){return e instanceof HTMLElement})),a=[],i=0;ithis.render()));const{start:s,end:l,value:o,step:r,title:n}=this.model.properties;this.on_change([s,l,o,r],(()=>{const{start:t,end:e,value:i,step:s}=this._calc_to();this._noUiSlider.updateOptions({range:{min:t,max:e},start:i,step:s},!0)}));const{bar_color:a}=this.model.properties;this.on_change(a,(()=>{this._set_bar_color()}));const{show_value:d}=this.model.properties;this.on_change([o,n,d],(()=>this._update_title()))}styles(){return[...super.styles(),p.default,u.default]}_update_title(){var t;(0,a.empty)(this.title_el);const e=null==this.model.title||0==this.model.title.length&&!this.model.show_value;if(this.title_el.style.display=e?\"none\":\"\",!e&&(0!=(null===(t=this.model.title)||void 0===t?void 0:t.length)&&(this.title_el.textContent=`${this.model.title}: `),this.model.show_value)){const{value:t}=this._calc_to(),e=t.map((t=>this.model.pretty(t))).join(\" .. \");this.title_el.appendChild((0,a.span)({class:m.slider_value},e))}}_set_bar_color(){if(!this.model.disabled){this.slider_el.querySelector(\".noUi-connect\").style.backgroundColor=(0,_.color2css)(this.model.bar_color)}}render(){super.render();const{start:t,end:e,value:i,step:s}=this._calc_to();let l;if(this.model.tooltips){const t={to:t=>this.model.pretty(t)};l=(0,d.repeat)(t,i.length)}else l=!1;if(null==this.slider_el){this.slider_el=(0,a.div)(),this._noUiSlider=n.default.create(this.slider_el,{range:{min:t,max:e},start:i,step:s,behaviour:this.model.behaviour,connect:this.model.connected,tooltips:l,orientation:this.model.orientation,direction:this.model.direction}),this._noUiSlider.on(\"slide\",((t,e,i)=>this._slide(i))),this._noUiSlider.on(\"change\",((t,e,i)=>this._change(i)));const o=(t,e)=>{if(!l)return;this.slider_el.querySelectorAll(\".noUi-handle\")[t].querySelector(\".noUi-tooltip\").style.display=e?\"block\":\"\"};this._noUiSlider.on(\"start\",((t,e)=>o(e,!0))),this._noUiSlider.on(\"end\",((t,e)=>o(e,!1)))}else this._noUiSlider.updateOptions({range:{min:t,max:e},start:i,step:s},!0);this._set_bar_color(),this.model.disabled?this.slider_el.setAttribute(\"disabled\",\"true\"):this.slider_el.removeAttribute(\"disabled\"),this.title_el=(0,a.div)({class:m.slider_title}),this._update_title(),this.group_el=(0,a.div)({class:v.input_group},this.title_el,this.slider_el),this.el.appendChild(this.group_el)}_slide(t){this.model.value=this._calc_from(t)}_change(t){const e=this._calc_from(t);this.model.setv({value:e,value_throttled:e})}}b.__name__=\"AbstractBaseSliderView\";class g extends b{_calc_to(){return{start:this.model.start,end:this.model.end,value:[this.model.value],step:this.model.step}}_calc_from([t]){return Number.isInteger(this.model.start)&&Number.isInteger(this.model.end)&&Number.isInteger(this.model.step)?Math.round(t):t}}i.AbstractSliderView=g,g.__name__=\"AbstractSliderView\";class f extends b{_calc_to(){return{start:this.model.start,end:this.model.end,value:this.model.value,step:this.model.step}}_calc_from(t){return t}}i.AbstractRangeSliderView=f,f.__name__=\"AbstractRangeSliderView\";class S extends h.OrientedControl{constructor(t){super(t),this.connected=!1}pretty(t){return this._formatter(t,this.format)}}i.AbstractSlider=S,r=S,S.__name__=\"AbstractSlider\",r.define((({Any:t,Boolean:e,Number:i,String:s,Color:l,Or:o,Enum:r,Ref:n,Nullable:a})=>({title:[a(s),\"\"],show_value:[e,!0],start:[t],end:[t],value:[t],value_throttled:[t],step:[i,1],format:[o(s,n(c.TickFormatter))],direction:[r(\"ltr\",\"rtl\"),\"ltr\"],tooltips:[e,!0],bar_color:[l,\"#e6e6e6\"]})))},\n 462: function _(t,e,r,n,i){var o,s;o=this,s=function(t){\"use strict\";var e,r;function n(t){return\"object\"==typeof t&&\"function\"==typeof t.to}function i(t){t.parentElement.removeChild(t)}function o(t){return null!=t}function s(t){t.preventDefault()}function a(t){return\"number\"==typeof t&&!isNaN(t)&&isFinite(t)}function l(t,e,r){r>0&&(f(t,e),setTimeout((function(){d(t,e)}),r))}function u(t){return Math.max(Math.min(t,100),0)}function c(t){return Array.isArray(t)?t:[t]}function p(t){var e=(t=String(t)).split(\".\");return e.length>1?e[1].length:0}function f(t,e){t.classList&&!/\\s/.test(e)?t.classList.add(e):t.className+=\" \"+e}function d(t,e){t.classList&&!/\\s/.test(e)?t.classList.remove(e):t.className=t.className.replace(new RegExp(\"(^|\\\\b)\"+e.split(\" \").join(\"|\")+\"(\\\\b|$)\",\"gi\"),\" \")}function h(t){var e=void 0!==window.pageXOffset,r=\"CSS1Compat\"===(t.compatMode||\"\");return{x:e?window.pageXOffset:r?t.documentElement.scrollLeft:t.body.scrollLeft,y:e?window.pageYOffset:r?t.documentElement.scrollTop:t.body.scrollTop}}function m(t,e){return 100/(e-t)}function g(t,e,r){return 100*e/(t[r+1]-t[r])}function v(t,e){for(var r=1;t>=e[r];)r+=1;return r}function b(t,e,r){if(r>=t.slice(-1)[0])return 100;var n=v(r,t),i=t[n-1],o=t[n],s=e[n-1],a=e[n];return s+function(t,e){return g(t,t[0]<0?e+Math.abs(t[0]):e-t[0],0)}([i,o],r)/m(s,a)}function S(t,e,r,n){if(100===n)return n;var i=v(n,t),o=t[i-1],s=t[i];return r?n-o>(s-o)/2?s:o:e[i-1]?t[i-1]+function(t,e){return Math.round(t/e)*e}(n-t[i-1],e[i-1]):n}t.PipsMode=void 0,(e=t.PipsMode||(t.PipsMode={})).Range=\"range\",e.Steps=\"steps\",e.Positions=\"positions\",e.Count=\"count\",e.Values=\"values\",t.PipsType=void 0,(r=t.PipsType||(t.PipsType={}))[r.None=-1]=\"None\",r[r.NoValue=0]=\"NoValue\",r[r.LargeValue=1]=\"LargeValue\",r[r.SmallValue=2]=\"SmallValue\";var x=function(){function t(t,e,r){var n;this.xPct=[],this.xVal=[],this.xSteps=[],this.xNumSteps=[],this.xHighestCompleteStep=[],this.xSteps=[r||!1],this.xNumSteps=[!1],this.snap=e;var i=[];for(Object.keys(t).forEach((function(e){i.push([c(t[e]),e])})),i.sort((function(t,e){return t[0][0]-e[0][0]})),n=0;nthis.xPct[i+1];)i++;else t===this.xPct[this.xPct.length-1]&&(i=this.xPct.length-2);r||t!==this.xPct[i+1]||i++,null===e&&(e=[]);var o=1,s=e[i],a=0,l=0,u=0,c=0;for(n=r?(t-this.xPct[i])/(this.xPct[i+1]-this.xPct[i]):(this.xPct[i+1]-t)/(this.xPct[i+1]-this.xPct[i]);s>0;)a=this.xPct[i+1+c]-this.xPct[i+c],e[i+c]*o+100-100*n>100?(l=a*n,o=(s-100*n)/e[i+c],n=1):(l=e[i+c]*a/100*o,o=0),r?(u-=l,this.xPct.length+c>=1&&c--):(u+=l,this.xPct.length-c>=1&&c++),s=e[i+c]*o;return t+u},t.prototype.toStepping=function(t){return t=b(this.xVal,this.xPct,t)},t.prototype.fromStepping=function(t){return function(t,e,r){if(r>=100)return t.slice(-1)[0];var n=v(r,e),i=t[n-1],o=t[n],s=e[n-1];return function(t,e){return e*(t[1]-t[0])/100+t[0]}([i,o],(r-s)*m(s,e[n]))}(this.xVal,this.xPct,t)},t.prototype.getStep=function(t){return t=S(this.xPct,this.xSteps,this.snap,t)},t.prototype.getDefaultStep=function(t,e,r){var n=v(t,this.xPct);return(100===t||e&&t===this.xPct[n-1])&&(n=Math.max(n-1,1)),(this.xVal[n]-this.xVal[n-1])/r},t.prototype.getNearbySteps=function(t){var e=v(t,this.xPct);return{stepBefore:{startValue:this.xVal[e-2],step:this.xNumSteps[e-2],highestStep:this.xHighestCompleteStep[e-2]},thisStep:{startValue:this.xVal[e-1],step:this.xNumSteps[e-1],highestStep:this.xHighestCompleteStep[e-1]},stepAfter:{startValue:this.xVal[e],step:this.xNumSteps[e],highestStep:this.xHighestCompleteStep[e]}}},t.prototype.countStepDecimals=function(){var t=this.xNumSteps.map(p);return Math.max.apply(null,t)},t.prototype.hasNoSize=function(){return this.xVal[0]===this.xVal[this.xVal.length-1]},t.prototype.convert=function(t){return this.getStep(this.toStepping(t))},t.prototype.handleEntryPoint=function(t,e){var r;if(!a(r=\"min\"===t?0:\"max\"===t?100:parseFloat(t))||!a(e[0]))throw new Error(\"noUiSlider: 'range' value isn't numeric.\");this.xPct.push(r),this.xVal.push(e[0]);var n=Number(e[1]);r?this.xSteps.push(!isNaN(n)&&n):isNaN(n)||(this.xSteps[0]=n),this.xHighestCompleteStep.push(0)},t.prototype.handleStepPoint=function(t,e){if(e)if(this.xVal[t]!==this.xVal[t+1]){this.xSteps[t]=g([this.xVal[t],this.xVal[t+1]],e,0)/m(this.xPct[t],this.xPct[t+1]);var r=(this.xVal[t+1]-this.xVal[t])/this.xNumSteps[t],n=Math.ceil(Number(r.toFixed(3))-1),i=this.xVal[t]+this.xNumSteps[t]*n;this.xHighestCompleteStep[t]=i}else this.xSteps[t]=this.xHighestCompleteStep[t]=this.xVal[t]},t}(),y={to:function(t){return void 0===t?\"\":t.toFixed(2)},from:Number},w={target:\"target\",base:\"base\",origin:\"origin\",handle:\"handle\",handleLower:\"handle-lower\",handleUpper:\"handle-upper\",touchArea:\"touch-area\",horizontal:\"horizontal\",vertical:\"vertical\",background:\"background\",connect:\"connect\",connects:\"connects\",ltr:\"ltr\",rtl:\"rtl\",textDirectionLtr:\"txt-dir-ltr\",textDirectionRtl:\"txt-dir-rtl\",draggable:\"draggable\",drag:\"state-drag\",tap:\"state-tap\",active:\"active\",tooltip:\"tooltip\",pips:\"pips\",pipsHorizontal:\"pips-horizontal\",pipsVertical:\"pips-vertical\",marker:\"marker\",markerHorizontal:\"marker-horizontal\",markerVertical:\"marker-vertical\",markerNormal:\"marker-normal\",markerLarge:\"marker-large\",markerSub:\"marker-sub\",value:\"value\",valueHorizontal:\"value-horizontal\",valueVertical:\"value-vertical\",valueNormal:\"value-normal\",valueLarge:\"value-large\",valueSub:\"value-sub\"},E=\".__tooltips\",P=\".__aria\";function C(t,e){if(!a(e))throw new Error(\"noUiSlider: 'step' is not numeric.\");t.singleStep=e}function N(t,e){if(!a(e))throw new Error(\"noUiSlider: 'keyboardPageMultiplier' is not numeric.\");t.keyboardPageMultiplier=e}function V(t,e){if(!a(e))throw new Error(\"noUiSlider: 'keyboardMultiplier' is not numeric.\");t.keyboardMultiplier=e}function k(t,e){if(!a(e))throw new Error(\"noUiSlider: 'keyboardDefaultStep' is not numeric.\");t.keyboardDefaultStep=e}function M(t,e){if(\"object\"!=typeof e||Array.isArray(e))throw new Error(\"noUiSlider: 'range' is not an object.\");if(void 0===e.min||void 0===e.max)throw new Error(\"noUiSlider: Missing 'min' or 'max' in 'range'.\");t.spectrum=new x(e,t.snap||!1,t.singleStep)}function A(t,e){if(e=c(e),!Array.isArray(e)||!e.length)throw new Error(\"noUiSlider: 'start' option is incorrect.\");t.handles=e.length,t.start=e}function U(t,e){if(\"boolean\"!=typeof e)throw new Error(\"noUiSlider: 'snap' option must be a boolean.\");t.snap=e}function D(t,e){if(\"boolean\"!=typeof e)throw new Error(\"noUiSlider: 'animate' option must be a boolean.\");t.animate=e}function O(t,e){if(\"number\"!=typeof e)throw new Error(\"noUiSlider: 'animationDuration' option must be a number.\");t.animationDuration=e}function L(t,e){var r,n=[!1];if(\"lower\"===e?e=[!0,!1]:\"upper\"===e&&(e=[!1,!0]),!0===e||!1===e){for(r=1;r1)throw new Error(\"noUiSlider: 'padding' option must not exceed 100% of the range.\")}}function F(t,e){switch(e){case\"ltr\":t.dir=0;break;case\"rtl\":t.dir=1;break;default:throw new Error(\"noUiSlider: 'direction' option was not recognized.\")}}function R(t,e){if(\"string\"!=typeof e)throw new Error(\"noUiSlider: 'behaviour' must be a string containing options.\");var r=e.indexOf(\"tap\")>=0,n=e.indexOf(\"drag\")>=0,i=e.indexOf(\"fixed\")>=0,o=e.indexOf(\"snap\")>=0,s=e.indexOf(\"hover\")>=0,a=e.indexOf(\"unconstrained\")>=0,l=e.indexOf(\"drag-all\")>=0;if(i){if(2!==t.handles)throw new Error(\"noUiSlider: 'fixed' behaviour must be used with 2 handles\");j(t,t.start[1]-t.start[0])}if(a&&(t.margin||t.limit))throw new Error(\"noUiSlider: 'unconstrained' behaviour cannot be used with margin or limit\");t.events={tap:r||o,drag:n,dragAll:l,fixed:i,snap:o,hover:s,unconstrained:a}}function _(t,e){if(!1!==e)if(!0===e||n(e)){t.tooltips=[];for(var r=0;r= 2) required for mode 'count'.\");for(var r=e.values-1,n=100/r,i=[];r--;)i[r]=r*n;return i.push(100),q(i,e.stepped)}return e.mode===t.PipsMode.Positions?q(e.values,e.stepped):e.mode===t.PipsMode.Values?e.stepped?e.values.map((function(t){return C.fromStepping(C.getStep(C.toStepping(t)))})):e.values:[]}(e),i={},o=C.xVal[0],s=C.xVal[C.xVal.length-1],a=!1,l=!1,u=0;return r=n.slice().sort((function(t,e){return t-e})),(n=r.filter((function(t){return!this[t]&&(this[t]=!0)}),{}))[0]!==o&&(n.unshift(o),a=!0),n[n.length-1]!==s&&(n.push(s),l=!0),n.forEach((function(r,o){var s,c,p,f,d,h,m,g,v,b,S=r,x=n[o+1],y=e.mode===t.PipsMode.Steps;for(y&&(s=C.xNumSteps[o]),s||(s=x-S),void 0===x&&(x=S),s=Math.max(s,1e-7),c=S;c<=x;c=Number((c+s).toFixed(7))){for(g=(d=(f=C.toStepping(c))-u)/(e.density||1),b=d/(v=Math.round(g)),p=1;p<=v;p+=1)i[(h=u+p*b).toFixed(5)]=[C.fromStepping(h),0];m=n.indexOf(c)>-1?t.PipsType.LargeValue:y?t.PipsType.SmallValue:t.PipsType.NoValue,!o&&a&&c!==x&&(m=0),c===x&&l||(i[f.toFixed(5)]=[c,m]),u=f}})),i}function Y(e,n,i){var o,s,a=U.createElement(\"div\"),l=((o={})[t.PipsType.None]=\"\",o[t.PipsType.NoValue]=r.cssClasses.valueNormal,o[t.PipsType.LargeValue]=r.cssClasses.valueLarge,o[t.PipsType.SmallValue]=r.cssClasses.valueSub,o),u=((s={})[t.PipsType.None]=\"\",s[t.PipsType.NoValue]=r.cssClasses.markerNormal,s[t.PipsType.LargeValue]=r.cssClasses.markerLarge,s[t.PipsType.SmallValue]=r.cssClasses.markerSub,s),c=[r.cssClasses.valueHorizontal,r.cssClasses.valueVertical],p=[r.cssClasses.markerHorizontal,r.cssClasses.markerVertical];function d(t,e){var n=e===r.cssClasses.value,i=n?l:u;return e+\" \"+(n?c:p)[r.ort]+\" \"+i[t]}return f(a,r.cssClasses.pips),f(a,0===r.ort?r.cssClasses.pipsHorizontal:r.cssClasses.pipsVertical),Object.keys(e).forEach((function(o){!function(e,o,s){if((s=n?n(o,s):s)!==t.PipsType.None){var l=T(a,!1);l.className=d(s,r.cssClasses.marker),l.style[r.style]=e+\"%\",s>t.PipsType.NoValue&&((l=T(a,!1)).className=d(s,r.cssClasses.value),l.setAttribute(\"data-value\",String(o)),l.style[r.style]=e+\"%\",l.innerHTML=String(i.to(o)))}}(o,e[o][0],e[o][1])})),a}function I(){g&&(i(g),g=null)}function W(t){I();var e=X(t),r=t.filter,n=t.format||{to:function(t){return String(Math.round(t))}};return g=w.appendChild(Y(e,r,n))}function $(){var t=a.getBoundingClientRect(),e=\"offset\"+[\"Width\",\"Height\"][r.ort];return 0===r.ort?t.width||a[e]:t.height||a[e]}function J(t,e,n,i){var o=function(o){var s,a,l=function(t,e,r){var n=0===t.type.indexOf(\"touch\"),i=0===t.type.indexOf(\"mouse\"),o=0===t.type.indexOf(\"pointer\"),s=0,a=0;if(0===t.type.indexOf(\"MSPointer\")&&(o=!0),\"mousedown\"===t.type&&!t.buttons&&!t.touches)return!1;if(n){var l=function(e){var n=e.target;return n===r||r.contains(n)||t.composed&&t.composedPath().shift()===r};if(\"touchstart\"===t.type){var u=Array.prototype.filter.call(t.touches,l);if(u.length>1)return!1;s=u[0].pageX,a=u[0].pageY}else{var c=Array.prototype.find.call(t.changedTouches,l);if(!c)return!1;s=c.pageX,a=c.pageY}}return e=e||h(U),(i||o)&&(s=t.clientX+e.x,a=t.clientY+e.y),t.pageOffset=e,t.points=[s,a],t.cursor=i||o,t}(o,i.pageOffset,i.target||e);return!!l&&!(F()&&!i.doNotReject)&&(s=w,a=r.cssClasses.tap,!((s.classList?s.classList.contains(a):new RegExp(\"\\\\b\"+a+\"\\\\b\").test(s.className))&&!i.doNotReject)&&!(t===x.start&&void 0!==l.buttons&&l.buttons>1)&&(!i.hover||!l.buttons)&&(y||l.preventDefault(),l.calcPoint=l.points[r.ort],void n(l,i)))},s=[];return t.split(\" \").forEach((function(t){e.addEventListener(t,o,!!y&&{passive:!0}),s.push([t,o])})),s}function K(t){var e,n,i,o,s,l,c=100*(t-(e=a,n=r.ort,i=e.getBoundingClientRect(),o=e.ownerDocument,s=o.documentElement,l=h(o),/webkit.*Chrome.*Mobile/i.test(navigator.userAgent)&&(l.x=0),n?i.top+l.y-s.clientTop:i.left+l.x-s.clientLeft))/$();return c=u(c),r.dir?100-c:c}function Q(t,e){\"mouseout\"===t.type&&\"HTML\"===t.target.nodeName&&null===t.relatedTarget&&tt(t,e)}function Z(t,e){if(-1===navigator.appVersion.indexOf(\"MSIE 9\")&&0===t.buttons&&0!==e.buttonsProperty)return tt(t,e);var n=(r.dir?-1:1)*(t.calcPoint-e.startCalcPoint);ut(n>0,100*n/e.baseSize,e.locations,e.handleNumbers,e.connect)}function tt(t,e){e.handle&&(d(e.handle,r.cssClasses.active),M-=1),e.listeners.forEach((function(t){D.removeEventListener(t[0],t[1])})),0===M&&(d(w,r.cssClasses.drag),pt(),t.cursor&&(O.style.cursor=\"\",O.removeEventListener(\"selectstart\",s))),e.handleNumbers.forEach((function(t){st(\"change\",t),st(\"set\",t),st(\"end\",t)}))}function et(t,e){if(!e.handleNumbers.some(R)){var n;1===e.handleNumbers.length&&(n=p[e.handleNumbers[0]].children[0],M+=1,f(n,r.cssClasses.active)),t.stopPropagation();var i=[],o=J(x.move,D,Z,{target:t.target,handle:n,connect:e.connect,listeners:i,startCalcPoint:t.calcPoint,baseSize:$(),pageOffset:t.pageOffset,handleNumbers:e.handleNumbers,buttonsProperty:t.buttons,locations:V.slice()}),a=J(x.end,D,tt,{target:t.target,handle:n,listeners:i,doNotReject:!0,handleNumbers:e.handleNumbers}),l=J(\"mouseout\",D,Q,{target:t.target,handle:n,listeners:i,doNotReject:!0,handleNumbers:e.handleNumbers});i.push.apply(i,o.concat(a,l)),t.cursor&&(O.style.cursor=getComputedStyle(t.target).cursor,p.length>1&&f(w,r.cssClasses.drag),O.addEventListener(\"selectstart\",s,!1)),e.handleNumbers.forEach((function(t){st(\"start\",t)}))}}function rt(t){t.stopPropagation();var e=K(t.calcPoint),n=function(t){var e=100,r=!1;return p.forEach((function(n,i){if(!R(i)){var o=V[i],s=Math.abs(o-t);(so||100===s&&100===e)&&(r=i,e=s)}})),r}(e);!1!==n&&(r.events.snap||l(w,r.cssClasses.tap,r.animationDuration),ft(n,e,!0,!0),pt(),st(\"slide\",n,!0),st(\"update\",n,!0),r.events.snap?et(t,{handleNumbers:[n]}):(st(\"change\",n,!0),st(\"set\",n,!0)))}function nt(t){var e=K(t.calcPoint),r=C.getStep(e),n=C.fromStepping(r);Object.keys(A).forEach((function(t){\"hover\"===t.split(\".\")[0]&&A[t].forEach((function(t){t.call(bt,n)}))}))}function it(t,e){A[t]=A[t]||[],A[t].push(e),\"update\"===t.split(\".\")[0]&&p.forEach((function(t,e){st(\"update\",e)}))}function ot(t){var e=t&&t.split(\".\")[0],r=e?t.substring(e.length):t;Object.keys(A).forEach((function(t){var n=t.split(\".\")[0],i=t.substring(n.length);e&&e!==n||r&&r!==i||function(t){return t===P||t===E}(i)&&r!==i||delete A[t]}))}function st(t,e,n){Object.keys(A).forEach((function(i){var o=i.split(\".\")[0];t===o&&A[i].forEach((function(t){t.call(bt,N.map(r.format.to),e,N.slice(),n||!1,V.slice(),bt)}))}))}function at(t,e,n,i,o,s){var a;return p.length>1&&!r.events.unconstrained&&(i&&e>0&&(a=C.getAbsoluteDistance(t[e-1],r.margin,!1),n=Math.max(n,a)),o&&e1&&r.limit&&(i&&e>0&&(a=C.getAbsoluteDistance(t[e-1],r.limit,!1),n=Math.min(n,a)),o&&e1?n.forEach((function(t,r){var n=at(o,t,o[t]+e,a[r],l[r],!1);!1===n?e=0:(e=n-o[t],o[t]=n)})):a=l=[!0];var u=!1;n.forEach((function(t,n){u=ft(t,r[t]+e,a[n],l[n])||u})),u&&(n.forEach((function(t){st(\"update\",t),st(\"slide\",t)})),null!=i&&st(\"drag\",s))}function ct(t,e){return r.dir?100-t-e:t}function pt(){k.forEach((function(t){var e=V[t]>50?-1:1,r=3+(p.length+e*t);p[t].style.zIndex=String(r)}))}function ft(t,e,n,i,o){return o||(e=at(V,t,e,n,i,!1)),!1!==e&&(function(t,e){V[t]=e,N[t]=C.fromStepping(e);var n=\"translate(\"+lt(10*(ct(e,0)-L)+\"%\",\"0\")+\")\";p[t].style[r.transformRule]=n,dt(t),dt(t+1)}(t,e),!0)}function dt(t){if(m[t]){var e=0,n=100;0!==t&&(e=V[t-1]),t!==m.length-1&&(n=V[t]);var i=n-e,o=\"translate(\"+lt(ct(e,i)+\"%\",\"0\")+\")\",s=\"scale(\"+lt(i/100,\"1\")+\")\";m[t].style[r.transformRule]=o+\" \"+s}}function ht(t,e){return null===t||!1===t||void 0===t?V[e]:(\"number\"==typeof t&&(t=String(t)),!1!==(t=r.format.from(t))&&(t=C.toStepping(t)),!1===t||isNaN(t)?V[e]:t)}function mt(t,e,n){var i=c(t),o=void 0===V[0];e=void 0===e||e,r.animate&&!o&&l(w,r.cssClasses.tap,r.animationDuration),k.forEach((function(t){ft(t,ht(i[t],t),!0,!1,n)}));var s=1===k.length?0:1;if(o&&C.hasNoSize()&&(n=!0,V[0]=0,k.length>1)){var a=100/(k.length-1);k.forEach((function(t){V[t]=t*a}))}for(;sn.stepAfter.startValue&&(o=n.stepAfter.startValue-i),s=i>n.thisStep.startValue?n.thisStep.step:!1!==n.stepBefore.step&&i-n.stepBefore.highestStep,100===e?o=null:0===e&&(s=null);var a=C.countStepDecimals();return null!==o&&!1!==o&&(o=Number(o.toFixed(a))),null!==s&&!1!==s&&(s=Number(s.toFixed(a))),[s,o]}f(b=w,r.cssClasses.target),0===r.dir?f(b,r.cssClasses.ltr):f(b,r.cssClasses.rtl),0===r.ort?f(b,r.cssClasses.horizontal):f(b,r.cssClasses.vertical),f(b,\"rtl\"===getComputedStyle(b).direction?r.cssClasses.textDirectionRtl:r.cssClasses.textDirectionLtr),a=T(b,r.cssClasses.base),function(t,e){var n=T(e,r.cssClasses.connects);p=[],(m=[]).push(z(n,t[0]));for(var i=0;i=0&&t .noUi-tooltip{-webkit-transform:translate(50%, 0);transform:translate(50%, 0);left:auto;bottom:10px;}.bk-root .noUi-vertical .noUi-origin > .noUi-tooltip{-webkit-transform:translate(0, -18px);transform:translate(0, -18px);top:auto;right:28px;}.bk-root .noUi-handle{cursor:grab;cursor:-webkit-grab;}.bk-root .noUi-handle.noUi-active{cursor:grabbing;cursor:-webkit-grabbing;}.bk-root .noUi-handle:after,.bk-root .noUi-handle:before{display:none;}.bk-root .noUi-tooltip{display:none;white-space:nowrap;}.bk-root .noUi-handle:hover .noUi-tooltip{display:block;}.bk-root .noUi-horizontal{width:100%;height:10px;}.bk-root .noUi-vertical{width:10px;height:100%;}.bk-root .noUi-horizontal .noUi-handle{width:14px;height:18px;right:-7px;top:-5px;}.bk-root .noUi-vertical .noUi-handle{width:18px;height:14px;right:-5px;top:-7px;}.bk-root .noUi-target.noUi-horizontal{margin:5px 0px;}.bk-root .noUi-target.noUi-vertical{margin:0px 5px;}'},\n 465: function _(e,t,r,a,i){a();var s;const d=(0,e(1).__importDefault)(e(151)),o=e(461),_=e(8);class n extends o.AbstractSliderView{}r.DateSliderView=n,n.__name__=\"DateSliderView\";class c extends o.AbstractSlider{constructor(e){super(e),this.behaviour=\"tap\",this.connected=[!0,!1]}_formatter(e,t){return(0,_.isString)(t)?(0,d.default)(e,t):t.compute(e)}}r.DateSlider=c,s=c,c.__name__=\"DateSlider\",s.prototype.default_view=n,s.override({format:\"%d %b %Y\"})},\n 466: function _(e,t,r,a,i){a();var n;const s=(0,e(1).__importDefault)(e(151)),d=e(461),o=e(8);class _ extends d.AbstractRangeSliderView{}r.DatetimeRangeSliderView=_,_.__name__=\"DatetimeRangeSliderView\";class c extends d.AbstractSlider{constructor(e){super(e),this.behaviour=\"drag\",this.connected=[!1,!0,!1]}_formatter(e,t){return(0,o.isString)(t)?(0,s.default)(e,t):t.compute(e)}}r.DatetimeRangeSlider=c,n=c,c.__name__=\"DatetimeRangeSlider\",n.prototype.default_view=_,n.override({format:\"%d %b %Y %H:%M:%S\",step:36e5})},\n 467: function _(e,t,s,r,i){var _;r();const n=e(468);class a extends n.MarkupView{render(){super.render(),this.model.render_as_text?this.markup_el.textContent=this.model.text:this.markup_el.innerHTML=this.has_math_disabled()?this.model.text:this.process_tex()}}s.DivView=a,a.__name__=\"DivView\";class d extends n.Markup{constructor(e){super(e)}}s.Div=d,_=d,d.__name__=\"Div\",_.prototype.default_view=a,_.define((({Boolean:e})=>({render_as_text:[e,!1]})))},\n 468: function _(t,e,s,i,r){i();const a=t(1);var n;const o=t(210),d=t(43),h=t(137),l=t(512),_=(0,a.__importStar)(t(469));class u extends l.WidgetView{get provider(){return h.default_provider}async lazy_initialize(){await super.lazy_initialize(),\"not_started\"==this.provider.status&&await this.provider.fetch(),\"not_started\"!=this.provider.status&&\"loading\"!=this.provider.status||this.provider.ready.connect((()=>{this.contains_tex_string()&&this.rerender()}))}after_layout(){super.after_layout(),\"loading\"===this.provider.status&&(this._has_finished=!1)}rerender(){this.layout.invalidate_cache(),this.render(),this.root.compute_layout()}connect_signals(){super.connect_signals(),this.connect(this.model.change,(()=>{this.rerender()}))}styles(){return[...super.styles(),_.default]}_update_layout(){this.layout=new o.CachedVariadicBox(this.el),this.layout.set_sizing(this.box_sizing())}render(){super.render();const t=Object.assign(Object.assign({},this.model.style),{display:\"inline-block\"});this.markup_el=(0,d.div)({class:_.clearfix,style:t}),this.el.appendChild(this.markup_el),\"failed\"!=this.provider.status&&\"loaded\"!=this.provider.status||(this._has_finished=!0)}has_math_disabled(){return this.model.disable_math||!this.contains_tex_string()}process_tex(){if(!this.provider.MathJax)return this.model.text;const{text:t}=this.model,e=this.provider.MathJax.find_tex(t),s=[];let i=0;for(const r of e)s.push(t.slice(i,r.start.n)),s.push(this.provider.MathJax.tex2svg(r.math,{display:r.display}).outerHTML),i=r.end.n;return i0}}s.MarkupView=u,u.__name__=\"MarkupView\";class p extends l.Widget{constructor(t){super(t)}}s.Markup=p,n=p,p.__name__=\"Markup\",n.define((({Boolean:t,String:e,Dict:s})=>({text:[e,\"\"],style:[s(e),{}],disable_math:[t,!1]})))},\n 469: function _(o,r,e,t,a){t(),e.root=\"bk-root\",e.clearfix=\"bk-clearfix\",e.default='.bk-root .bk-clearfix:before,.bk-root .bk-clearfix:after{content:\"\";display:table;}.bk-root .bk-clearfix:after{clear:both;}'},\n 470: function _(e,t,i,n,s){n();const o=e(1);var l;const r=e(441),d=e(251),_=e(43),u=e(8),c=(0,o.__importStar)(e(318)),h=(0,o.__importStar)(e(229)),m=h;class p extends r.AbstractButtonView{constructor(){super(...arguments),this._open=!1}styles(){return[...super.styles(),h.default]}render(){super.render();const e=(0,_.div)({class:[m.caret,m.down]});if(this.model.is_split){const t=this._render_button(e);t.classList.add(c.dropdown_toggle),t.addEventListener(\"click\",(()=>this._toggle_menu())),this.group_el.appendChild(t)}else this.button_el.appendChild(e);const t=this.model.menu.map(((e,t)=>{if(null==e)return(0,_.div)({class:m.divider});{const i=(0,u.isString)(e)?e:e[0],n=(0,_.div)(i);return n.addEventListener(\"click\",(()=>this._item_click(t))),n}}));this.menu=(0,_.div)({class:[m.menu,m.below]},t),this.el.appendChild(this.menu),(0,_.undisplay)(this.menu)}_show_menu(){if(!this._open){this._open=!0,(0,_.display)(this.menu);const e=t=>{const{target:i}=t;i instanceof HTMLElement&&!this.el.contains(i)&&(document.removeEventListener(\"click\",e),this._hide_menu())};document.addEventListener(\"click\",e)}}_hide_menu(){this._open&&(this._open=!1,(0,_.undisplay)(this.menu))}_toggle_menu(){this._open?this._hide_menu():this._show_menu()}click(){this.model.is_split?(this._hide_menu(),this.model.trigger_event(new d.ButtonClick),super.click()):this._toggle_menu()}_item_click(e){this._hide_menu();const t=this.model.menu[e];if(null!=t){const i=(0,u.isString)(t)?t:t[1];(0,u.isString)(i)?this.model.trigger_event(new d.MenuItemClick(i)):i.execute(this.model,{index:e})}}}i.DropdownView=p,p.__name__=\"DropdownView\";class a extends r.AbstractButton{constructor(e){super(e)}get is_split(){return this.split}}i.Dropdown=a,l=a,a.__name__=\"Dropdown\",l.prototype.default_view=p,l.define((({Null:e,Boolean:t,String:i,Array:n,Tuple:s,Or:o})=>({split:[t,!1],menu:[n(o(i,s(i,o(i)),e)),[]]}))),l.override({label:\"Dropdown\"})},\n 471: function _(e,l,i,t,s){var n;t();const a=e(43),o=e(512);class d extends o.WidgetView{connect_signals(){super.connect_signals(),this.connect(this.model.change,(()=>this.render()))}render(){const{multiple:e,accept:l,disabled:i,width:t}=this.model;null==this.dialog_el&&(this.dialog_el=(0,a.input)({type:\"file\",multiple:e}),this.dialog_el.onchange=()=>{const{files:e}=this.dialog_el;null!=e&&this.load_files(e)},this.el.appendChild(this.dialog_el)),null!=l&&\"\"!=l&&(this.dialog_el.accept=l),this.dialog_el.style.width=`${t}px`,this.dialog_el.disabled=i}async load_files(e){const l=[],i=[],t=[];for(const s of e){const e=await this._read_file(s),[,n=\"\",,a=\"\"]=e.split(/[:;,]/,4);l.push(a),i.push(s.name),t.push(n)}this.model.multiple?this.model.setv({value:l,filename:i,mime_type:t}):this.model.setv({value:l[0],filename:i[0],mime_type:t[0]})}_read_file(e){return new Promise(((l,i)=>{const t=new FileReader;t.onload=()=>{var s;const{result:n}=t;null!=n?l(n):i(null!==(s=t.error)&&void 0!==s?s:new Error(`unable to read '${e.name}'`))},t.readAsDataURL(e)}))}}i.FileInputView=d,d.__name__=\"FileInputView\";class r extends o.Widget{constructor(e){super(e)}}i.FileInput=r,n=r,r.__name__=\"FileInput\",n.prototype.default_view=d,n.define((({Boolean:e,String:l,Array:i,Or:t})=>({value:[t(l,i(l)),\"\"],mime_type:[t(l,i(l)),\"\"],filename:[t(l,i(l)),\"\"],accept:[l,\"\"],multiple:[e,!1]})))},\n 472: function _(e,t,i,s,n){s();const l=e(1);var o;const r=e(43),c=e(8),h=e(448),p=(0,l.__importStar)(e(449));class d extends h.InputWidgetView{connect_signals(){super.connect_signals(),this.connect(this.model.properties.value.change,(()=>this.render_selection())),this.connect(this.model.properties.options.change,(()=>this.render())),this.connect(this.model.properties.name.change,(()=>this.render())),this.connect(this.model.properties.title.change,(()=>this.render())),this.connect(this.model.properties.size.change,(()=>this.render())),this.connect(this.model.properties.disabled.change,(()=>this.render()))}render(){super.render();const e=this.model.options.map((e=>{let t,i;return(0,c.isString)(e)?t=i=e:[t,i]=e,(0,r.option)({value:t},i)}));this.input_el=(0,r.select)({multiple:!0,class:p.input,name:this.model.name,disabled:this.model.disabled},e),this.input_el.addEventListener(\"change\",(()=>this.change_input())),this.group_el.appendChild(this.input_el),this.render_selection()}render_selection(){const e=new Set(this.model.value);for(const t of this.el.querySelectorAll(\"option\"))t.selected=e.has(t.value);this.input_el.size=this.model.size}change_input(){const e=null!=this.el.querySelector(\"select:focus\"),t=[];for(const e of this.el.querySelectorAll(\"option\"))e.selected&&t.push(e.value);this.model.value=t,super.change_input(),e&&this.input_el.focus()}}i.MultiSelectView=d,d.__name__=\"MultiSelectView\";class u extends h.InputWidget{constructor(e){super(e)}}i.MultiSelect=u,o=u,u.__name__=\"MultiSelect\",o.prototype.default_view=d,o.define((({Int:e,String:t,Array:i,Tuple:s,Or:n})=>({value:[i(t),[]],options:[i(n(t,s(t,t))),[]],size:[e,4]})))},\n 473: function _(e,a,r,t,s){var n;t();const p=e(468),_=e(43);class i extends p.MarkupView{render(){super.render();const e=(0,_.p)({style:{margin:0}});this.has_math_disabled()?e.textContent=this.model.text:e.innerHTML=this.process_tex(),this.markup_el.appendChild(e)}}r.ParagraphView=i,i.__name__=\"ParagraphView\";class h extends p.Markup{constructor(e){super(e)}}r.Paragraph=h,n=h,h.__name__=\"Paragraph\",n.prototype.default_view=i},\n 474: function _(e,s,t,n,r){var p;n();const u=e(446);class a extends u.TextInputView{render(){super.render(),this.input_el.type=\"password\"}}t.PasswordInputView=a,a.__name__=\"PasswordInputView\";class o extends u.TextInput{constructor(e){super(e)}}t.PasswordInput=o,p=o,o.__name__=\"PasswordInput\",p.prototype.default_view=a},\n 475: function _(e,t,i,l,s){l();const o=e(1);var n;const h=(0,o.__importDefault)(e(476)),a=e(43),u=e(8),c=e(210),_=(0,o.__importStar)(e(449)),d=(0,o.__importDefault)(e(477)),r=e(448);class m extends r.InputWidgetView{constructor(){super(...arguments),this._last_height=null}connect_signals(){super.connect_signals(),this.connect(this.model.properties.disabled.change,(()=>this.set_disabled()));const{value:e,max_items:t,option_limit:i,search_option_limit:l,delete_button:s,placeholder:o,options:n,name:h,title:a}=this.model.properties;this.on_change([e,t,i,l,s,o,n,h,a],(()=>this.render()))}styles(){return[...super.styles(),d.default]}_update_layout(){this.layout=new c.CachedVariadicBox(this.el),this.layout.set_sizing(this.box_sizing())}render(){super.render(),this.input_el=(0,a.select)({multiple:!0,class:_.input,name:this.model.name,disabled:this.model.disabled}),this.group_el.appendChild(this.input_el);const e=new Set(this.model.value),t=this.model.options.map((t=>{let i,l;return(0,u.isString)(t)?i=l=t:[i,l]=t,{value:i,label:l,selected:e.has(i)}})),i=this.model.solid?\"solid\":\"light\",l=`choices__item ${i}`,s=`choices__button ${i}`,o={choices:t,duplicateItemsAllowed:!1,removeItemButton:this.model.delete_button,classNames:{item:l,button:s}};null!=this.model.placeholder&&(o.placeholderValue=this.model.placeholder),null!=this.model.max_items&&(o.maxItemCount=this.model.max_items),null!=this.model.option_limit&&(o.renderChoiceLimit=this.model.option_limit),null!=this.model.search_option_limit&&(o.searchResultLimit=this.model.search_option_limit),this.choice_el=new h.default(this.input_el,o);const n=()=>this.choice_el.containerOuter.element.getBoundingClientRect().height;null!=this._last_height&&this._last_height!=n()&&this.root.invalidate_layout(),this._last_height=n(),this.input_el.addEventListener(\"change\",(()=>this.change_input()))}set_disabled(){this.model.disabled?this.choice_el.disable():this.choice_el.enable()}change_input(){const e=null!=this.el.querySelector(\"select:focus\"),t=[];for(const e of this.el.querySelectorAll(\"option\"))e.selected&&t.push(e.value);this.model.value=t,super.change_input(),e&&this.input_el.focus()}}i.MultiChoiceView=m,m.__name__=\"MultiChoiceView\";class p extends r.InputWidget{constructor(e){super(e)}}i.MultiChoice=p,n=p,p.__name__=\"MultiChoice\",n.prototype.default_view=m,n.define((({Boolean:e,Int:t,String:i,Array:l,Tuple:s,Or:o,Nullable:n})=>({value:[l(i),[]],options:[l(o(i,s(i,i))),[]],max_items:[n(t),null],delete_button:[e,!0],placeholder:[n(i),null],option_limit:[n(t),null],search_option_limit:[n(t),null],solid:[e,!0]})))},\n 476: function _(e,t,i,n,s){\n /*! choices.js v9.0.1 | © 2019 Josh Johnson | https://github.com/jshjohnson/Choices#readme */\n var r,o;r=window,o=function(){return function(e){var t={};function i(n){if(t[n])return t[n].exports;var s=t[n]={i:n,l:!1,exports:{}};return e[n].call(s.exports,s,s.exports,i),s.l=!0,s.exports}return i.m=e,i.c=t,i.d=function(e,t,n){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},i.r=function(e){\"undefined\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\"Module\"}),Object.defineProperty(e,\"__esModule\",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&\"object\"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,\"default\",{enumerable:!0,value:e}),2&t&&\"string\"!=typeof e)for(var s in e)i.d(n,s,function(t){return e[t]}.bind(null,s));return n},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,\"a\",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p=\"/public/assets/scripts/\",i(i.s=4)}([function(e,t,i){\"use strict\";var n=function(e){return function(e){return!!e&&\"object\"==typeof e}(e)&&!function(e){var t=Object.prototype.toString.call(e);return\"[object RegExp]\"===t||\"[object Date]\"===t||function(e){return e.$$typeof===s}(e)}(e)},s=\"function\"==typeof Symbol&&Symbol.for?Symbol.for(\"react.element\"):60103;function r(e,t){return!1!==t.clone&&t.isMergeableObject(e)?l((i=e,Array.isArray(i)?[]:{}),e,t):e;var i}function o(e,t,i){return e.concat(t).map((function(e){return r(e,i)}))}function a(e){return Object.keys(e).concat(function(e){return Object.getOwnPropertySymbols?Object.getOwnPropertySymbols(e).filter((function(t){return e.propertyIsEnumerable(t)})):[]}(e))}function c(e,t,i){var n={};return i.isMergeableObject(e)&&a(e).forEach((function(t){n[t]=r(e[t],i)})),a(t).forEach((function(s){(function(e,t){try{return t in e&&!(Object.hasOwnProperty.call(e,t)&&Object.propertyIsEnumerable.call(e,t))}catch(e){return!1}})(e,s)||(i.isMergeableObject(t[s])&&e[s]?n[s]=function(e,t){if(!t.customMerge)return l;var i=t.customMerge(e);return\"function\"==typeof i?i:l}(s,i)(e[s],t[s],i):n[s]=r(t[s],i))})),n}function l(e,t,i){(i=i||{}).arrayMerge=i.arrayMerge||o,i.isMergeableObject=i.isMergeableObject||n,i.cloneUnlessOtherwiseSpecified=r;var s=Array.isArray(t);return s===Array.isArray(e)?s?i.arrayMerge(e,t,i):c(e,t,i):r(t,i)}l.all=function(e,t){if(!Array.isArray(e))throw new Error(\"first argument should be an array\");return e.reduce((function(e,i){return l(e,i,t)}),{})};var h=l;e.exports=h},function(e,t,i){\"use strict\";(function(e,n){var s,r=i(3);s=\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:void 0!==e?e:n;var o=Object(r.a)(s);t.a=o}).call(this,i(5),i(6)(e))},function(e,t,i){\n /*!\n * Fuse.js v3.4.5 - Lightweight fuzzy-search (http://fusejs.io)\n *\n * Copyright (c) 2012-2017 Kirollos Risk (http://kiro.me)\n * All Rights Reserved. Apache Software License 2.0\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n */\n e.exports=function(e){var t={};function i(n){if(t[n])return t[n].exports;var s=t[n]={i:n,l:!1,exports:{}};return e[n].call(s.exports,s,s.exports,i),s.l=!0,s.exports}return i.m=e,i.c=t,i.d=function(e,t,n){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},i.r=function(e){\"undefined\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\"Module\"}),Object.defineProperty(e,\"__esModule\",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&\"object\"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,\"default\",{enumerable:!0,value:e}),2&t&&\"string\"!=typeof e)for(var s in e)i.d(n,s,function(t){return e[t]}.bind(null,s));return n},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,\"a\",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p=\"\",i(i.s=1)}([function(e,t){e.exports=function(e){return Array.isArray?Array.isArray(e):\"[object Array]\"===Object.prototype.toString.call(e)}},function(e,t,i){function n(e){return(n=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e})(e)}function s(e,t){for(var i=0;i1&&void 0!==arguments[1]?arguments[1]:{limit:!1};this._log('---------\\nSearch pattern: \"'.concat(e,'\"'));var i=this._prepareSearchers(e),n=i.tokenSearchers,s=i.fullSearcher,r=this._search(n,s),o=r.weights,a=r.results;return this._computeScore(o,a),this.options.shouldSort&&this._sort(a),t.limit&&\"number\"==typeof t.limit&&(a=a.slice(0,t.limit)),this._format(a)}},{key:\"_prepareSearchers\",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:\"\",t=[];if(this.options.tokenize)for(var i=e.split(this.options.tokenSeparator),n=0,s=i.length;n0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1?arguments[1]:void 0,i=this.list,n={},s=[];if(\"string\"==typeof i[0]){for(var r=0,o=i.length;r1)throw new Error(\"Key weight has to be > 0 and <= 1\");p=p.name}else a[p]={weight:1};this._analyze({key:p,value:this.options.getFn(h,p),record:h,index:c},{resultMap:n,results:s,tokenSearchers:e,fullSearcher:t})}return{weights:a,results:s}}},{key:\"_analyze\",value:function(e,t){var i=e.key,n=e.arrayIndex,s=void 0===n?-1:n,r=e.value,o=e.record,c=e.index,l=t.tokenSearchers,h=void 0===l?[]:l,u=t.fullSearcher,d=void 0===u?[]:u,p=t.resultMap,m=void 0===p?{}:p,f=t.results,v=void 0===f?[]:f;if(null!=r){var g=!1,_=-1,b=0;if(\"string\"==typeof r){this._log(\"\\nKey: \".concat(\"\"===i?\"-\":i));var y=d.search(r);if(this._log('Full text: \"'.concat(r,'\", score: ').concat(y.score)),this.options.tokenize){for(var E=r.split(this.options.tokenSeparator),I=[],S=0;S-1&&(P=(P+_)/2),this._log(\"Score average:\",P);var D=!this.options.tokenize||!this.options.matchAllTokens||b>=h.length;if(this._log(\"\\nCheck Matches: \".concat(D)),(g||y.isMatch)&&D){var M=m[c];M?M.output.push({key:i,arrayIndex:s,value:r,score:P,matchedIndices:y.matchedIndices}):(m[c]={item:o,output:[{key:i,arrayIndex:s,value:r,score:P,matchedIndices:y.matchedIndices}]},v.push(m[c]))}}else if(a(r))for(var N=0,F=r.length;N-1&&(o.arrayIndex=r.arrayIndex),t.matches.push(o)}}})),this.options.includeScore&&s.push((function(e,t){t.score=e.score}));for(var r=0,o=e.length;ri)return s(e,this.pattern,n);var o=this.options,a=o.location,c=o.distance,l=o.threshold,h=o.findAllMatches,u=o.minMatchCharLength;return r(e,this.pattern,this.patternAlphabet,{location:a,distance:c,threshold:l,findAllMatches:h,minMatchCharLength:u})}}])&&n(t.prototype,i),a&&n(t,a),e}();e.exports=a},function(e,t){var i=/[\\-\\[\\]\\/\\{\\}\\(\\)\\*\\+\\?\\.\\\\\\^\\$\\|]/g;e.exports=function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:/ +/g,s=new RegExp(t.replace(i,\"\\\\$&\").replace(n,\"|\")),r=e.match(s),o=!!r,a=[];if(o)for(var c=0,l=r.length;c=P;N-=1){var F=N-1,j=i[e.charAt(F)];if(j&&(E[F]=1),M[N]=(M[N+1]<<1|1)&j,0!==T&&(M[N]|=(O[N+1]|O[N])<<1|1|O[N+1]),M[N]&L&&(C=n(t,{errors:T,currentLocation:F,expectedLocation:v,distance:l}))<=_){if(_=C,(b=F)<=v)break;P=Math.max(1,2*v-b)}}if(n(t,{errors:T+1,currentLocation:v,expectedLocation:v,distance:l})>_)break;O=M}return{isMatch:b>=0,score:0===C?.001:C,matchedIndices:s(E,f)}}},function(e,t){e.exports=function(e,t){var i=t.errors,n=void 0===i?0:i,s=t.currentLocation,r=void 0===s?0:s,o=t.expectedLocation,a=void 0===o?0:o,c=t.distance,l=void 0===c?100:c,h=n/e.length,u=Math.abs(a-r);return l?h+u/l:u?1:h}},function(e,t){e.exports=function(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,i=[],n=-1,s=-1,r=0,o=e.length;r=t&&i.push([n,s]),n=-1)}return e[r-1]&&r-n>=t&&i.push([n,r-1]),i}},function(e,t){e.exports=function(e){for(var t={},i=e.length,n=0;n/g,\"&rt;\").replace(/-1?e.map((function(e){var i=e;return i.id===parseInt(t.choiceId,10)&&(i.selected=!0),i})):e;case\"REMOVE_ITEM\":return t.choiceId>-1?e.map((function(e){var i=e;return i.id===parseInt(t.choiceId,10)&&(i.selected=!1),i})):e;case\"FILTER_CHOICES\":return e.map((function(e){var i=e;return i.active=t.results.some((function(e){var t=e.item,n=e.score;return t.id===i.id&&(i.score=n,!0)})),i}));case\"ACTIVATE_CHOICES\":return e.map((function(e){var i=e;return i.active=t.active,i}));case\"CLEAR_CHOICES\":return v;default:return e}},general:_}),A=function(e,t){var i=e;if(\"CLEAR_ALL\"===t.type)i=void 0;else if(\"RESET_TO\"===t.type)return O(t.state);return C(i,t)};function L(e,t){for(var i=0;i\"'+I(e)+'\"'},maxItemText:function(e){return\"Only \"+e+\" values can be added\"},valueComparer:function(e,t){return e===t},fuseOptions:{includeScore:!0},callbackOnInit:null,callbackOnCreateTemplates:null,classNames:{containerOuter:\"choices\",containerInner:\"choices__inner\",input:\"choices__input\",inputCloned:\"choices__input--cloned\",list:\"choices__list\",listItems:\"choices__list--multiple\",listSingle:\"choices__list--single\",listDropdown:\"choices__list--dropdown\",item:\"choices__item\",itemSelectable:\"choices__item--selectable\",itemDisabled:\"choices__item--disabled\",itemChoice:\"choices__item--choice\",placeholder:\"choices__placeholder\",group:\"choices__group\",groupHeading:\"choices__heading\",button:\"choices__button\",activeState:\"is-active\",focusState:\"is-focused\",openState:\"is-open\",disabledState:\"is-disabled\",highlightedState:\"is-highlighted\",selectedState:\"is-selected\",flippedState:\"is-flipped\",loadingState:\"is-loading\",noResults:\"has-no-results\",noChoices:\"has-no-choices\"}},D=\"showDropdown\",M=\"hideDropdown\",N=\"change\",F=\"choice\",j=\"search\",K=\"addItem\",R=\"removeItem\",H=\"highlightItem\",B=\"highlightChoice\",V=\"ADD_CHOICE\",G=\"FILTER_CHOICES\",q=\"ACTIVATE_CHOICES\",U=\"CLEAR_CHOICES\",z=\"ADD_GROUP\",W=\"ADD_ITEM\",X=\"REMOVE_ITEM\",$=\"HIGHLIGHT_ITEM\",J=46,Y=8,Z=13,Q=65,ee=27,te=38,ie=40,ne=33,se=34,re=\"text\",oe=\"select-one\",ae=\"select-multiple\",ce=function(){function e(e){var t=e.element,i=e.type,n=e.classNames,s=e.position;this.element=t,this.classNames=n,this.type=i,this.position=s,this.isOpen=!1,this.isFlipped=!1,this.isFocussed=!1,this.isDisabled=!1,this.isLoading=!1,this._onFocus=this._onFocus.bind(this),this._onBlur=this._onBlur.bind(this)}var t=e.prototype;return t.addEventListeners=function(){this.element.addEventListener(\"focus\",this._onFocus),this.element.addEventListener(\"blur\",this._onBlur)},t.removeEventListeners=function(){this.element.removeEventListener(\"focus\",this._onFocus),this.element.removeEventListener(\"blur\",this._onBlur)},t.shouldFlip=function(e){if(\"number\"!=typeof e)return!1;var t=!1;return\"auto\"===this.position?t=!window.matchMedia(\"(min-height: \"+(e+1)+\"px)\").matches:\"top\"===this.position&&(t=!0),t},t.setActiveDescendant=function(e){this.element.setAttribute(\"aria-activedescendant\",e)},t.removeActiveDescendant=function(){this.element.removeAttribute(\"aria-activedescendant\")},t.open=function(e){this.element.classList.add(this.classNames.openState),this.element.setAttribute(\"aria-expanded\",\"true\"),this.isOpen=!0,this.shouldFlip(e)&&(this.element.classList.add(this.classNames.flippedState),this.isFlipped=!0)},t.close=function(){this.element.classList.remove(this.classNames.openState),this.element.setAttribute(\"aria-expanded\",\"false\"),this.removeActiveDescendant(),this.isOpen=!1,this.isFlipped&&(this.element.classList.remove(this.classNames.flippedState),this.isFlipped=!1)},t.focus=function(){this.isFocussed||this.element.focus()},t.addFocusState=function(){this.element.classList.add(this.classNames.focusState)},t.removeFocusState=function(){this.element.classList.remove(this.classNames.focusState)},t.enable=function(){this.element.classList.remove(this.classNames.disabledState),this.element.removeAttribute(\"aria-disabled\"),this.type===oe&&this.element.setAttribute(\"tabindex\",\"0\"),this.isDisabled=!1},t.disable=function(){this.element.classList.add(this.classNames.disabledState),this.element.setAttribute(\"aria-disabled\",\"true\"),this.type===oe&&this.element.setAttribute(\"tabindex\",\"-1\"),this.isDisabled=!0},t.wrap=function(e){!function(e,t){void 0===t&&(t=document.createElement(\"div\")),e.nextSibling?e.parentNode.insertBefore(t,e.nextSibling):e.parentNode.appendChild(t),t.appendChild(e)}(e,this.element)},t.unwrap=function(e){this.element.parentNode.insertBefore(e,this.element),this.element.parentNode.removeChild(this.element)},t.addLoadingState=function(){this.element.classList.add(this.classNames.loadingState),this.element.setAttribute(\"aria-busy\",\"true\"),this.isLoading=!0},t.removeLoadingState=function(){this.element.classList.remove(this.classNames.loadingState),this.element.removeAttribute(\"aria-busy\"),this.isLoading=!1},t._onFocus=function(){this.isFocussed=!0},t._onBlur=function(){this.isFocussed=!1},e}();function le(e,t){for(var i=0;i0?this.element.scrollTop+o-s:e.offsetTop;requestAnimationFrame((function(){i._animateScroll(a,t)}))}},t._scrollDown=function(e,t,i){var n=(i-e)/t,s=n>1?n:1;this.element.scrollTop=e+s},t._scrollUp=function(e,t,i){var n=(e-i)/t,s=n>1?n:1;this.element.scrollTop=e-s},t._animateScroll=function(e,t){var i=this,n=this.element.scrollTop,s=!1;t>0?(this._scrollDown(n,4,e),ne&&(s=!0)),s&&requestAnimationFrame((function(){i._animateScroll(e,t)}))},e}();function de(e,t){for(var i=0;i0?\"treeitem\":\"option\"),Object.assign(g.dataset,{choice:\"\",id:l,value:h,selectText:i}),m?(g.classList.add(a),g.dataset.choiceDisabled=\"\",g.setAttribute(\"aria-disabled\",\"true\")):(g.classList.add(r),g.dataset.choiceSelectable=\"\"),g},input:function(e,t){var i=e.input,n=e.inputCloned,s=Object.assign(document.createElement(\"input\"),{type:\"text\",className:i+\" \"+n,autocomplete:\"off\",autocapitalize:\"off\",spellcheck:!1});return s.setAttribute(\"role\",\"textbox\"),s.setAttribute(\"aria-autocomplete\",\"list\"),s.setAttribute(\"aria-label\",t),s},dropdown:function(e){var t=e.list,i=e.listDropdown,n=document.createElement(\"div\");return n.classList.add(t,i),n.setAttribute(\"aria-expanded\",\"false\"),n},notice:function(e,t,i){var n=e.item,s=e.itemChoice,r=e.noResults,o=e.noChoices;void 0===i&&(i=\"\");var a=[n,s];return\"no-choices\"===i?a.push(o):\"no-results\"===i&&a.push(r),Object.assign(document.createElement(\"div\"),{innerHTML:t,className:a.join(\" \")})},option:function(e){var t=e.label,i=e.value,n=e.customProperties,s=e.active,r=e.disabled,o=new Option(t,i,!1,s);return n&&(o.dataset.customProperties=n),o.disabled=r,o}},be=function(e){return void 0===e&&(e=!0),{type:q,active:e}},ye=function(e,t){return{type:$,id:e,highlighted:t}},Ee=function(e){var t=e.value,i=e.id,n=e.active,s=e.disabled;return{type:z,value:t,id:i,active:n,disabled:s}},Ie=function(e){return{type:\"SET_IS_LOADING\",isLoading:e}};function Se(e,t){for(var i=0;i=0?this._store.getGroupById(s):null;return this._store.dispatch(ye(i,!0)),t&&this.passedElement.triggerEvent(H,{id:i,value:o,label:c,groupValue:l&&l.value?l.value:null}),this},r.unhighlightItem=function(e){if(!e)return this;var t=e.id,i=e.groupId,n=void 0===i?-1:i,s=e.value,r=void 0===s?\"\":s,o=e.label,a=void 0===o?\"\":o,c=n>=0?this._store.getGroupById(n):null;return this._store.dispatch(ye(t,!1)),this.passedElement.triggerEvent(H,{id:t,value:r,label:a,groupValue:c&&c.value?c.value:null}),this},r.highlightAll=function(){var e=this;return this._store.items.forEach((function(t){return e.highlightItem(t)})),this},r.unhighlightAll=function(){var e=this;return this._store.items.forEach((function(t){return e.unhighlightItem(t)})),this},r.removeActiveItemsByValue=function(e){var t=this;return this._store.activeItems.filter((function(t){return t.value===e})).forEach((function(e){return t._removeItem(e)})),this},r.removeActiveItems=function(e){var t=this;return this._store.activeItems.filter((function(t){return t.id!==e})).forEach((function(e){return t._removeItem(e)})),this},r.removeHighlightedItems=function(e){var t=this;return void 0===e&&(e=!1),this._store.highlightedActiveItems.forEach((function(i){t._removeItem(i),e&&t._triggerChange(i.value)})),this},r.showDropdown=function(e){var t=this;return this.dropdown.isActive||requestAnimationFrame((function(){t.dropdown.show(),t.containerOuter.open(t.dropdown.distanceFromTopWindow),!e&&t._canSearch&&t.input.focus(),t.passedElement.triggerEvent(D,{})})),this},r.hideDropdown=function(e){var t=this;return this.dropdown.isActive?(requestAnimationFrame((function(){t.dropdown.hide(),t.containerOuter.close(),!e&&t._canSearch&&(t.input.removeActiveDescendant(),t.input.blur()),t.passedElement.triggerEvent(M,{})})),this):this},r.getValue=function(e){void 0===e&&(e=!1);var t=this._store.activeItems.reduce((function(t,i){var n=e?i.value:i;return t.push(n),t}),[]);return this._isSelectOneElement?t[0]:t},r.setValue=function(e){var t=this;return this.initialised?(e.forEach((function(e){return t._setChoiceOrItem(e)})),this):this},r.setChoiceByValue=function(e){var t=this;return!this.initialised||this._isTextElement||(Array.isArray(e)?e:[e]).forEach((function(e){return t._findAndSelectChoiceByValue(e)})),this},r.setChoices=function(e,t,i,n){var s=this;if(void 0===e&&(e=[]),void 0===t&&(t=\"value\"),void 0===i&&(i=\"label\"),void 0===n&&(n=!1),!this.initialised)throw new ReferenceError(\"setChoices was called on a non-initialized instance of Choices\");if(!this._isSelectElement)throw new TypeError(\"setChoices can't be used with INPUT based Choices\");if(\"string\"!=typeof t||!t)throw new TypeError(\"value parameter must be a name of 'value' field in passed objects\");if(n&&this.clearChoices(),\"function\"==typeof e){var r=e(this);if(\"function\"==typeof Promise&&r instanceof Promise)return new Promise((function(e){return requestAnimationFrame(e)})).then((function(){return s._handleLoadingState(!0)})).then((function(){return r})).then((function(e){return s.setChoices(e,t,i,n)})).catch((function(e){s.config.silent||console.error(e)})).then((function(){return s._handleLoadingState(!1)})).then((function(){return s}));if(!Array.isArray(r))throw new TypeError(\".setChoices first argument function must return either array of choices or Promise, got: \"+typeof r);return this.setChoices(r,t,i,!1)}if(!Array.isArray(e))throw new TypeError(\".setChoices must be called either with array of choices with a function resulting into Promise of array of choices\");return this.containerOuter.removeLoadingState(),this._startLoading(),e.forEach((function(e){e.choices?s._addGroup({id:parseInt(e.id,10)||null,group:e,valueKey:t,labelKey:i}):s._addChoice({value:e[t],label:e[i],isSelected:e.selected,isDisabled:e.disabled,customProperties:e.customProperties,placeholder:e.placeholder})})),this._stopLoading(),this},r.clearChoices=function(){return this._store.dispatch({type:U}),this},r.clearStore=function(){return this._store.dispatch({type:\"CLEAR_ALL\"}),this},r.clearInput=function(){var e=!this._isSelectOneElement;return this.input.clear(e),!this._isTextElement&&this._canSearch&&(this._isSearching=!1,this._store.dispatch(be(!0))),this},r._render=function(){if(!this._store.isLoading()){this._currentState=this._store.state;var e=this._currentState.choices!==this._prevState.choices||this._currentState.groups!==this._prevState.groups||this._currentState.items!==this._prevState.items,t=this._isSelectElement,i=this._currentState.items!==this._prevState.items;e&&(t&&this._renderChoices(),i&&this._renderItems(),this._prevState=this._currentState)}},r._renderChoices=function(){var e=this,t=this._store,i=t.activeGroups,n=t.activeChoices,s=document.createDocumentFragment();if(this.choiceList.clear(),this.config.resetScrollPosition&&requestAnimationFrame((function(){return e.choiceList.scrollToTop()})),i.length>=1&&!this._isSearching){var r=n.filter((function(e){return!0===e.placeholder&&-1===e.groupId}));r.length>=1&&(s=this._createChoicesFragment(r,s)),s=this._createGroupsFragment(i,n,s)}else n.length>=1&&(s=this._createChoicesFragment(n,s));if(s.childNodes&&s.childNodes.length>0){var o=this._store.activeItems,a=this._canAddItem(o,this.input.value);a.response?(this.choiceList.append(s),this._highlightChoice()):this.choiceList.append(this._getTemplate(\"notice\",a.notice))}else{var c,l;this._isSearching?(l=\"function\"==typeof this.config.noResultsText?this.config.noResultsText():this.config.noResultsText,c=this._getTemplate(\"notice\",l,\"no-results\")):(l=\"function\"==typeof this.config.noChoicesText?this.config.noChoicesText():this.config.noChoicesText,c=this._getTemplate(\"notice\",l,\"no-choices\")),this.choiceList.append(c)}},r._renderItems=function(){var e=this._store.activeItems||[];this.itemList.clear();var t=this._createItemsFragment(e);t.childNodes&&this.itemList.append(t)},r._createGroupsFragment=function(e,t,i){var n=this;return void 0===i&&(i=document.createDocumentFragment()),this.config.shouldSort&&e.sort(this.config.sorter),e.forEach((function(e){var s=function(e){return t.filter((function(t){return n._isSelectOneElement?t.groupId===e.id:t.groupId===e.id&&(\"always\"===n.config.renderSelectedChoices||!t.selected)}))}(e);if(s.length>=1){var r=n._getTemplate(\"choiceGroup\",e);i.appendChild(r),n._createChoicesFragment(s,i,!0)}})),i},r._createChoicesFragment=function(e,t,i){var n=this;void 0===t&&(t=document.createDocumentFragment()),void 0===i&&(i=!1);var s=this.config,r=s.renderSelectedChoices,o=s.searchResultLimit,a=s.renderChoiceLimit,c=this._isSearching?w:this.config.sorter,l=function(e){if(\"auto\"!==r||n._isSelectOneElement||!e.selected){var i=n._getTemplate(\"choice\",e,n.config.itemSelectText);t.appendChild(i)}},h=e;\"auto\"!==r||this._isSelectOneElement||(h=e.filter((function(e){return!e.selected})));var u=h.reduce((function(e,t){return t.placeholder?e.placeholderChoices.push(t):e.normalChoices.push(t),e}),{placeholderChoices:[],normalChoices:[]}),d=u.placeholderChoices,p=u.normalChoices;(this.config.shouldSort||this._isSearching)&&p.sort(c);var m=h.length,f=this._isSelectOneElement?[].concat(d,p):p;this._isSearching?m=o:a&&a>0&&!i&&(m=a);for(var v=0;v=n){var o=s?this._searchChoices(e):0;this.passedElement.triggerEvent(j,{value:e,resultCount:o})}else r&&(this._isSearching=!1,this._store.dispatch(be(!0)))}},r._canAddItem=function(e,t){var i=!0,n=\"function\"==typeof this.config.addItemText?this.config.addItemText(t):this.config.addItemText;if(!this._isSelectOneElement){var s=function(e,t,i){return void 0===i&&(i=\"value\"),e.some((function(e){return\"string\"==typeof t?e[i]===t.trim():e[i]===t}))}(e,t);this.config.maxItemCount>0&&this.config.maxItemCount<=e.length&&(i=!1,n=\"function\"==typeof this.config.maxItemText?this.config.maxItemText(this.config.maxItemCount):this.config.maxItemText),!this.config.duplicateItemsAllowed&&s&&i&&(i=!1,n=\"function\"==typeof this.config.uniqueItemText?this.config.uniqueItemText(t):this.config.uniqueItemText),this._isTextElement&&this.config.addItems&&i&&\"function\"==typeof this.config.addItemFilter&&!this.config.addItemFilter(t)&&(i=!1,n=\"function\"==typeof this.config.customAddItemText?this.config.customAddItemText(t):this.config.customAddItemText)}return{response:i,notice:n}},r._searchChoices=function(e){var t=\"string\"==typeof e?e.trim():e,i=\"string\"==typeof this._currentValue?this._currentValue.trim():this._currentValue;if(t.length<1&&t===i+\" \")return 0;var n=this._store.searchableChoices,r=t,o=[].concat(this.config.searchFields),a=Object.assign(this.config.fuseOptions,{keys:o}),c=new s.a(n,a).search(r);return this._currentValue=t,this._highlightPosition=0,this._isSearching=!0,this._store.dispatch(function(e){return{type:G,results:e}}(c)),c.length},r._addEventListeners=function(){var e=document.documentElement;e.addEventListener(\"touchend\",this._onTouchEnd,!0),this.containerOuter.element.addEventListener(\"keydown\",this._onKeyDown,!0),this.containerOuter.element.addEventListener(\"mousedown\",this._onMouseDown,!0),e.addEventListener(\"click\",this._onClick,{passive:!0}),e.addEventListener(\"touchmove\",this._onTouchMove,{passive:!0}),this.dropdown.element.addEventListener(\"mouseover\",this._onMouseOver,{passive:!0}),this._isSelectOneElement&&(this.containerOuter.element.addEventListener(\"focus\",this._onFocus,{passive:!0}),this.containerOuter.element.addEventListener(\"blur\",this._onBlur,{passive:!0})),this.input.element.addEventListener(\"keyup\",this._onKeyUp,{passive:!0}),this.input.element.addEventListener(\"focus\",this._onFocus,{passive:!0}),this.input.element.addEventListener(\"blur\",this._onBlur,{passive:!0}),this.input.element.form&&this.input.element.form.addEventListener(\"reset\",this._onFormReset,{passive:!0}),this.input.addEventListeners()},r._removeEventListeners=function(){var e=document.documentElement;e.removeEventListener(\"touchend\",this._onTouchEnd,!0),this.containerOuter.element.removeEventListener(\"keydown\",this._onKeyDown,!0),this.containerOuter.element.removeEventListener(\"mousedown\",this._onMouseDown,!0),e.removeEventListener(\"click\",this._onClick),e.removeEventListener(\"touchmove\",this._onTouchMove),this.dropdown.element.removeEventListener(\"mouseover\",this._onMouseOver),this._isSelectOneElement&&(this.containerOuter.element.removeEventListener(\"focus\",this._onFocus),this.containerOuter.element.removeEventListener(\"blur\",this._onBlur)),this.input.element.removeEventListener(\"keyup\",this._onKeyUp),this.input.element.removeEventListener(\"focus\",this._onFocus),this.input.element.removeEventListener(\"blur\",this._onBlur),this.input.element.form&&this.input.element.form.removeEventListener(\"reset\",this._onFormReset),this.input.removeEventListeners()},r._onKeyDown=function(e){var t,i=e.target,n=e.keyCode,s=e.ctrlKey,r=e.metaKey,o=this._store.activeItems,a=this.input.isFocussed,c=this.dropdown.isActive,l=this.itemList.hasChildren(),h=String.fromCharCode(n),u=J,d=Y,p=Z,m=Q,f=ee,v=te,g=ie,_=ne,b=se,y=s||r;!this._isTextElement&&/[a-zA-Z0-9-_ ]/.test(h)&&this.showDropdown();var E=((t={})[m]=this._onAKey,t[p]=this._onEnterKey,t[f]=this._onEscapeKey,t[v]=this._onDirectionKey,t[_]=this._onDirectionKey,t[g]=this._onDirectionKey,t[b]=this._onDirectionKey,t[d]=this._onDeleteKey,t[u]=this._onDeleteKey,t);E[n]&&E[n]({event:e,target:i,keyCode:n,metaKey:r,activeItems:o,hasFocusedInput:a,hasActiveDropdown:c,hasItems:l,hasCtrlDownKeyPressed:y})},r._onKeyUp=function(e){var t=e.target,i=e.keyCode,n=this.input.value,s=this._store.activeItems,r=this._canAddItem(s,n),o=J,a=Y;if(this._isTextElement)if(r.notice&&n){var c=this._getTemplate(\"notice\",r.notice);this.dropdown.element.innerHTML=c.outerHTML,this.showDropdown(!0)}else this.hideDropdown(!0);else{var l=(i===o||i===a)&&!t.value,h=!this._isTextElement&&this._isSearching,u=this._canSearch&&r.response;l&&h?(this._isSearching=!1,this._store.dispatch(be(!0))):u&&this._handleSearch(this.input.value)}this._canSearch=this.config.searchEnabled},r._onAKey=function(e){var t=e.hasItems;e.hasCtrlDownKeyPressed&&t&&(this._canSearch=!1,this.config.removeItems&&!this.input.value&&this.input.element===document.activeElement&&this.highlightAll())},r._onEnterKey=function(e){var t=e.event,i=e.target,n=e.activeItems,s=e.hasActiveDropdown,r=Z,o=i.hasAttribute(\"data-button\");if(this._isTextElement&&i.value){var a=this.input.value;this._canAddItem(n,a).response&&(this.hideDropdown(!0),this._addItem({value:a}),this._triggerChange(a),this.clearInput())}if(o&&(this._handleButtonAction(n,i),t.preventDefault()),s){var c=this.dropdown.getChild(\".\"+this.config.classNames.highlightedState);c&&(n[0]&&(n[0].keyCode=r),this._handleChoiceAction(n,c)),t.preventDefault()}else this._isSelectOneElement&&(this.showDropdown(),t.preventDefault())},r._onEscapeKey=function(e){e.hasActiveDropdown&&(this.hideDropdown(!0),this.containerOuter.focus())},r._onDirectionKey=function(e){var t,i,n,s=e.event,r=e.hasActiveDropdown,o=e.keyCode,a=e.metaKey,c=ie,l=ne,h=se;if(r||this._isSelectOneElement){this.showDropdown(),this._canSearch=!1;var u,d=o===c||o===h?1:-1,p=\"[data-choice-selectable]\";if(a||o===h||o===l)u=d>0?this.dropdown.element.querySelector(\"[data-choice-selectable]:last-of-type\"):this.dropdown.element.querySelector(p);else{var m=this.dropdown.element.querySelector(\".\"+this.config.classNames.highlightedState);u=m?function(e,t,i){if(void 0===i&&(i=1),e instanceof Element&&\"string\"==typeof t){for(var n=(i>0?\"next\":\"previous\")+\"ElementSibling\",s=e[n];s;){if(s.matches(t))return s;s=s[n]}return s}}(m,p,d):this.dropdown.element.querySelector(p)}u&&(t=u,i=this.choiceList.element,void 0===(n=d)&&(n=1),t&&(n>0?i.scrollTop+i.offsetHeight>=t.offsetTop+t.offsetHeight:t.offsetTop>=i.scrollTop)||this.choiceList.scrollToChildElement(u,d),this._highlightChoice(u)),s.preventDefault()}},r._onDeleteKey=function(e){var t=e.event,i=e.target,n=e.hasFocusedInput,s=e.activeItems;!n||i.value||this._isSelectOneElement||(this._handleBackspace(s),t.preventDefault())},r._onTouchMove=function(){this._wasTap&&(this._wasTap=!1)},r._onTouchEnd=function(e){var t=(e||e.touches[0]).target;this._wasTap&&this.containerOuter.element.contains(t)&&((t===this.containerOuter.element||t===this.containerInner.element)&&(this._isTextElement?this.input.focus():this._isSelectMultipleElement&&this.showDropdown()),e.stopPropagation()),this._wasTap=!0},r._onMouseDown=function(e){var t=e.target;if(t instanceof HTMLElement){if(we&&this.choiceList.element.contains(t)){var i=this.choiceList.element.firstElementChild,n=\"ltr\"===this._direction?e.offsetX>=i.offsetWidth:e.offsetX0&&this.unhighlightAll(),this.containerOuter.removeFocusState(),this.hideDropdown(!0))},r._onFocus=function(e){var t,i=this,n=e.target;this.containerOuter.element.contains(n)&&((t={}).text=function(){n===i.input.element&&i.containerOuter.addFocusState()},t[\"select-one\"]=function(){i.containerOuter.addFocusState(),n===i.input.element&&i.showDropdown(!0)},t[\"select-multiple\"]=function(){n===i.input.element&&(i.showDropdown(!0),i.containerOuter.addFocusState())},t)[this.passedElement.element.type]()},r._onBlur=function(e){var t=this,i=e.target;if(this.containerOuter.element.contains(i)&&!this._isScrollingOnIe){var n,s=this._store.activeItems.some((function(e){return e.highlighted}));((n={}).text=function(){i===t.input.element&&(t.containerOuter.removeFocusState(),s&&t.unhighlightAll(),t.hideDropdown(!0))},n[\"select-one\"]=function(){t.containerOuter.removeFocusState(),(i===t.input.element||i===t.containerOuter.element&&!t._canSearch)&&t.hideDropdown(!0)},n[\"select-multiple\"]=function(){i===t.input.element&&(t.containerOuter.removeFocusState(),t.hideDropdown(!0),s&&t.unhighlightAll())},n)[this.passedElement.element.type]()}else this._isScrollingOnIe=!1,this.input.element.focus()},r._onFormReset=function(){this._store.dispatch({type:\"RESET_TO\",state:this._initialState})},r._highlightChoice=function(e){var t=this;void 0===e&&(e=null);var i=Array.from(this.dropdown.element.querySelectorAll(\"[data-choice-selectable]\"));if(i.length){var n=e;Array.from(this.dropdown.element.querySelectorAll(\".\"+this.config.classNames.highlightedState)).forEach((function(e){e.classList.remove(t.config.classNames.highlightedState),e.setAttribute(\"aria-selected\",\"false\")})),n?this._highlightPosition=i.indexOf(n):(n=i.length>this._highlightPosition?i[this._highlightPosition]:i[i.length-1])||(n=i[0]),n.classList.add(this.config.classNames.highlightedState),n.setAttribute(\"aria-selected\",\"true\"),this.passedElement.triggerEvent(B,{el:n}),this.dropdown.isActive&&(this.input.setActiveDescendant(n.id),this.containerOuter.setActiveDescendant(n.id))}},r._addItem=function(e){var t=e.value,i=e.label,n=void 0===i?null:i,s=e.choiceId,r=void 0===s?-1:s,o=e.groupId,a=void 0===o?-1:o,c=e.customProperties,l=void 0===c?null:c,h=e.placeholder,u=void 0!==h&&h,d=e.keyCode,p=void 0===d?null:d,m=\"string\"==typeof t?t.trim():t,f=p,v=l,g=this._store.items,_=n||m,b=r||-1,y=a>=0?this._store.getGroupById(a):null,E=g?g.length+1:1;return this.config.prependValue&&(m=this.config.prependValue+m.toString()),this.config.appendValue&&(m+=this.config.appendValue.toString()),this._store.dispatch(function(e){var t=e.value,i=e.label,n=e.id,s=e.choiceId,r=e.groupId,o=e.customProperties,a=e.placeholder,c=e.keyCode;return{type:W,value:t,label:i,id:n,choiceId:s,groupId:r,customProperties:o,placeholder:a,keyCode:c}}({value:m,label:_,id:E,choiceId:b,groupId:a,customProperties:l,placeholder:u,keyCode:f})),this._isSelectOneElement&&this.removeActiveItems(E),this.passedElement.triggerEvent(K,{id:E,value:m,label:_,customProperties:v,groupValue:y&&y.value?y.value:void 0,keyCode:f}),this},r._removeItem=function(e){if(!e||!E(\"Object\",e))return this;var t=e.id,i=e.value,n=e.label,s=e.choiceId,r=e.groupId,o=r>=0?this._store.getGroupById(r):null;return this._store.dispatch(function(e,t){return{type:X,id:e,choiceId:t}}(t,s)),o&&o.value?this.passedElement.triggerEvent(R,{id:t,value:i,label:n,groupValue:o.value}):this.passedElement.triggerEvent(R,{id:t,value:i,label:n}),this},r._addChoice=function(e){var t=e.value,i=e.label,n=void 0===i?null:i,s=e.isSelected,r=void 0!==s&&s,o=e.isDisabled,a=void 0!==o&&o,c=e.groupId,l=void 0===c?-1:c,h=e.customProperties,u=void 0===h?null:h,d=e.placeholder,p=void 0!==d&&d,m=e.keyCode,f=void 0===m?null:m;if(null!=t){var v=this._store.choices,g=n||t,_=v?v.length+1:1,b=this._baseId+\"-\"+this._idNames.itemChoice+\"-\"+_;this._store.dispatch(function(e){var t=e.value,i=e.label,n=e.id,s=e.groupId,r=e.disabled,o=e.elementId,a=e.customProperties,c=e.placeholder,l=e.keyCode;return{type:V,value:t,label:i,id:n,groupId:s,disabled:r,elementId:o,customProperties:a,placeholder:c,keyCode:l}}({id:_,groupId:l,elementId:b,value:t,label:g,disabled:a,customProperties:u,placeholder:p,keyCode:f})),r&&this._addItem({value:t,label:g,choiceId:_,customProperties:u,placeholder:p,keyCode:f})}},r._addGroup=function(e){var t=this,i=e.group,n=e.id,s=e.valueKey,r=void 0===s?\"value\":s,o=e.labelKey,a=void 0===o?\"label\":o,c=E(\"Object\",i)?i.choices:Array.from(i.getElementsByTagName(\"OPTION\")),l=n||Math.floor((new Date).valueOf()*Math.random()),h=!!i.disabled&&i.disabled;c?(this._store.dispatch(Ee({value:i.label,id:l,active:!0,disabled:h})),c.forEach((function(e){var i=e.disabled||e.parentNode&&e.parentNode.disabled;t._addChoice({value:e[r],label:E(\"Object\",e)?e[a]:e.innerHTML,isSelected:e.selected,isDisabled:i,groupId:l,customProperties:e.customProperties,placeholder:e.placeholder})}))):this._store.dispatch(Ee({value:i.label,id:i.id,active:!1,disabled:i.disabled}))},r._getTemplate=function(e){var t;if(!e)return null;for(var i=this.config.classNames,n=arguments.length,s=new Array(n>1?n-1:0),r=1;r{var e;return this.input_el.name=null!==(e=this.model.name)&&void 0!==e?e:\"\"})),this.connect(this.model.properties.value.change,(()=>{this.input_el.value=this.format_value,this.old_value=this.input_el.value})),this.connect(this.model.properties.low.change,(()=>{const{value:e,low:t,high:l}=this.model;null!=t&&null!=l&&(0,p.assert)(t<=l,\"Invalid bounds, low must be inferior to high\"),null!=e&&null!=t&&e{const{value:e,low:t,high:l}=this.model;null!=t&&null!=l&&(0,p.assert)(l>=t,\"Invalid bounds, high must be superior to low\"),null!=e&&null!=l&&e>l&&(this.model.value=l)})),this.connect(this.model.properties.high.change,(()=>this.input_el.placeholder=this.model.placeholder)),this.connect(this.model.properties.disabled.change,(()=>this.input_el.disabled=this.model.disabled)),this.connect(this.model.properties.placeholder.change,(()=>this.input_el.placeholder=this.model.placeholder))}get format_value(){return null!=this.model.value?this.model.pretty(this.model.value):\"\"}_set_input_filter(e){this.input_el.addEventListener(\"input\",(()=>{const{selectionStart:t,selectionEnd:l}=this.input_el;if(e(this.input_el.value))this.old_value=this.input_el.value;else{const e=this.old_value.length-this.input_el.value.length;this.input_el.value=this.old_value,t&&l&&this.input_el.setSelectionRange(t-1,l+e)}}))}render(){super.render(),this.input_el=(0,r.input)({type:\"text\",class:_.input,name:this.model.name,value:this.format_value,disabled:this.model.disabled,placeholder:this.model.placeholder}),this.old_value=this.format_value,this.set_input_filter(),this.input_el.addEventListener(\"change\",(()=>this.change_input())),this.input_el.addEventListener(\"focusout\",(()=>this.input_el.value=this.format_value)),this.group_el.appendChild(this.input_el)}set_input_filter(){\"int\"==this.model.mode?this._set_input_filter((e=>m.test(e))):\"float\"==this.model.mode&&this._set_input_filter((e=>c.test(e)))}bound_value(e){let t=e;const{low:l,high:i}=this.model;return t=null!=l?Math.max(l,t):t,t=null!=i?Math.min(i,t):t,t}get value(){let e=\"\"!=this.input_el.value?Number(this.input_el.value):null;return null!=e&&(e=this.bound_value(e)),e}change_input(){null==this.value?this.model.value=null:Number.isNaN(this.value)||(this.model.value=this.value)}}l.NumericInputView=v,v.__name__=\"NumericInputView\";class g extends o.InputWidget{constructor(e){super(e)}_formatter(e,t){return(0,d.isString)(t)?h.format(e,t):t.doFormat([e],{loc:0})[0]}pretty(e){return null!=this.format?this._formatter(e,this.format):`${e}`}}l.NumericInput=g,u=g,g.__name__=\"NumericInput\",u.prototype.default_view=v,u.define((({Number:e,String:t,Enum:l,Ref:i,Or:n,Nullable:s})=>({value:[s(e),null],placeholder:[t,\"\"],mode:[l(\"int\",\"float\"),\"int\"],format:[s(n(t,i(a.TickFormatter))),null],low:[s(e),null],high:[s(e),null]})))},\n 479: function _(e,t,r,s,n){var a;s();const o=e(468),_=e(43);class p extends o.MarkupView{render(){super.render();const e=(0,_.pre)({style:{overflow:\"auto\"}},this.model.text);this.markup_el.appendChild(e)}}r.PreTextView=p,p.__name__=\"PreTextView\";class u extends o.Markup{constructor(e){super(e)}}r.PreText=u,a=u,u.__name__=\"PreText\",a.prototype.default_view=p},\n 480: function _(t,o,e,a,i){a();const n=t(1);var u;const s=t(452),c=t(43),_=(0,n.__importStar)(t(318));class r extends s.ButtonGroupView{change_active(t){this.model.active!==t&&(this.model.active=t)}_update_active(){const{active:t}=this.model;this._buttons.forEach(((o,e)=>{(0,c.classes)(o).toggle(_.active,t===e)}))}}e.RadioButtonGroupView=r,r.__name__=\"RadioButtonGroupView\";class l extends s.ButtonGroup{constructor(t){super(t)}}e.RadioButtonGroup=l,u=l,l.__name__=\"RadioButtonGroup\",u.prototype.default_view=r,u.define((({Int:t,Nullable:o})=>({active:[o(t),null]})))},\n 481: function _(e,n,i,t,a){t();const s=e(1);var l;const o=e(43),d=e(34),p=e(455),r=(0,s.__importStar)(e(449));class u extends p.InputGroupView{render(){super.render();const e=(0,o.div)({class:[r.input_group,this.model.inline?r.inline:null]});this.el.appendChild(e);const n=(0,d.uniqueId)(),{active:i,labels:t}=this.model;this._inputs=[];for(let a=0;athis.change_active(a))),this._inputs.push(s),this.model.disabled&&(s.disabled=!0),a==i&&(s.checked=!0);const l=(0,o.label)(s,(0,o.span)(t[a]));e.appendChild(l)}}change_active(e){this.model.active=e}}i.RadioGroupView=u,u.__name__=\"RadioGroupView\";class c extends p.InputGroup{constructor(e){super(e)}}i.RadioGroup=c,l=c,c.__name__=\"RadioGroup\",l.prototype.default_view=u,l.define((({Boolean:e,Int:n,String:i,Array:t,Nullable:a})=>({active:[a(n),null],labels:[t(i),[]],inline:[e,!1]})))},\n 482: function _(e,r,t,a,i){a();var n;const o=(0,e(1).__importStar)(e(153)),s=e(461),_=e(8);class d extends s.AbstractRangeSliderView{}t.RangeSliderView=d,d.__name__=\"RangeSliderView\";class c extends s.AbstractSlider{constructor(e){super(e),this.behaviour=\"drag\",this.connected=[!1,!0,!1]}_formatter(e,r){return(0,_.isString)(r)?o.format(e,r):r.compute(e)}}t.RangeSlider=c,n=c,c.__name__=\"RangeSlider\",n.prototype.default_view=d,n.override({format:\"0[.]00\"})},\n 483: function _(e,t,n,s,i){s();const l=e(1);var u;const a=e(43),o=e(8),p=e(13),_=e(448),r=(0,l.__importStar)(e(449));class c extends _.InputWidgetView{constructor(){super(...arguments),this._known_values=new Set}connect_signals(){super.connect_signals();const{value:e,options:t}=this.model.properties;this.on_change(e,(()=>{this._update_value()})),this.on_change(t,(()=>{(0,a.empty)(this.input_el),(0,a.append)(this.input_el,...this.options_el()),this._update_value()}))}options_el(){const{_known_values:e}=this;function t(t){return t.map((t=>{let n,s;return(0,o.isString)(t)?n=s=t:[n,s]=t,e.add(n),(0,a.option)({value:n},s)}))}e.clear();const{options:n}=this.model;return(0,o.isArray)(n)?t(n):(0,p.entries)(n).map((([e,n])=>(0,a.optgroup)({label:e},t(n))))}render(){super.render(),this.input_el=(0,a.select)({class:r.input,name:this.model.name,disabled:this.model.disabled},this.options_el()),this._update_value(),this.input_el.addEventListener(\"change\",(()=>this.change_input())),this.group_el.appendChild(this.input_el)}change_input(){const e=this.input_el.value;this.model.value=e,super.change_input()}_update_value(){const{value:e}=this.model;this._known_values.has(e)?this.input_el.value=e:this.input_el.removeAttribute(\"value\")}}n.SelectView=c,c.__name__=\"SelectView\";class h extends _.InputWidget{constructor(e){super(e)}}n.Select=h,u=h,h.__name__=\"Select\",u.prototype.default_view=c,u.define((({String:e,Array:t,Tuple:n,Dict:s,Or:i})=>{const l=t(i(e,n(e,e)));return{value:[e,\"\"],options:[i(l,s(l)),[]]}}))},\n 484: function _(e,t,r,i,a){i();var o;const s=(0,e(1).__importStar)(e(153)),_=e(461),n=e(8);class c extends _.AbstractSliderView{}r.SliderView=c,c.__name__=\"SliderView\";class d extends _.AbstractSlider{constructor(e){super(e),this.behaviour=\"tap\",this.connected=[!0,!1]}_formatter(e,t){return(0,n.isString)(t)?s.format(e,t):t.compute(e)}}r.Slider=d,o=d,d.__name__=\"Slider\",o.prototype.default_view=c,o.override({format:\"0[.]00\"})},\n 485: function _(e,t,i,n,s){var l;n();const o=e(478),r=e(43),{min:a,max:h,floor:_,abs:u}=Math;function d(e){return _(e)!==e?e.toFixed(16).replace(/0+$/,\"\").split(\".\")[1].length:0}class p extends o.NumericInputView{*buttons(){yield this.btn_up_el,yield this.btn_down_el}initialize(){super.initialize(),this._handles={interval:void 0,timeout:void 0},this._interval=200}connect_signals(){super.connect_signals();const e=this.model.properties;this.on_change(e.disabled,(()=>{for(const e of this.buttons())(0,r.toggle_attribute)(e,\"disabled\",this.model.disabled)}))}render(){super.render(),this.wrapper_el=(0,r.div)({class:\"bk-spin-wrapper\"}),this.group_el.replaceChild(this.wrapper_el,this.input_el),this.btn_up_el=(0,r.button)({class:\"bk-spin-btn bk-spin-btn-up\"}),this.btn_down_el=(0,r.button)({class:\"bk-spin-btn bk-spin-btn-down\"}),this.wrapper_el.appendChild(this.input_el),this.wrapper_el.appendChild(this.btn_up_el),this.wrapper_el.appendChild(this.btn_down_el);for(const e of this.buttons())(0,r.toggle_attribute)(e,\"disabled\",this.model.disabled),e.addEventListener(\"mousedown\",(e=>this._btn_mouse_down(e))),e.addEventListener(\"mouseup\",(()=>this._btn_mouse_up())),e.addEventListener(\"mouseleave\",(()=>this._btn_mouse_leave()));this.input_el.addEventListener(\"keydown\",(e=>this._input_key_down(e))),this.input_el.addEventListener(\"keyup\",(()=>this.model.value_throttled=this.model.value)),this.input_el.addEventListener(\"wheel\",(e=>this._input_mouse_wheel(e))),this.input_el.addEventListener(\"wheel\",function(e,t,i=!1){let n;return function(...s){const l=this,o=i&&void 0===n;void 0!==n&&clearTimeout(n),n=setTimeout((function(){n=void 0,i||e.apply(l,s)}),t),o&&e.apply(l,s)}}((()=>{this.model.value_throttled=this.model.value}),this.model.wheel_wait,!1))}get precision(){const{low:e,high:t,step:i}=this.model,n=d;return h(n(u(null!=e?e:0)),n(u(null!=t?t:0)),n(u(i)))}remove(){this._stop_incrementation(),super.remove()}_start_incrementation(e){clearInterval(this._handles.interval),this._counter=0;const{step:t}=this.model,i=e=>{if(this._counter+=1,this._counter%5==0){const t=Math.floor(this._counter/5);t<10?(clearInterval(this._handles.interval),this._handles.interval=setInterval((()=>i(e)),this._interval/(t+1))):t>=10&&t<=13&&(clearInterval(this._handles.interval),this._handles.interval=setInterval((()=>i(2*e)),this._interval/10))}this.increment(e)};this._handles.interval=setInterval((()=>i(e*t)),this._interval)}_stop_incrementation(){clearTimeout(this._handles.timeout),this._handles.timeout=void 0,clearInterval(this._handles.interval),this._handles.interval=void 0,this.model.value_throttled=this.model.value}_btn_mouse_down(e){e.preventDefault();const t=e.currentTarget===this.btn_up_el?1:-1;this.increment(t*this.model.step),this.input_el.focus(),this._handles.timeout=setTimeout((()=>this._start_incrementation(t)),this._interval)}_btn_mouse_up(){this._stop_incrementation()}_btn_mouse_leave(){this._stop_incrementation()}_input_mouse_wheel(e){if(document.activeElement===this.input_el){e.preventDefault();const t=e.deltaY>0?-1:1;this.increment(t*this.model.step)}}_input_key_down(e){switch(e.keyCode){case r.Keys.Up:return e.preventDefault(),this.increment(this.model.step);case r.Keys.Down:return e.preventDefault(),this.increment(-this.model.step);case r.Keys.PageUp:return e.preventDefault(),this.increment(this.model.page_step_multiplier*this.model.step);case r.Keys.PageDown:return e.preventDefault(),this.increment(-this.model.page_step_multiplier*this.model.step)}}adjust_to_precision(e){return this.bound_value(Number(e.toFixed(this.precision)))}increment(e){const{low:t,high:i}=this.model;null==this.model.value?e>0?this.model.value=null!=t?t:null!=i?a(0,i):0:e<0&&(this.model.value=null!=i?i:null!=t?h(t,0):0):this.model.value=this.adjust_to_precision(this.model.value+e)}change_input(){super.change_input(),this.model.value_throttled=this.model.value}}i.SpinnerView=p,p.__name__=\"SpinnerView\";class m extends o.NumericInput{constructor(e){super(e)}}i.Spinner=m,l=m,m.__name__=\"Spinner\",l.prototype.default_view=p,l.define((({Number:e,Nullable:t})=>({value_throttled:[t(e),null],step:[e,1],page_step_multiplier:[e,10],wheel_wait:[e,100]}))),l.override({mode:\"float\"})},\n 486: function _(e,t,s,n,i){n();const o=e(1);var r;const c=e(447),l=e(43),p=(0,o.__importStar)(e(449));class _ extends c.TextLikeInputView{connect_signals(){super.connect_signals(),this.connect(this.model.properties.rows.change,(()=>this.input_el.rows=this.model.rows)),this.connect(this.model.properties.cols.change,(()=>this.input_el.cols=this.model.cols))}_render_input(){this.input_el=(0,l.textarea)({class:p.input})}render(){super.render(),this.input_el.cols=this.model.cols,this.input_el.rows=this.model.rows}}s.TextAreaInputView=_,_.__name__=\"TextAreaInputView\";class a extends c.TextLikeInput{constructor(e){super(e)}}s.TextAreaInput=a,r=a,a.__name__=\"TextAreaInput\",r.prototype.default_view=_,r.define((({Int:e})=>({cols:[e,20],rows:[e,2]}))),r.override({max_length:500})},\n 487: function _(e,t,s,c,i){c();const o=e(1);var a;const n=e(441),l=e(43),_=(0,o.__importStar)(e(318));class r extends n.AbstractButtonView{connect_signals(){super.connect_signals(),this.connect(this.model.properties.active.change,(()=>this._update_active()))}render(){super.render(),this._update_active()}click(){this.model.active=!this.model.active,super.click()}_update_active(){(0,l.classes)(this.button_el).toggle(_.active,this.model.active)}}s.ToggleView=r,r.__name__=\"ToggleView\";class g extends n.AbstractButton{constructor(e){super(e)}}s.Toggle=g,a=g,g.__name__=\"Toggle\",a.prototype.default_view=r,a.define((({Boolean:e})=>({active:[e,!1]}))),a.override({label:\"Toggle\"})},\n }, 439, {\"models/widgets/main\":439,\"models/widgets/index\":440,\"models/widgets/abstract_button\":441,\"models/widgets/control\":442,\"models/widgets/widget\":512,\"models/widgets/abstract_icon\":444,\"models/widgets/autocomplete_input\":445,\"models/widgets/text_input\":446,\"models/widgets/text_like_input\":447,\"models/widgets/input_widget\":448,\"styles/widgets/inputs.css\":449,\"models/widgets/button\":450,\"models/widgets/checkbox_button_group\":451,\"models/widgets/button_group\":452,\"models/widgets/oriented_control\":453,\"models/widgets/checkbox_group\":454,\"models/widgets/input_group\":455,\"models/widgets/color_picker\":456,\"models/widgets/date_picker\":457,\"styles/widgets/flatpickr.css\":459,\"models/widgets/date_range_slider\":460,\"models/widgets/abstract_slider\":461,\"styles/widgets/sliders.css\":463,\"styles/widgets/nouislider.css\":464,\"models/widgets/date_slider\":465,\"models/widgets/datetime_range_slider\":466,\"models/widgets/div\":467,\"models/widgets/markup\":468,\"styles/clearfix.css\":469,\"models/widgets/dropdown\":470,\"models/widgets/file_input\":471,\"models/widgets/multiselect\":472,\"models/widgets/paragraph\":473,\"models/widgets/password_input\":474,\"models/widgets/multichoice\":475,\"styles/widgets/choices.css\":477,\"models/widgets/numeric_input\":478,\"models/widgets/pretext\":479,\"models/widgets/radio_button_group\":480,\"models/widgets/radio_group\":481,\"models/widgets/range_slider\":482,\"models/widgets/selectbox\":483,\"models/widgets/slider\":484,\"models/widgets/spinner\":485,\"models/widgets/textarea_input\":486,\"models/widgets/toggle\":487}, {});});\n\n /* END bokeh-widgets.min.js */\n },\n function(Bokeh) {\n /* BEGIN bokeh-tables.min.js */\n /*!\n * Copyright (c) 2012 - 2022, Anaconda, Inc., and Bokeh Contributors\n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n * \n * Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n * \n * Neither the name of Anaconda nor the names of any contributors\n * may be used to endorse or promote products derived from this software\n * without specific prior written permission.\n * \n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n * THE POSSIBILITY OF SUCH DAMAGE.\n */\n (function(root, factory) {\n factory(root[\"Bokeh\"], \"2.4.3\");\n })(this, function(Bokeh, version) {\n let define;\n return (function(modules, entry, aliases, externals) {\n const bokeh = typeof Bokeh !== \"undefined\" && (version != null ? Bokeh[version] : Bokeh);\n if (bokeh != null) {\n return bokeh.register_plugin(modules, entry, aliases);\n } else {\n throw new Error(\"Cannot find Bokeh \" + version + \". You have to load it prior to loading plugins.\");\n }\n })\n ({\n 488: function _(t,e,o,r,s){r();const _=(0,t(1).__importStar)(t(489));o.Tables=_;(0,t(7).register_models)(_)},\n 489: function _(g,a,r,e,t){e();const o=g(1);(0,o.__exportStar)(g(490),r),(0,o.__exportStar)(g(493),r),t(\"DataTable\",g(496).DataTable),t(\"TableColumn\",g(514).TableColumn),t(\"TableWidget\",g(513).TableWidget);var n=g(516);t(\"AvgAggregator\",n.AvgAggregator),t(\"MinAggregator\",n.MinAggregator),t(\"MaxAggregator\",n.MaxAggregator),t(\"SumAggregator\",n.SumAggregator);var A=g(517);t(\"GroupingInfo\",A.GroupingInfo),t(\"DataCube\",A.DataCube)},\n 490: function _(e,t,i,s,a){s();const r=e(1);var l,n,u,d,o,p,_,c,h;const E=e(43),V=e(226),m=e(53),f=e(491),v=(0,r.__importStar)(e(492));class w extends V.DOMView{constructor(e){const{model:t,parent:i}=e.column;super(Object.assign({model:t,parent:i},e)),this.args=e,this.initialize(),this.render()}get emptyValue(){return null}initialize(){super.initialize(),this.inputEl=this._createInput(),this.defaultValue=null}async lazy_initialize(){throw new Error(\"unsupported\")}css_classes(){return super.css_classes().concat(v.cell_editor)}render(){super.render(),this.args.container.append(this.el),this.el.appendChild(this.inputEl),this.renderEditor(),this.disableNavigation()}renderEditor(){}disableNavigation(){this.inputEl.addEventListener(\"keydown\",(e=>{switch(e.keyCode){case E.Keys.Left:case E.Keys.Right:case E.Keys.Up:case E.Keys.Down:case E.Keys.PageUp:case E.Keys.PageDown:e.stopImmediatePropagation()}}))}destroy(){this.remove()}focus(){this.inputEl.focus()}show(){}hide(){}position(){}getValue(){return this.inputEl.value}setValue(e){this.inputEl.value=e}serializeValue(){return this.getValue()}isValueChanged(){return!(\"\"==this.getValue()&&null==this.defaultValue)&&this.getValue()!==this.defaultValue}applyValue(e,t){const i=this.args.grid.getData(),s=i.index.indexOf(e[f.DTINDEX_NAME]);i.setField(s,this.args.column.field,t)}loadValue(e){const t=e[this.args.column.field];this.defaultValue=null!=t?t:this.emptyValue,this.setValue(this.defaultValue)}validateValue(e){if(this.args.column.validator){const t=this.args.column.validator(e);if(!t.valid)return t}return{valid:!0,msg:null}}validate(){return this.validateValue(this.getValue())}}i.CellEditorView=w,w.__name__=\"CellEditorView\";class g extends m.Model{}i.CellEditor=g,g.__name__=\"CellEditor\";class x extends w{get emptyValue(){return\"\"}_createInput(){return(0,E.input)({type:\"text\"})}renderEditor(){this.inputEl.focus(),this.inputEl.select()}loadValue(e){super.loadValue(e),this.inputEl.defaultValue=this.defaultValue,this.inputEl.select()}}i.StringEditorView=x,x.__name__=\"StringEditorView\";class y extends g{}i.StringEditor=y,l=y,y.__name__=\"StringEditor\",l.prototype.default_view=x,l.define((({String:e,Array:t})=>({completions:[t(e),[]]})));class I extends w{_createInput(){return(0,E.textarea)()}renderEditor(){this.inputEl.focus(),this.inputEl.select()}}i.TextEditorView=I,I.__name__=\"TextEditorView\";class b extends g{}i.TextEditor=b,n=b,b.__name__=\"TextEditor\",n.prototype.default_view=I;class N extends w{_createInput(){return(0,E.select)()}renderEditor(){for(const e of this.model.options)this.inputEl.appendChild((0,E.option)({value:e},e));this.focus()}}i.SelectEditorView=N,N.__name__=\"SelectEditorView\";class C extends g{}i.SelectEditor=C,u=C,C.__name__=\"SelectEditor\",u.prototype.default_view=N,u.define((({String:e,Array:t})=>({options:[t(e),[]]})));class D extends w{_createInput(){return(0,E.input)({type:\"text\"})}}i.PercentEditorView=D,D.__name__=\"PercentEditorView\";class S extends g{}i.PercentEditor=S,d=S,S.__name__=\"PercentEditor\",d.prototype.default_view=D;class k extends w{_createInput(){return(0,E.input)({type:\"checkbox\"})}renderEditor(){this.focus()}loadValue(e){this.defaultValue=!!e[this.args.column.field],this.inputEl.checked=this.defaultValue}serializeValue(){return this.inputEl.checked}}i.CheckboxEditorView=k,k.__name__=\"CheckboxEditorView\";class z extends g{}i.CheckboxEditor=z,o=z,z.__name__=\"CheckboxEditor\",o.prototype.default_view=k;class P extends w{_createInput(){return(0,E.input)({type:\"text\"})}renderEditor(){this.inputEl.focus(),this.inputEl.select()}remove(){super.remove()}serializeValue(){var e;return null!==(e=parseInt(this.getValue(),10))&&void 0!==e?e:0}loadValue(e){super.loadValue(e),this.inputEl.defaultValue=this.defaultValue,this.inputEl.select()}validateValue(e){return isNaN(e)?{valid:!1,msg:\"Please enter a valid integer\"}:super.validateValue(e)}}i.IntEditorView=P,P.__name__=\"IntEditorView\";class T extends g{}i.IntEditor=T,p=T,T.__name__=\"IntEditor\",p.prototype.default_view=P,p.define((({Int:e})=>({step:[e,1]})));class K extends w{_createInput(){return(0,E.input)({type:\"text\"})}renderEditor(){this.inputEl.focus(),this.inputEl.select()}remove(){super.remove()}serializeValue(){var e;return null!==(e=parseFloat(this.getValue()))&&void 0!==e?e:0}loadValue(e){super.loadValue(e),this.inputEl.defaultValue=this.defaultValue,this.inputEl.select()}validateValue(e){return isNaN(e)?{valid:!1,msg:\"Please enter a valid number\"}:super.validateValue(e)}}i.NumberEditorView=K,K.__name__=\"NumberEditorView\";class A extends g{}i.NumberEditor=A,_=A,A.__name__=\"NumberEditor\",_.prototype.default_view=K,_.define((({Number:e})=>({step:[e,.01]})));class M extends w{_createInput(){return(0,E.input)({type:\"text\"})}}i.TimeEditorView=M,M.__name__=\"TimeEditorView\";class O extends g{}i.TimeEditor=O,c=O,O.__name__=\"TimeEditor\",c.prototype.default_view=M;class F extends w{_createInput(){return(0,E.input)({type:\"text\"})}get emptyValue(){return new Date}renderEditor(){this.inputEl.focus(),this.inputEl.select()}destroy(){super.destroy()}show(){super.show()}hide(){super.hide()}position(){return super.position()}getValue(){}setValue(e){}}i.DateEditorView=F,F.__name__=\"DateEditorView\";class L extends g{}i.DateEditor=L,h=L,L.__name__=\"DateEditor\",h.prototype.default_view=F},\n 491: function _(_,n,i,t,d){t(),i.DTINDEX_NAME=\"__bkdt_internal_index__\"},\n 492: function _(e,l,o,t,r){t(),o.root=\"bk-root\",o.data_table=\"bk-data-table\",o.cell_special_defaults=\"bk-cell-special-defaults\",o.cell_select=\"bk-cell-select\",o.cell_index=\"bk-cell-index\",o.header_index=\"bk-header-index\",o.cell_editor=\"bk-cell-editor\",o.cell_editor_completion=\"bk-cell-editor-completion\",o.default='.bk-root .bk-data-table{box-sizing:content-box;font-size:11px;}.bk-root .bk-data-table input[type=\"checkbox\"]{margin-left:4px;margin-right:4px;}.bk-root .bk-cell-special-defaults{border-right-color:silver;border-right-style:solid;background:#f5f5f5;}.bk-root .bk-cell-select{border-right-color:silver;border-right-style:solid;background:#f5f5f5;}.bk-root .slick-cell.bk-cell-index{border-right-color:silver;border-right-style:solid;background:#f5f5f5;text-align:right;background:#f0f0f0;color:#909090;}.bk-root .bk-header-index .slick-column-name{float:right;}.bk-root .slick-row.selected .bk-cell-index{background-color:transparent;}.bk-root .slick-row.odd{background:#f0f0f0;}.bk-root .slick-cell{padding-left:4px;padding-right:4px;border-right-color:transparent;border:0.25px solid transparent;}.bk-root .slick-cell .bk{line-height:inherit;}.bk-root .slick-cell.active{border-style:dashed;}.bk-root .slick-cell.selected{background-color:#F0F8FF;}.bk-root .slick-cell.editable{padding-left:0;padding-right:0;}.bk-root .bk-cell-editor{display:contents;}.bk-root .bk-cell-editor input,.bk-root .bk-cell-editor select{width:100%;height:100%;border:0;margin:0;padding:0;outline:0;background:transparent;vertical-align:baseline;}.bk-root .bk-cell-editor input{padding-left:4px;padding-right:4px;}.bk-root .bk-cell-editor-completion{font-size:11px;}'},\n 493: function _(t,e,r,n,o){n();const a=t(1);var s,i,l,c,u,m;const _=(0,a.__importDefault)(t(151)),d=(0,a.__importStar)(t(153)),f=t(494),g=t(43),F=t(20),h=t(8),p=t(34),S=t(22),x=t(53);class b extends x.Model{constructor(t){super(t)}doFormat(t,e,r,n,o){return null==r?\"\":`${r}`.replace(/&/g,\"&\").replace(//g,\">\")}}r.CellFormatter=b,b.__name__=\"CellFormatter\";class M extends b{constructor(t){super(t)}doFormat(t,e,r,n,o){const{font_style:a,text_align:s,text_color:i}=this,l=(0,g.div)(null==r?\"\":`${r}`);switch(a){case\"bold\":l.style.fontWeight=\"bold\";break;case\"italic\":l.style.fontStyle=\"italic\"}return null!=s&&(l.style.textAlign=s),null!=i&&(l.style.color=(0,S.color2css)(i)),l.outerHTML}}r.StringFormatter=M,s=M,M.__name__=\"StringFormatter\",s.define((({Color:t,Nullable:e,String:r})=>({font_style:[F.FontStyle,\"normal\"],text_align:[F.TextAlign,\"left\"],text_color:[e(t),null],nan_format:[r,\"-\"]})));class w extends M{constructor(t){super(t)}get scientific_limit_low(){return 10**this.power_limit_low}get scientific_limit_high(){return 10**this.power_limit_high}doFormat(t,e,r,n,o){const a=Math.abs(r)<=this.scientific_limit_low||Math.abs(r)>=this.scientific_limit_high;let s=this.precision;return s<1&&(s=1),r=null==r||isNaN(r)?this.nan_format:0==r?(0,p.to_fixed)(r,1):a?r.toExponential(s):(0,p.to_fixed)(r,s),super.doFormat(t,e,r,n,o)}}r.ScientificFormatter=w,i=w,w.__name__=\"ScientificFormatter\",i.define((({Number:t})=>({precision:[t,10],power_limit_high:[t,5],power_limit_low:[t,-3]})));class C extends M{constructor(t){super(t)}doFormat(t,e,r,n,o){const{format:a,language:s,nan_format:i}=this,l=(()=>{switch(this.rounding){case\"round\":case\"nearest\":return Math.round;case\"floor\":case\"rounddown\":return Math.floor;case\"ceil\":case\"roundup\":return Math.ceil}})();return r=null==r||isNaN(r)?i:d.format(r,a,s,l),super.doFormat(t,e,r,n,o)}}r.NumberFormatter=C,l=C,C.__name__=\"NumberFormatter\",l.define((({String:t})=>({format:[t,\"0,0\"],language:[t,\"en\"],rounding:[F.RoundingFunction,\"round\"]})));class y extends b{constructor(t){super(t)}doFormat(t,e,r,n,o){return r?(0,g.i)({class:this.icon}).outerHTML:\"\"}}r.BooleanFormatter=y,c=y,y.__name__=\"BooleanFormatter\",c.define((({String:t})=>({icon:[t,\"check\"]})));class N extends M{constructor(t){super(t)}getFormat(){switch(this.format){case\"ATOM\":case\"W3C\":case\"RFC-3339\":case\"ISO-8601\":return\"%Y-%m-%d\";case\"COOKIE\":return\"%a, %d %b %Y\";case\"RFC-850\":return\"%A, %d-%b-%y\";case\"RFC-1123\":case\"RFC-2822\":return\"%a, %e %b %Y\";case\"RSS\":case\"RFC-822\":case\"RFC-1036\":return\"%a, %e %b %y\";case\"TIMESTAMP\":return;default:return this.format}}doFormat(t,e,r,n,o){const{nan_format:a}=this;let s;return s=null==(r=(0,h.isString)(r)?parseInt(r,10):r)||isNaN(r)||-9223372036854776===r?a:(0,_.default)(r,this.getFormat()),super.doFormat(t,e,s,n,o)}}r.DateFormatter=N,u=N,N.__name__=\"DateFormatter\",u.define((({String:t})=>({format:[t,\"ISO-8601\"]})));class T extends b{constructor(t){super(t)}doFormat(t,e,r,n,o){const{template:a}=this;if(null==r)return\"\";return f._.template(a)(Object.assign(Object.assign({},o),{value:r}))}}r.HTMLTemplateFormatter=T,m=T,T.__name__=\"HTMLTemplateFormatter\",m.define((({String:t})=>({template:[t,\"<%= value %>\"]})))},\n 494: function _(e,n,t,f,i){var o=e(495),d=o.template;function r(e,n,t){return d(e,n,t)}r._=o,n.exports=r,\"function\"==typeof define&&define.amd?define((function(){return r})):\"undefined\"==typeof window&&\"undefined\"==typeof navigator||(window.UnderscoreTemplate=r)},\n 495: function _(r,e,n,t,a){\n // (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n // Underscore may be freely distributed under the MIT license.\n var u={},c=Array.prototype,o=Object.prototype,l=c.slice,i=o.toString,f=o.hasOwnProperty,s=c.forEach,p=Object.keys,_=Array.isArray,h=function(){},v=h.each=h.forEach=function(r,e,n){if(null!=r)if(s&&r.forEach===s)r.forEach(e,n);else if(r.length===+r.length){for(var t=0,a=r.length;t\":\">\",'\"':\""\",\"'\":\"'\"}},y={escape:new RegExp(\"[\"+h.keys(g.escape).join(\"\")+\"]\",\"g\")};h.each([\"escape\"],(function(r){h[r]=function(e){return null==e?\"\":(\"\"+e).replace(y[r],(function(e){return g[r][e]}))}})),h.templateSettings={evaluate:/<%([\\s\\S]+?)%>/g,interpolate:/<%=([\\s\\S]+?)%>/g,escape:/<%-([\\s\\S]+?)%>/g};var j=/(.)^/,b={\"'\":\"'\",\"\\\\\":\"\\\\\",\"\\r\":\"r\",\"\\n\":\"n\",\"\\t\":\"t\",\"\\u2028\":\"u2028\",\"\\u2029\":\"u2029\"},w=/\\\\|'|\\r|\\n|\\t|\\u2028|\\u2029/g;h.template=function(r,e,n){var t;n=h.defaults({},n,h.templateSettings);var a=new RegExp([(n.escape||j).source,(n.interpolate||j).source,(n.evaluate||j).source].join(\"|\")+\"|$\",\"g\"),u=0,c=\"__p+='\";r.replace(a,(function(e,n,t,a,o){return c+=r.slice(u,o).replace(w,(function(r){return\"\\\\\"+b[r]})),n&&(c+=\"'+\\n((__t=(\"+n+\"))==null?'':_.escape(__t))+\\n'\"),t&&(c+=\"'+\\n((__t=(\"+t+\"))==null?'':__t)+\\n'\"),a&&(c+=\"';\\n\"+a+\"\\n__p+='\"),u=o+e.length,e})),c+=\"';\\n\",n.variable||(c=\"with(obj||{}){\\n\"+c+\"}\\n\"),c=\"var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\\n\"+c+\"return __p;\\n\";try{t=new Function(n.variable||\"obj\",\"_\",c)}catch(r){throw r.source=c,r}if(e)return t(e,h);var o=function(r){return t.call(this,r,h)};return o.source=\"function(\"+(n.variable||\"obj\")+\"){\\n\"+c+\"}\",o},e.exports=h},\n 496: function _(e,t,i,s,o){s();const n=e(1);var l;const r=e(497),d=e(501),a=e(502),h=e(503),u=e(34),c=e(8),_=e(9),m=e(13),g=e(19),p=e(512),f=e(491),b=e(513),w=e(514),x=(0,n.__importStar)(e(492)),C=x,v=(0,n.__importDefault)(e(515));i.AutosizeModes={fit_columns:\"FCV\",fit_viewport:\"FVC\",force_fit:\"LFF\",none:\"NOA\"};let z=!1;class A{constructor(e,t){this.init(e,t)}init(e,t){if(f.DTINDEX_NAME in e.data)throw new Error(`special name ${f.DTINDEX_NAME} cannot be used as a data table column`);this.source=e,this.view=t,this.index=[...this.view.indices]}getLength(){return this.index.length}getItem(e){const t={};for(const i of(0,m.keys)(this.source.data))t[i]=this.source.data[i][this.index[e]];return t[f.DTINDEX_NAME]=this.index[e],t}getField(e,t){return t==f.DTINDEX_NAME?this.index[e]:this.source.data[t][this.index[e]]}setField(e,t,i){const s=this.index[e];this.source.patch({[t]:[[s,i]]})}getRecords(){return(0,_.range)(0,this.getLength()).map((e=>this.getItem(e)))}getItems(){return this.getRecords()}slice(e,t,i){return e=null!=e?e:0,t=null!=t?t:this.getLength(),i=null!=i?i:1,(0,_.range)(e,t,i).map((e=>this.getItem(e)))}sort(e){let t=e.map((e=>[e.sortCol.field,e.sortAsc?1:-1]));0==t.length&&(t=[[f.DTINDEX_NAME,1]]);const i=this.getRecords(),s=this.index.slice();this.index.sort(((e,o)=>{for(const[n,l]of t){const t=i[s.indexOf(e)][n],r=i[s.indexOf(o)][n];if(t!==r)return(0,c.isNumber)(t)&&(0,c.isNumber)(r)?l*(t-r||+isNaN(t)-+isNaN(r)):`${t}`>`${r}`?l:-l}return 0}))}}i.TableDataProvider=A,A.__name__=\"TableDataProvider\";class M extends p.WidgetView{constructor(){super(...arguments),this._in_selection_update=!1,this._width=null}connect_signals(){super.connect_signals(),this.connect(this.model.change,(()=>this.render())),this.connect(this.model.source.streaming,(()=>this.updateGrid())),this.connect(this.model.source.patching,(()=>this.updateGrid())),this.connect(this.model.source.change,(()=>this.updateGrid())),this.connect(this.model.source.properties.data.change,(()=>this.updateGrid())),this.connect(this.model.source.selected.change,(()=>this.updateSelection())),this.connect(this.model.source.selected.properties.indices.change,(()=>this.updateSelection()));for(const e of this.model.columns)this.connect(e.change,(()=>{this.invalidate_layout(),this.render()}))}remove(){var e;null===(e=this.grid)||void 0===e||e.destroy(),super.remove()}styles(){return[...super.styles(),v.default,x.default]}update_position(){super.update_position(),this.grid.resizeCanvas()}after_layout(){super.after_layout(),this.updateLayout(!0,!1)}box_sizing(){const e=super.box_sizing();return\"fit_viewport\"===this.model.autosize_mode&&null!=this._width&&(e.width=this._width),e}updateLayout(e,t){const s=this.autosize;s===i.AutosizeModes.fit_columns||s===i.AutosizeModes.force_fit?(e||this.grid.resizeCanvas(),this.grid.autosizeColumns()):e&&t&&s===i.AutosizeModes.fit_viewport&&this.invalidate_layout()}updateGrid(){if(this.model.view.compute_indices(),this.data.init(this.model.source,this.model.view),this.model.sortable){const e=this.grid.getColumns(),t=this.grid.getSortColumns().map((t=>({sortCol:{field:e[this.grid.getColumnIndex(t.columnId)].field},sortAsc:t.sortAsc})));this.data.sort(t)}this.grid.invalidate(),this.updateLayout(!0,!0)}updateSelection(){if(this._in_selection_update)return;const{selected:e}=this.model.source,t=e.indices.map((e=>this.data.index.indexOf(e))).sort();this._in_selection_update=!0,this.grid.setSelectedRows(t),this._in_selection_update=!1;const i=this.grid.getViewport(),s=this.model.get_scroll_index(i,t);null!=s&&this.grid.scrollRowToTop(s)}newIndexColumn(){return{id:(0,u.uniqueId)(),name:this.model.index_header,field:f.DTINDEX_NAME,width:this.model.index_width,behavior:\"select\",cannotTriggerInsert:!0,resizable:!1,selectable:!1,sortable:!0,cssClass:C.cell_index,headerCssClass:C.header_index}}css_classes(){return super.css_classes().concat(C.data_table)}get autosize(){let e;return e=!0===this.model.fit_columns?i.AutosizeModes.force_fit:!1===this.model.fit_columns?i.AutosizeModes.none:i.AutosizeModes[this.model.autosize_mode],e}render(){var e;const t=this.model.columns.filter((e=>e.visible)).map((e=>Object.assign(Object.assign({},e.toColumn()),{parent:this})));let s=null;if(\"checkbox\"==this.model.selectable&&(s=new d.CheckboxSelectColumn({cssClass:C.cell_select}),t.unshift(s.getColumnDefinition())),null!=this.model.index_position){const e=this.model.index_position,i=this.newIndexColumn();-1==e?t.push(i):e<-1?t.splice(e+1,0,i):t.splice(e,0,i)}let{reorderable:o}=this.model;!o||\"undefined\"!=typeof $&&null!=$.fn&&null!=$.fn.sortable||(z||(g.logger.warn(\"jquery-ui is required to enable DataTable.reorderable\"),z=!0),o=!1);let n=-1,l=!1;const{frozen_rows:u,frozen_columns:_}=this.model,m=null==_?-1:_-1;null!=u&&(l=u<0,n=Math.abs(u));const p={enableCellNavigation:!1!==this.model.selectable,enableColumnReorder:o,autosizeColsMode:this.autosize,multiColumnSort:this.model.sortable,editable:this.model.editable,autoEdit:this.model.auto_edit,autoHeight:!1,rowHeight:this.model.row_height,frozenColumn:m,frozenRow:n,frozenBottom:l},f=null!=this.grid;if(this.data=new A(this.model.source,this.model.view),this.grid=new h.Grid(this.el,this.data,t,p),this.autosize==i.AutosizeModes.fit_viewport){this.grid.autosizeColumns();let i=0;for(const s of t)i+=null!==(e=s.width)&&void 0!==e?e:0;this._width=Math.ceil(i)}if(this.grid.onSort.subscribe(((e,t)=>{if(!this.model.sortable)return;const i=t.sortCols;null!=i&&(this.data.sort(i),this.grid.invalidate(),this.updateSelection(),this.grid.render(),this.model.header_row||this._hide_header(),this.model.update_sort_columns(i))})),!1!==this.model.selectable){this.grid.setSelectionModel(new r.RowSelectionModel({selectActiveRow:null==s})),null!=s&&this.grid.registerPlugin(s);const e={dataItemColumnValueExtractor(e,t){let i=e[t.field];return(0,c.isString)(i)&&(i=i.replace(/\\n/g,\"\\\\n\")),i},includeHeaderWhenCopying:!1};this.grid.registerPlugin(new a.CellExternalCopyManager(e)),this.grid.onSelectedRowsChanged.subscribe(((e,t)=>{this._in_selection_update||(this.model.source.selected.indices=t.rows.map((e=>this.data.index[e])))})),this.updateSelection(),this.model.header_row||this._hide_header()}f&&this.updateLayout(f,!1)}_hide_header(){for(const e of this.el.querySelectorAll(\".slick-header-columns\"))e.style.height=\"0px\";this.grid.resizeCanvas()}}i.DataTableView=M,M.__name__=\"DataTableView\";class D extends b.TableWidget{constructor(e){super(e),this._sort_columns=[]}get sort_columns(){return this._sort_columns}update_sort_columns(e){this._sort_columns=e.map((({sortCol:e,sortAsc:t})=>({field:e.field,sortAsc:t})))}get_scroll_index(e,t){return this.scroll_to_selection&&0!=t.length?(0,_.some)(t,(t=>e.top<=t&&t<=e.bottom))?null:Math.max(0,Math.min(...t)-1):null}}i.DataTable=D,l=D,D.__name__=\"DataTable\",l.prototype.default_view=M,l.define((({Array:e,Boolean:t,Int:i,Ref:s,String:o,Enum:n,Or:l,Nullable:r})=>({autosize_mode:[n(\"fit_columns\",\"fit_viewport\",\"none\",\"force_fit\"),\"force_fit\"],auto_edit:[t,!1],columns:[e(s(w.TableColumn)),[]],fit_columns:[r(t),null],frozen_columns:[r(i),null],frozen_rows:[r(i),null],sortable:[t,!0],reorderable:[t,!0],editable:[t,!1],selectable:[l(t,n(\"checkbox\")),!0],index_position:[r(i),0],index_header:[o,\"#\"],index_width:[i,40],scroll_to_selection:[t,!0],header_row:[t,!0],row_height:[i,25]}))),l.override({width:600,height:400})},\n 497: function _(e,t,n,o,r){var l=e(498),i=e(500);t.exports={RowSelectionModel:function(e){var t,n,o,r=[],c=this,u=new i.EventHandler,s={selectActiveRow:!0};function a(e){return function(){n||(n=!0,e.apply(this,arguments),n=!1)}}function f(e){for(var t=[],n=0;n=0&&r0&&t-1 in e)}w.fn=w.prototype={jquery:b,constructor:w,length:0,toArray:function(){return i.call(this)},get:function(e){return null==e?i.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=w.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return w.each(this,e)},map:function(e){return this.pushStack(w.map(this,(function(t,n){return e.call(t,n,t)})))},slice:function(){return this.pushStack(i.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(w.grep(this,(function(e,t){return(t+1)%2})))},odd:function(){return this.pushStack(w.grep(this,(function(e,t){return t%2})))},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n+~]|[\\\\x20\\\\t\\\\r\\\\n\\\\f])[\\\\x20\\\\t\\\\r\\\\n\\\\f]*\"),U=new RegExp(M+\"|>\"),X=new RegExp(F),V=new RegExp(\"^\"+I+\"$\"),G={ID:new RegExp(\"^#(\"+I+\")\"),CLASS:new RegExp(\"^\\\\.(\"+I+\")\"),TAG:new RegExp(\"^(\"+I+\"|[*])\"),ATTR:new RegExp(\"^\"+W),PSEUDO:new RegExp(\"^\"+F),CHILD:new RegExp(\"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\([\\\\x20\\\\t\\\\r\\\\n\\\\f]*(even|odd|(([+-]|)(\\\\d*)n|)[\\\\x20\\\\t\\\\r\\\\n\\\\f]*(?:([+-]|)[\\\\x20\\\\t\\\\r\\\\n\\\\f]*(\\\\d+)|))[\\\\x20\\\\t\\\\r\\\\n\\\\f]*\\\\)|)\",\"i\"),bool:new RegExp(\"^(?:\"+R+\")$\",\"i\"),needsContext:new RegExp(\"^[\\\\x20\\\\t\\\\r\\\\n\\\\f]*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\([\\\\x20\\\\t\\\\r\\\\n\\\\f]*((?:-\\\\d)?\\\\d*)[\\\\x20\\\\t\\\\r\\\\n\\\\f]*\\\\)|)(?=[^-]|$)\",\"i\")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\\d$/i,K=/^[^{]+\\{\\s*\\[native \\w/,Z=/^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,ee=/[+~]/,te=new RegExp(\"\\\\\\\\[\\\\da-fA-F]{1,6}[\\\\x20\\\\t\\\\r\\\\n\\\\f]?|\\\\\\\\([^\\\\r\\\\n\\\\f])\",\"g\"),ne=function(e,t){var n=\"0x\"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\\0-\\x1f\\x7f]|^-?\\d)|^-$|[^\\0-\\x1f\\x7f-\\uFFFF\\w-]/g,ie=function(e,t){return t?\"\\0\"===e?\"\\ufffd\":e.slice(0,-1)+\"\\\\\"+e.charCodeAt(e.length-1).toString(16)+\" \":\"\\\\\"+e},oe=function(){p()},ae=be((function(e){return!0===e.disabled&&\"fieldset\"===e.nodeName.toLowerCase()}),{dir:\"parentNode\",next:\"legend\"});try{H.apply(D=O.call(w.childNodes),w.childNodes),D[w.childNodes.length].nodeType}catch(e){H={apply:D.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){for(var n=e.length,r=0;e[n++]=t[r++];);e.length=n-1}}}function se(e,t,r,i){var o,s,l,c,f,h,y,m=t&&t.ownerDocument,w=t?t.nodeType:9;if(r=r||[],\"string\"!=typeof e||!e||1!==w&&9!==w&&11!==w)return r;if(!i&&(p(t),t=t||d,g)){if(11!==w&&(f=Z.exec(e)))if(o=f[1]){if(9===w){if(!(l=t.getElementById(o)))return r;if(l.id===o)return r.push(l),r}else if(m&&(l=m.getElementById(o))&&x(t,l)&&l.id===o)return r.push(l),r}else{if(f[2])return H.apply(r,t.getElementsByTagName(e)),r;if((o=f[3])&&n.getElementsByClassName&&t.getElementsByClassName)return H.apply(r,t.getElementsByClassName(o)),r}if(n.qsa&&!A[e+\" \"]&&(!v||!v.test(e))&&(1!==w||\"object\"!==t.nodeName.toLowerCase())){if(y=e,m=t,1===w&&(U.test(e)||z.test(e))){for((m=ee.test(e)&&ye(t.parentNode)||t)===t&&n.scope||((c=t.getAttribute(\"id\"))?c=c.replace(re,ie):t.setAttribute(\"id\",c=b)),s=(h=a(e)).length;s--;)h[s]=(c?\"#\"+c:\":scope\")+\" \"+xe(h[s]);y=h.join(\",\")}try{return H.apply(r,m.querySelectorAll(y)),r}catch(t){A(e,!0)}finally{c===b&&t.removeAttribute(\"id\")}}}return u(e.replace($,\"$1\"),t,r,i)}function ue(){var e=[];return function t(n,i){return e.push(n+\" \")>r.cacheLength&&delete t[e.shift()],t[n+\" \"]=i}}function le(e){return e[b]=!0,e}function ce(e){var t=d.createElement(\"fieldset\");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){for(var n=e.split(\"|\"),i=n.length;i--;)r.attrHandle[n[i]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function de(e){return function(t){return\"input\"===t.nodeName.toLowerCase()&&t.type===e}}function he(e){return function(t){var n=t.nodeName.toLowerCase();return(\"input\"===n||\"button\"===n)&&t.type===e}}function ge(e){return function(t){return\"form\"in t?t.parentNode&&!1===t.disabled?\"label\"in t?\"label\"in t.parentNode?t.parentNode.disabled===e:t.disabled===e:t.isDisabled===e||t.isDisabled!==!e&&ae(t)===e:t.disabled===e:\"label\"in t&&t.disabled===e}}function ve(e){return le((function(t){return t=+t,le((function(n,r){for(var i,o=e([],n.length,t),a=o.length;a--;)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))}))}))}function ye(e){return e&&void 0!==e.getElementsByTagName&&e}for(t in n=se.support={},o=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||\"HTML\")},p=se.setDocument=function(e){var t,i,a=e?e.ownerDocument||e:w;return a!=d&&9===a.nodeType&&a.documentElement?(h=(d=a).documentElement,g=!o(d),w!=d&&(i=d.defaultView)&&i.top!==i&&(i.addEventListener?i.addEventListener(\"unload\",oe,!1):i.attachEvent&&i.attachEvent(\"onunload\",oe)),n.scope=ce((function(e){return h.appendChild(e).appendChild(d.createElement(\"div\")),void 0!==e.querySelectorAll&&!e.querySelectorAll(\":scope fieldset div\").length})),n.attributes=ce((function(e){return e.className=\"i\",!e.getAttribute(\"className\")})),n.getElementsByTagName=ce((function(e){return e.appendChild(d.createComment(\"\")),!e.getElementsByTagName(\"*\").length})),n.getElementsByClassName=K.test(d.getElementsByClassName),n.getById=ce((function(e){return h.appendChild(e).id=b,!d.getElementsByName||!d.getElementsByName(b).length})),n.getById?(r.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute(\"id\")===t}},r.find.ID=function(e,t){if(void 0!==t.getElementById&&g){var n=t.getElementById(e);return n?[n]:[]}}):(r.filter.ID=function(e){var t=e.replace(te,ne);return function(e){var n=void 0!==e.getAttributeNode&&e.getAttributeNode(\"id\");return n&&n.value===t}},r.find.ID=function(e,t){if(void 0!==t.getElementById&&g){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode(\"id\"))&&n.value===e)return[o];for(i=t.getElementsByName(e),r=0;o=i[r++];)if((n=o.getAttributeNode(\"id\"))&&n.value===e)return[o]}return[]}}),r.find.TAG=n.getElementsByTagName?function(e,t){return void 0!==t.getElementsByTagName?t.getElementsByTagName(e):n.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if(\"*\"===e){for(;n=o[i++];)1===n.nodeType&&r.push(n);return r}return o},r.find.CLASS=n.getElementsByClassName&&function(e,t){if(void 0!==t.getElementsByClassName&&g)return t.getElementsByClassName(e)},y=[],v=[],(n.qsa=K.test(d.querySelectorAll))&&(ce((function(e){var t;h.appendChild(e).innerHTML=\"\",e.querySelectorAll(\"[msallowcapture^='']\").length&&v.push(\"[*^$]=[\\\\x20\\\\t\\\\r\\\\n\\\\f]*(?:''|\\\"\\\")\"),e.querySelectorAll(\"[selected]\").length||v.push(\"\\\\[[\\\\x20\\\\t\\\\r\\\\n\\\\f]*(?:value|\"+R+\")\"),e.querySelectorAll(\"[id~=\"+b+\"-]\").length||v.push(\"~=\"),(t=d.createElement(\"input\")).setAttribute(\"name\",\"\"),e.appendChild(t),e.querySelectorAll(\"[name='']\").length||v.push(\"\\\\[[\\\\x20\\\\t\\\\r\\\\n\\\\f]*name[\\\\x20\\\\t\\\\r\\\\n\\\\f]*=[\\\\x20\\\\t\\\\r\\\\n\\\\f]*(?:''|\\\"\\\")\"),e.querySelectorAll(\":checked\").length||v.push(\":checked\"),e.querySelectorAll(\"a#\"+b+\"+*\").length||v.push(\".#.+[+~]\"),e.querySelectorAll(\"\\\\\\f\"),v.push(\"[\\\\r\\\\n\\\\f]\")})),ce((function(e){e.innerHTML=\"\";var t=d.createElement(\"input\");t.setAttribute(\"type\",\"hidden\"),e.appendChild(t).setAttribute(\"name\",\"D\"),e.querySelectorAll(\"[name=d]\").length&&v.push(\"name[\\\\x20\\\\t\\\\r\\\\n\\\\f]*[*^$|!~]?=\"),2!==e.querySelectorAll(\":enabled\").length&&v.push(\":enabled\",\":disabled\"),h.appendChild(e).disabled=!0,2!==e.querySelectorAll(\":disabled\").length&&v.push(\":enabled\",\":disabled\"),e.querySelectorAll(\"*,:x\"),v.push(\",.*:\")}))),(n.matchesSelector=K.test(m=h.matches||h.webkitMatchesSelector||h.mozMatchesSelector||h.oMatchesSelector||h.msMatchesSelector))&&ce((function(e){n.disconnectedMatch=m.call(e,\"*\"),m.call(e,\"[s!='']:x\"),y.push(\"!=\",F)})),v=v.length&&new RegExp(v.join(\"|\")),y=y.length&&new RegExp(y.join(\"|\")),t=K.test(h.compareDocumentPosition),x=t||K.test(h.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},N=t?function(e,t){if(e===t)return f=!0,0;var r=!e.compareDocumentPosition-!t.compareDocumentPosition;return r||(1&(r=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!n.sortDetached&&t.compareDocumentPosition(e)===r?e==d||e.ownerDocument==w&&x(w,e)?-1:t==d||t.ownerDocument==w&&x(w,t)?1:c?P(c,e)-P(c,t):0:4&r?-1:1)}:function(e,t){if(e===t)return f=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==d?-1:t==d?1:i?-1:o?1:c?P(c,e)-P(c,t):0;if(i===o)return pe(e,t);for(n=e;n=n.parentNode;)a.unshift(n);for(n=t;n=n.parentNode;)s.unshift(n);for(;a[r]===s[r];)r++;return r?pe(a[r],s[r]):a[r]==w?-1:s[r]==w?1:0},d):d},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(p(e),n.matchesSelector&&g&&!A[t+\" \"]&&(!y||!y.test(t))&&(!v||!v.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(e){A(t,!0)}return se(t,d,null,[e]).length>0},se.contains=function(e,t){return(e.ownerDocument||e)!=d&&p(e),x(e,t)},se.attr=function(e,t){(e.ownerDocument||e)!=d&&p(e);var i=r.attrHandle[t.toLowerCase()],o=i&&j.call(r.attrHandle,t.toLowerCase())?i(e,t,!g):void 0;return void 0!==o?o:n.attributes||!g?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null},se.escape=function(e){return(e+\"\").replace(re,ie)},se.error=function(e){throw new Error(\"Syntax error, unrecognized expression: \"+e)},se.uniqueSort=function(e){var t,r=[],i=0,o=0;if(f=!n.detectDuplicates,c=!n.sortStable&&e.slice(0),e.sort(N),f){for(;t=e[o++];)t===e[o]&&(i=r.push(o));for(;i--;)e.splice(r[i],1)}return c=null,e},i=se.getText=function(e){var t,n=\"\",r=0,o=e.nodeType;if(o){if(1===o||9===o||11===o){if(\"string\"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=i(e)}else if(3===o||4===o)return e.nodeValue}else for(;t=e[r++];)n+=i(t);return n},r=se.selectors={cacheLength:50,createPseudo:le,match:G,attrHandle:{},find:{},relative:{\">\":{dir:\"parentNode\",first:!0},\" \":{dir:\"parentNode\"},\"+\":{dir:\"previousSibling\",first:!0},\"~\":{dir:\"previousSibling\"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||\"\").replace(te,ne),\"~=\"===e[2]&&(e[3]=\" \"+e[3]+\" \"),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),\"nth\"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*(\"even\"===e[3]||\"odd\"===e[3])),e[5]=+(e[7]+e[8]||\"odd\"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||\"\":n&&X.test(n)&&(t=a(n,!0))&&(t=n.indexOf(\")\",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return\"*\"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=E[e+\" \"];return t||(t=new RegExp(\"(^|[\\\\x20\\\\t\\\\r\\\\n\\\\f])\"+e+\"(\"+M+\"|$)\"))&&E(e,(function(e){return t.test(\"string\"==typeof e.className&&e.className||void 0!==e.getAttribute&&e.getAttribute(\"class\")||\"\")}))},ATTR:function(e,t,n){return function(r){var i=se.attr(r,e);return null==i?\"!=\"===t:!t||(i+=\"\",\"=\"===t?i===n:\"!=\"===t?i!==n:\"^=\"===t?n&&0===i.indexOf(n):\"*=\"===t?n&&i.indexOf(n)>-1:\"$=\"===t?n&&i.slice(-n.length)===n:\"~=\"===t?(\" \"+i.replace(B,\" \")+\" \").indexOf(n)>-1:\"|=\"===t&&(i===n||i.slice(0,n.length+1)===n+\"-\"))}},CHILD:function(e,t,n,r,i){var o=\"nth\"!==e.slice(0,3),a=\"last\"!==e.slice(-4),s=\"of-type\"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,p,d,h,g=o!==a?\"nextSibling\":\"previousSibling\",v=t.parentNode,y=s&&t.nodeName.toLowerCase(),m=!u&&!s,x=!1;if(v){if(o){for(;g;){for(p=t;p=p[g];)if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g=\"only\"===e&&!h&&\"nextSibling\"}return!0}if(h=[a?v.firstChild:v.lastChild],a&&m){for(x=(d=(l=(c=(f=(p=v)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1])&&l[2],p=d&&v.childNodes[d];p=++d&&p&&p[g]||(x=d=0)||h.pop();)if(1===p.nodeType&&++x&&p===t){c[e]=[T,d,x];break}}else if(m&&(x=d=(l=(c=(f=(p=t)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1]),!1===x)for(;(p=++d&&p&&p[g]||(x=d=0)||h.pop())&&((s?p.nodeName.toLowerCase()!==y:1!==p.nodeType)||!++x||(m&&((c=(f=p[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]=[T,x]),p!==t)););return(x-=i)===r||x%r==0&&x/r>=0}}},PSEUDO:function(e,t){var n,i=r.pseudos[e]||r.setFilters[e.toLowerCase()]||se.error(\"unsupported pseudo: \"+e);return i[b]?i(t):i.length>1?(n=[e,e,\"\",t],r.setFilters.hasOwnProperty(e.toLowerCase())?le((function(e,n){for(var r,o=i(e,t),a=o.length;a--;)e[r=P(e,o[a])]=!(n[r]=o[a])})):function(e){return i(e,0,n)}):i}},pseudos:{not:le((function(e){var t=[],n=[],r=s(e.replace($,\"$1\"));return r[b]?le((function(e,t,n,i){for(var o,a=r(e,null,i,[]),s=e.length;s--;)(o=a[s])&&(e[s]=!(t[s]=o))})):function(e,i,o){return t[0]=e,r(t,null,o,n),t[0]=null,!n.pop()}})),has:le((function(e){return function(t){return se(e,t).length>0}})),contains:le((function(e){return e=e.replace(te,ne),function(t){return(t.textContent||i(t)).indexOf(e)>-1}})),lang:le((function(e){return V.test(e||\"\")||se.error(\"unsupported lang: \"+e),e=e.replace(te,ne).toLowerCase(),function(t){var n;do{if(n=g?t.lang:t.getAttribute(\"xml:lang\")||t.getAttribute(\"lang\"))return(n=n.toLowerCase())===e||0===n.indexOf(e+\"-\")}while((t=t.parentNode)&&1===t.nodeType);return!1}})),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===h},focus:function(e){return e===d.activeElement&&(!d.hasFocus||d.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:ge(!1),disabled:ge(!0),checked:function(e){var t=e.nodeName.toLowerCase();return\"input\"===t&&!!e.checked||\"option\"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!r.pseudos.empty(e)},header:function(e){return J.test(e.nodeName)},input:function(e){return Q.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return\"input\"===t&&\"button\"===e.type||\"button\"===t},text:function(e){var t;return\"input\"===e.nodeName.toLowerCase()&&\"text\"===e.type&&(null==(t=e.getAttribute(\"type\"))||\"text\"===t.toLowerCase())},first:ve((function(){return[0]})),last:ve((function(e,t){return[t-1]})),eq:ve((function(e,t,n){return[n<0?n+t:n]})),even:ve((function(e,t){for(var n=0;nt?t:n;--r>=0;)e.push(r);return e})),gt:ve((function(e,t,n){for(var r=n<0?n+t:n;++r1?function(t,n,r){for(var i=e.length;i--;)if(!e[i](t,n,r))return!1;return!0}:e[0]}function Te(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s-1&&(o[l]=!(a[l]=f))}}else y=Te(y===a?y.splice(h,y.length):y),i?i(null,a,y,u):H.apply(a,y)}))}function Ee(e){for(var t,n,i,o=e.length,a=r.relative[e[0].type],s=a||r.relative[\" \"],u=a?1:0,c=be((function(e){return e===t}),s,!0),f=be((function(e){return P(t,e)>-1}),s,!0),p=[function(e,n,r){var i=!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):f(e,n,r));return t=null,i}];u1&&we(p),u>1&&xe(e.slice(0,u-1).concat({value:\" \"===e[u-2].type?\"*\":\"\"})).replace($,\"$1\"),n,u0,i=e.length>0,o=function(o,a,s,u,c){var f,h,v,y=0,m=\"0\",x=o&&[],b=[],w=l,C=o||i&&r.find.TAG(\"*\",c),E=T+=null==w?1:Math.random()||.1,S=C.length;for(c&&(l=a==d||a||c);m!==S&&null!=(f=C[m]);m++){if(i&&f){for(h=0,a||f.ownerDocument==d||(p(f),s=!g);v=e[h++];)if(v(f,a||d,s)){u.push(f);break}c&&(T=E)}n&&((f=!v&&f)&&y--,o&&x.push(f))}if(y+=m,n&&m!==y){for(h=0;v=t[h++];)v(x,b,a,s);if(o){if(y>0)for(;m--;)x[m]||b[m]||(b[m]=q.call(u));b=Te(b)}H.apply(u,b),c&&!o&&b.length>0&&y+t.length>1&&se.uniqueSort(u)}return c&&(T=E,l=w),x};return n?le(o):o}(o,i)),s.selector=e}return s},u=se.select=function(e,t,n,i){var o,u,l,c,f,p=\"function\"==typeof e&&e,d=!i&&a(e=p.selector||e);if(n=n||[],1===d.length){if((u=d[0]=d[0].slice(0)).length>2&&\"ID\"===(l=u[0]).type&&9===t.nodeType&&g&&r.relative[u[1].type]){if(!(t=(r.find.ID(l.matches[0].replace(te,ne),t)||[])[0]))return n;p&&(t=t.parentNode),e=e.slice(u.shift().value.length)}for(o=G.needsContext.test(e)?0:u.length;o--&&(l=u[o],!r.relative[c=l.type]);)if((f=r.find[c])&&(i=f(l.matches[0].replace(te,ne),ee.test(u[0].type)&&ye(t.parentNode)||t))){if(u.splice(o,1),!(e=i.length&&xe(u)))return H.apply(n,i),n;break}}return(p||s(e,d))(i,t,!g,n,!t||ee.test(e)&&ye(t.parentNode)||t),n},n.sortStable=b.split(\"\").sort(N).join(\"\")===b,n.detectDuplicates=!!f,p(),n.sortDetached=ce((function(e){return 1&e.compareDocumentPosition(d.createElement(\"fieldset\"))})),ce((function(e){return e.innerHTML=\"\",\"#\"===e.firstChild.getAttribute(\"href\")}))||fe(\"type|href|height|width\",(function(e,t,n){if(!n)return e.getAttribute(t,\"type\"===t.toLowerCase()?1:2)})),n.attributes&&ce((function(e){return e.innerHTML=\"\",e.firstChild.setAttribute(\"value\",\"\"),\"\"===e.firstChild.getAttribute(\"value\")}))||fe(\"value\",(function(e,t,n){if(!n&&\"input\"===e.nodeName.toLowerCase())return e.defaultValue})),ce((function(e){return null==e.getAttribute(\"disabled\")}))||fe(R,(function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null})),se}(e);w.find=C,w.expr=C.selectors,w.expr[\":\"]=w.expr.pseudos,w.uniqueSort=w.unique=C.uniqueSort,w.text=C.getText,w.isXMLDoc=C.isXML,w.contains=C.contains,w.escapeSelector=C.escape;var E=function(e,t,n){for(var r=[],i=void 0!==n;(e=e[t])&&9!==e.nodeType;)if(1===e.nodeType){if(i&&w(e).is(n))break;r.push(e)}return r},S=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},k=w.expr.match.needsContext;function A(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var N=/^<([a-z][^\\/\\0>:\\x20\\t\\r\\n\\f]*)[\\x20\\t\\r\\n\\f]*\\/?>(?:<\\/\\1>|)$/i;function j(e,t,n){return h(t)?w.grep(e,(function(e,r){return!!t.call(e,r,e)!==n})):t.nodeType?w.grep(e,(function(e){return e===t!==n})):\"string\"!=typeof t?w.grep(e,(function(e){return s.call(t,e)>-1!==n})):w.filter(t,e,n)}w.filter=function(e,t,n){var r=t[0];return n&&(e=\":not(\"+e+\")\"),1===t.length&&1===r.nodeType?w.find.matchesSelector(r,e)?[r]:[]:w.find.matches(e,w.grep(t,(function(e){return 1===e.nodeType})))},w.fn.extend({find:function(e){var t,n,r=this.length,i=this;if(\"string\"!=typeof e)return this.pushStack(w(e).filter((function(){for(t=0;t1?w.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,\"string\"==typeof e&&k.test(e)?w(e):e||[],!1).length}});var D,q=/^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]+))$/;(w.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,\"string\"==typeof e){if(!(r=\"<\"===e[0]&&\">\"===e[e.length-1]&&e.length>=3?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof w?t[0]:t,w.merge(this,w.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:v,!0)),N.test(r[1])&&w.isPlainObject(t))for(r in t)h(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=v.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):h(e)?void 0!==n.ready?n.ready(e):e(w):w.makeArray(e,this)}).prototype=w.fn,D=w(v);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){for(;(e=e[t])&&1!==e.nodeType;);return e}w.fn.extend({has:function(e){var t=w(e,this),n=t.length;return this.filter((function(){for(var e=0;e-1:1===n.nodeType&&w.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?w.uniqueSort(o):o)},index:function(e){return e?\"string\"==typeof e?s.call(w(e),this[0]):s.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(w.uniqueSort(w.merge(this.get(),w(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),w.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return E(e,\"parentNode\")},parentsUntil:function(e,t,n){return E(e,\"parentNode\",n)},next:function(e){return O(e,\"nextSibling\")},prev:function(e){return O(e,\"previousSibling\")},nextAll:function(e){return E(e,\"nextSibling\")},prevAll:function(e){return E(e,\"previousSibling\")},nextUntil:function(e,t,n){return E(e,\"nextSibling\",n)},prevUntil:function(e,t,n){return E(e,\"previousSibling\",n)},siblings:function(e){return S((e.parentNode||{}).firstChild,e)},children:function(e){return S(e.firstChild)},contents:function(e){return null!=e.contentDocument&&r(e.contentDocument)?e.contentDocument:(A(e,\"template\")&&(e=e.content||e),w.merge([],e.childNodes))}},(function(e,t){w.fn[e]=function(n,r){var i=w.map(this,t,n);return\"Until\"!==e.slice(-5)&&(r=n),r&&\"string\"==typeof r&&(i=w.filter(r,i)),this.length>1&&(H[e]||w.uniqueSort(i),L.test(e)&&i.reverse()),this.pushStack(i)}}));var P=/[^\\x20\\t\\r\\n\\f]+/g;function R(e){return e}function M(e){throw e}function I(e,t,n,r){var i;try{e&&h(i=e.promise)?i.call(e).done(t).fail(n):e&&h(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}w.Callbacks=function(e){e=\"string\"==typeof e?function(e){var t={};return w.each(e.match(P)||[],(function(e,n){t[n]=!0})),t}(e):w.extend({},e);var t,n,r,i,o=[],a=[],s=-1,u=function(){for(i=i||e.once,r=t=!0;a.length;s=-1)for(n=a.shift();++s-1;)o.splice(n,1),n<=s&&s--})),this},has:function(e){return e?w.inArray(e,o)>-1:o.length>0},empty:function(){return o&&(o=[]),this},disable:function(){return i=a=[],o=n=\"\",this},disabled:function(){return!o},lock:function(){return i=a=[],n||t||(o=n=\"\"),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=[e,(n=n||[]).slice?n.slice():n],a.push(n),t||u()),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!r}};return l},w.extend({Deferred:function(t){var n=[[\"notify\",\"progress\",w.Callbacks(\"memory\"),w.Callbacks(\"memory\"),2],[\"resolve\",\"done\",w.Callbacks(\"once memory\"),w.Callbacks(\"once memory\"),0,\"resolved\"],[\"reject\",\"fail\",w.Callbacks(\"once memory\"),w.Callbacks(\"once memory\"),1,\"rejected\"]],r=\"pending\",i={state:function(){return r},always:function(){return o.done(arguments).fail(arguments),this},catch:function(e){return i.then(null,e)},pipe:function(){var e=arguments;return w.Deferred((function(t){w.each(n,(function(n,r){var i=h(e[r[4]])&&e[r[4]];o[r[1]]((function(){var e=i&&i.apply(this,arguments);e&&h(e.promise)?e.promise().progress(t.notify).done(t.resolve).fail(t.reject):t[r[0]+\"With\"](this,i?[e]:arguments)}))})),e=null})).promise()},then:function(t,r,i){var o=0;function a(t,n,r,i){return function(){var s=this,u=arguments,l=function(){var e,l;if(!(t=o&&(r!==M&&(s=void 0,u=[e]),n.rejectWith(s,u))}};t?c():(w.Deferred.getStackHook&&(c.stackTrace=w.Deferred.getStackHook()),e.setTimeout(c))}}return w.Deferred((function(e){n[0][3].add(a(0,e,h(i)?i:R,e.notifyWith)),n[1][3].add(a(0,e,h(t)?t:R)),n[2][3].add(a(0,e,h(r)?r:M))})).promise()},promise:function(e){return null!=e?w.extend(e,i):i}},o={};return w.each(n,(function(e,t){var a=t[2],s=t[5];i[t[1]]=a.add,s&&a.add((function(){r=s}),n[3-e][2].disable,n[3-e][3].disable,n[0][2].lock,n[0][3].lock),a.add(t[3].fire),o[t[0]]=function(){return o[t[0]+\"With\"](this===o?void 0:this,arguments),this},o[t[0]+\"With\"]=a.fireWith})),i.promise(o),t&&t.call(o,o),o},when:function(e){var t=arguments.length,n=t,r=Array(n),o=i.call(arguments),a=w.Deferred(),s=function(e){return function(n){r[e]=this,o[e]=arguments.length>1?i.call(arguments):n,--t||a.resolveWith(r,o)}};if(t<=1&&(I(e,a.done(s(n)).resolve,a.reject,!t),\"pending\"===a.state()||h(o[n]&&o[n].then)))return a.then();for(;n--;)I(o[n],s(n),a.reject);return a.promise()}});var W=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;w.Deferred.exceptionHook=function(t,n){e.console&&e.console.warn&&t&&W.test(t.name)&&e.console.warn(\"jQuery.Deferred exception: \"+t.message,t.stack,n)},w.readyException=function(t){e.setTimeout((function(){throw t}))};var F=w.Deferred();function B(){v.removeEventListener(\"DOMContentLoaded\",B),e.removeEventListener(\"load\",B),w.ready()}w.fn.ready=function(e){return F.then(e).catch((function(e){w.readyException(e)})),this},w.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--w.readyWait:w.isReady)||(w.isReady=!0,!0!==e&&--w.readyWait>0||F.resolveWith(v,[w]))}}),w.ready.then=F.then,\"complete\"===v.readyState||\"loading\"!==v.readyState&&!v.documentElement.doScroll?e.setTimeout(w.ready):(v.addEventListener(\"DOMContentLoaded\",B),e.addEventListener(\"load\",B));var $=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if(\"object\"===x(n))for(s in i=!0,n)$(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,h(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(w(e),n)})),t))for(;s1,null,!0)},removeData:function(e){return this.each((function(){Q.remove(this,e)}))}}),w.extend({queue:function(e,t,n){var r;if(e)return t=(t||\"fx\")+\"queue\",r=Y.get(e,t),n&&(!r||Array.isArray(n)?r=Y.access(e,t,w.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||\"fx\";var n=w.queue(e,t),r=n.length,i=n.shift(),o=w._queueHooks(e,t);\"inprogress\"===i&&(i=n.shift(),r--),i&&(\"fx\"===t&&n.unshift(\"inprogress\"),delete o.stop,i.call(e,(function(){w.dequeue(e,t)}),o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+\"queueHooks\";return Y.get(e,n)||Y.access(e,n,{empty:w.Callbacks(\"once memory\").add((function(){Y.remove(e,[t+\"queue\",n])}))})}}),w.fn.extend({queue:function(e,t){var n=2;return\"string\"!=typeof e&&(t=e,e=\"fx\",n--),arguments.length\\x20\\t\\r\\n\\f]*)/i,ge=/^$|^module$|\\/(?:java|ecma)script/i;fe=v.createDocumentFragment().appendChild(v.createElement(\"div\")),(pe=v.createElement(\"input\")).setAttribute(\"type\",\"radio\"),pe.setAttribute(\"checked\",\"checked\"),pe.setAttribute(\"name\",\"t\"),fe.appendChild(pe),d.checkClone=fe.cloneNode(!0).cloneNode(!0).lastChild.checked,fe.innerHTML=\"\",d.noCloneChecked=!!fe.cloneNode(!0).lastChild.defaultValue,fe.innerHTML=\"\",d.option=!!fe.lastChild;var ve={thead:[1,\"\",\"
\"],col:[2,\"\",\"
\"],tr:[2,\"\",\"
\"],td:[3,\"\",\"
\"],_default:[0,\"\",\"\"]};function ye(e,t){var n;return n=void 0!==e.getElementsByTagName?e.getElementsByTagName(t||\"*\"):void 0!==e.querySelectorAll?e.querySelectorAll(t||\"*\"):[],void 0===t||t&&A(e,t)?w.merge([e],n):n}function me(e,t){for(var n=0,r=e.length;n\",\"\"]);var xe=/<|&#?\\w+;/;function be(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d-1)i&&i.push(o);else if(l=ie(o),a=ye(f.appendChild(o),\"script\"),l&&me(a),n)for(c=0;o=a[c++];)ge.test(o.type||\"\")&&n.push(o);return f}var we=/^([^.]*)(?:\\.(.+)|)/;function Te(){return!0}function Ce(){return!1}function Ee(e,t){return e===function(){try{return v.activeElement}catch(e){}}()==(\"focus\"===t)}function Se(e,t,n,r,i,o){var a,s;if(\"object\"==typeof t){for(s in\"string\"!=typeof n&&(r=r||n,n=void 0),t)Se(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&(\"string\"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Ce;else if(!i)return e;return 1===o&&(a=i,i=function(e){return w().off(e),a.apply(this,arguments)},i.guid=a.guid||(a.guid=w.guid++)),e.each((function(){w.event.add(this,t,i,r,n)}))}function ke(e,t,n){n?(Y.set(e,t,!1),w.event.add(e,t,{namespace:!1,handler:function(e){var r,o,a=Y.get(this,t);if(1&e.isTrigger&&this[t]){if(a.length)(w.event.special[t]||{}).delegateType&&e.stopPropagation();else if(a=i.call(arguments),Y.set(this,t,a),r=n(this,t),this[t](),a!==(o=Y.get(this,t))||r?Y.set(this,t,!1):o={},a!==o)return e.stopImmediatePropagation(),e.preventDefault(),o&&o.value}else a.length&&(Y.set(this,t,{value:w.event.trigger(w.extend(a[0],w.Event.prototype),a.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Y.get(e,t)&&w.event.add(e,t,Te)}w.event={global:{},add:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Y.get(e);if(V(e))for(n.handler&&(n=(o=n).handler,i=o.selector),i&&w.find.matchesSelector(re,i),n.guid||(n.guid=w.guid++),(u=v.events)||(u=v.events=Object.create(null)),(a=v.handle)||(a=v.handle=function(t){return void 0!==w&&w.event.triggered!==t.type?w.event.dispatch.apply(e,arguments):void 0}),l=(t=(t||\"\").match(P)||[\"\"]).length;l--;)d=g=(s=we.exec(t[l])||[])[1],h=(s[2]||\"\").split(\".\").sort(),d&&(f=w.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=w.event.special[d]||{},c=w.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&w.expr.match.needsContext.test(i),namespace:h.join(\".\")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(e,r,h,a)||e.addEventListener&&e.addEventListener(d,a)),f.add&&(f.add.call(e,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),w.event.global[d]=!0)},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Y.hasData(e)&&Y.get(e);if(v&&(u=v.events)){for(l=(t=(t||\"\").match(P)||[\"\"]).length;l--;)if(d=g=(s=we.exec(t[l])||[])[1],h=(s[2]||\"\").split(\".\").sort(),d){for(f=w.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp(\"(^|\\\\.)\"+h.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"),a=o=p.length;o--;)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&(\"**\"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||w.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)w.event.remove(e,d+t[l],n,r,!0);w.isEmptyObject(u)&&Y.remove(e,\"handle events\")}},dispatch:function(e){var t,n,r,i,o,a,s=new Array(arguments.length),u=w.event.fix(e),l=(Y.get(this,\"events\")||Object.create(null))[u.type]||[],c=w.event.special[u.type]||{};for(s[0]=u,t=1;t=1))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&(\"click\"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n-1:w.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u\\s*$/g;function De(e,t){return A(e,\"table\")&&A(11!==t.nodeType?t:t.firstChild,\"tr\")&&w(e).children(\"tbody\")[0]||e}function qe(e){return e.type=(null!==e.getAttribute(\"type\"))+\"/\"+e.type,e}function Le(e){return\"true/\"===(e.type||\"\").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute(\"type\"),e}function He(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,\"handle events\"),s)for(n=0,r=s[i].length;n1&&\"string\"==typeof v&&!d.checkClone&&Ne.test(v))return e.each((function(i){var o=e.eq(i);y&&(t[0]=v.call(this,i,o.html())),Pe(o,t,n,r)}));if(p&&(a=(i=be(t,e[0].ownerDocument,!1,e,r)).firstChild,1===i.childNodes.length&&(i=a),a||r)){for(u=(s=w.map(ye(i,\"script\"),qe)).length;f0&&me(a,!u&&ye(e,\"script\")),s},cleanData:function(e){for(var t,n,r,i=w.event.special,o=0;void 0!==(n=e[o]);o++)if(V(n)){if(t=n[Y.expando]){if(t.events)for(r in t.events)i[r]?w.event.remove(n,r):w.removeEvent(n,r,t.handle);n[Y.expando]=void 0}n[Q.expando]&&(n[Q.expando]=void 0)}}}),w.fn.extend({detach:function(e){return Re(this,e,!0)},remove:function(e){return Re(this,e)},text:function(e){return $(this,(function(e){return void 0===e?w.text(this):this.empty().each((function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)}))}),null,e,arguments.length)},append:function(){return Pe(this,arguments,(function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||De(this,e).appendChild(e)}))},prepend:function(){return Pe(this,arguments,(function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=De(this,e);t.insertBefore(e,t.firstChild)}}))},before:function(){return Pe(this,arguments,(function(e){this.parentNode&&this.parentNode.insertBefore(e,this)}))},after:function(){return Pe(this,arguments,(function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)}))},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(w.cleanData(ye(e,!1)),e.textContent=\"\");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map((function(){return w.clone(this,e,t)}))},html:function(e){return $(this,(function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if(\"string\"==typeof e&&!Ae.test(e)&&!ve[(he.exec(e)||[\"\",\"\"])[1].toLowerCase()]){e=w.htmlPrefilter(e);try{for(;n=0&&(u+=Math.max(0,Math.ceil(e[\"offset\"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))||0),u}function Ze(e,t,n){var r=Ie(e),i=(!d.boxSizingReliable()||n)&&\"border-box\"===w.css(e,\"boxSizing\",!1,r),o=i,a=Be(e,t,r),s=\"offset\"+t[0].toUpperCase()+t.slice(1);if(Me.test(a)){if(!n)return a;a=\"auto\"}return(!d.boxSizingReliable()&&i||!d.reliableTrDimensions()&&A(e,\"tr\")||\"auto\"===a||!parseFloat(a)&&\"inline\"===w.css(e,\"display\",!1,r))&&e.getClientRects().length&&(i=\"border-box\"===w.css(e,\"boxSizing\",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+Ke(e,t,n||(i?\"border\":\"content\"),o,r,a)+\"px\"}function et(e,t,n,r,i){return new et.prototype.init(e,t,n,r,i)}w.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Be(e,\"opacity\");return\"\"===n?\"1\":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=X(t),u=Ge.test(t),l=e.style;if(u||(t=Xe(s)),a=w.cssHooks[t]||w.cssHooks[s],void 0===n)return a&&\"get\"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];\"string\"===(o=typeof n)&&(i=te.exec(n))&&i[1]&&(n=se(e,t,i),o=\"number\"),null!=n&&n==n&&(\"number\"!==o||u||(n+=i&&i[3]||(w.cssNumber[s]?\"\":\"px\")),d.clearCloneStyle||\"\"!==n||0!==t.indexOf(\"background\")||(l[t]=\"inherit\"),a&&\"set\"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=X(t);return Ge.test(t)||(t=Xe(s)),(a=w.cssHooks[t]||w.cssHooks[s])&&\"get\"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Be(e,t,r)),\"normal\"===i&&t in Qe&&(i=Qe[t]),\"\"===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),w.each([\"height\",\"width\"],(function(e,t){w.cssHooks[t]={get:function(e,n,r){if(n)return!Ve.test(w.css(e,\"display\"))||e.getClientRects().length&&e.getBoundingClientRect().width?Ze(e,t,r):We(e,Ye,(function(){return Ze(e,t,r)}))},set:function(e,n,r){var i,o=Ie(e),a=!d.scrollboxSize()&&\"absolute\"===o.position,s=(a||r)&&\"border-box\"===w.css(e,\"boxSizing\",!1,o),u=r?Ke(e,t,r,s,o):0;return s&&a&&(u-=Math.ceil(e[\"offset\"+t[0].toUpperCase()+t.slice(1)]-parseFloat(o[t])-Ke(e,t,\"border\",!1,o)-.5)),u&&(i=te.exec(n))&&\"px\"!==(i[3]||\"px\")&&(e.style[t]=n,n=w.css(e,t)),Je(0,n,u)}}})),w.cssHooks.marginLeft=$e(d.reliableMarginLeft,(function(e,t){if(t)return(parseFloat(Be(e,\"marginLeft\"))||e.getBoundingClientRect().left-We(e,{marginLeft:0},(function(){return e.getBoundingClientRect().left})))+\"px\"})),w.each({margin:\"\",padding:\"\",border:\"Width\"},(function(e,t){w.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o=\"string\"==typeof n?n.split(\" \"):[n];r<4;r++)i[e+ne[r]+t]=o[r]||o[r-2]||o[0];return i}},\"margin\"!==e&&(w.cssHooks[e+t].set=Je)})),w.fn.extend({css:function(e,t){return $(this,(function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=Ie(e),i=t.length;a1)}}),w.Tween=et,et.prototype={constructor:et,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||w.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(w.cssNumber[n]?\"\":\"px\")},cur:function(){var e=et.propHooks[this.prop];return e&&e.get?e.get(this):et.propHooks._default.get(this)},run:function(e){var t,n=et.propHooks[this.prop];return this.options.duration?this.pos=t=w.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):et.propHooks._default.set(this),this}},et.prototype.init.prototype=et.prototype,et.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=w.css(e.elem,e.prop,\"\"))&&\"auto\"!==t?t:0},set:function(e){w.fx.step[e.prop]?w.fx.step[e.prop](e):1!==e.elem.nodeType||!w.cssHooks[e.prop]&&null==e.elem.style[Xe(e.prop)]?e.elem[e.prop]=e.now:w.style(e.elem,e.prop,e.now+e.unit)}}},et.propHooks.scrollTop=et.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},w.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:\"swing\"},w.fx=et.prototype.init,w.fx.step={};var tt,nt,rt=/^(?:toggle|show|hide)$/,it=/queueHooks$/;function ot(){nt&&(!1===v.hidden&&e.requestAnimationFrame?e.requestAnimationFrame(ot):e.setTimeout(ot,w.fx.interval),w.fx.tick())}function at(){return e.setTimeout((function(){tt=void 0})),tt=Date.now()}function st(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i[\"margin\"+(n=ne[r])]=i[\"padding\"+n]=e;return t&&(i.opacity=i.width=e),i}function ut(e,t,n){for(var r,i=(lt.tweeners[t]||[]).concat(lt.tweeners[\"*\"]),o=0,a=i.length;o1)},removeAttr:function(e){return this.each((function(){w.removeAttr(this,e)}))}}),w.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return void 0===e.getAttribute?w.prop(e,t,n):(1===o&&w.isXMLDoc(e)||(i=w.attrHooks[t.toLowerCase()]||(w.expr.match.bool.test(t)?ct:void 0)),void 0!==n?null===n?void w.removeAttr(e,t):i&&\"set\"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+\"\"),n):i&&\"get\"in i&&null!==(r=i.get(e,t))?r:null==(r=w.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!d.radioValue&&\"radio\"===t&&A(e,\"input\")){var n=e.value;return e.setAttribute(\"type\",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(P);if(i&&1===e.nodeType)for(;n=i[r++];)e.removeAttribute(n)}}),ct={set:function(e,t,n){return!1===t?w.removeAttr(e,n):e.setAttribute(n,n),n}},w.each(w.expr.match.bool.source.match(/\\w+/g),(function(e,t){var n=ft[t]||w.find.attr;ft[t]=function(e,t,r){var i,o,a=t.toLowerCase();return r||(o=ft[a],ft[a]=i,i=null!=n(e,t,r)?a:null,ft[a]=o),i}}));var pt=/^(?:input|select|textarea|button)$/i,dt=/^(?:a|area)$/i;function ht(e){return(e.match(P)||[]).join(\" \")}function gt(e){return e.getAttribute&&e.getAttribute(\"class\")||\"\"}function vt(e){return Array.isArray(e)?e:\"string\"==typeof e&&e.match(P)||[]}w.fn.extend({prop:function(e,t){return $(this,w.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each((function(){delete this[w.propFix[e]||e]}))}}),w.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&w.isXMLDoc(e)||(t=w.propFix[t]||t,i=w.propHooks[t]),void 0!==n?i&&\"set\"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&\"get\"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=w.find.attr(e,\"tabindex\");return t?parseInt(t,10):pt.test(e.nodeName)||dt.test(e.nodeName)&&e.href?0:-1}}},propFix:{for:\"htmlFor\",class:\"className\"}}),d.optSelected||(w.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),w.each([\"tabIndex\",\"readOnly\",\"maxLength\",\"cellSpacing\",\"cellPadding\",\"rowSpan\",\"colSpan\",\"useMap\",\"frameBorder\",\"contentEditable\"],(function(){w.propFix[this.toLowerCase()]=this})),w.fn.extend({addClass:function(e){var t,n,r,i,o,a,s,u=0;if(h(e))return this.each((function(t){w(this).addClass(e.call(this,t,gt(this)))}));if((t=vt(e)).length)for(;n=this[u++];)if(i=gt(n),r=1===n.nodeType&&\" \"+ht(i)+\" \"){for(a=0;o=t[a++];)r.indexOf(\" \"+o+\" \")<0&&(r+=o+\" \");i!==(s=ht(r))&&n.setAttribute(\"class\",s)}return this},removeClass:function(e){var t,n,r,i,o,a,s,u=0;if(h(e))return this.each((function(t){w(this).removeClass(e.call(this,t,gt(this)))}));if(!arguments.length)return this.attr(\"class\",\"\");if((t=vt(e)).length)for(;n=this[u++];)if(i=gt(n),r=1===n.nodeType&&\" \"+ht(i)+\" \"){for(a=0;o=t[a++];)for(;r.indexOf(\" \"+o+\" \")>-1;)r=r.replace(\" \"+o+\" \",\" \");i!==(s=ht(r))&&n.setAttribute(\"class\",s)}return this},toggleClass:function(e,t){var n=typeof e,r=\"string\"===n||Array.isArray(e);return\"boolean\"==typeof t&&r?t?this.addClass(e):this.removeClass(e):h(e)?this.each((function(n){w(this).toggleClass(e.call(this,n,gt(this),t),t)})):this.each((function(){var t,i,o,a;if(r)for(i=0,o=w(this),a=vt(e);t=a[i++];)o.hasClass(t)?o.removeClass(t):o.addClass(t);else void 0!==e&&\"boolean\"!==n||((t=gt(this))&&Y.set(this,\"__className__\",t),this.setAttribute&&this.setAttribute(\"class\",t||!1===e?\"\":Y.get(this,\"__className__\")||\"\"))}))},hasClass:function(e){var t,n,r=0;for(t=\" \"+e+\" \";n=this[r++];)if(1===n.nodeType&&(\" \"+ht(gt(n))+\" \").indexOf(t)>-1)return!0;return!1}});var yt=/\\r/g;w.fn.extend({val:function(e){var t,n,r,i=this[0];return arguments.length?(r=h(e),this.each((function(n){var i;1===this.nodeType&&(null==(i=r?e.call(this,n,w(this).val()):e)?i=\"\":\"number\"==typeof i?i+=\"\":Array.isArray(i)&&(i=w.map(i,(function(e){return null==e?\"\":e+\"\"}))),(t=w.valHooks[this.type]||w.valHooks[this.nodeName.toLowerCase()])&&\"set\"in t&&void 0!==t.set(this,i,\"value\")||(this.value=i))}))):i?(t=w.valHooks[i.type]||w.valHooks[i.nodeName.toLowerCase()])&&\"get\"in t&&void 0!==(n=t.get(i,\"value\"))?n:\"string\"==typeof(n=i.value)?n.replace(yt,\"\"):null==n?\"\":n:void 0}}),w.extend({valHooks:{option:{get:function(e){var t=w.find.attr(e,\"value\");return null!=t?t:ht(w.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a=\"select-one\"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r-1)&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),w.each([\"radio\",\"checkbox\"],(function(){w.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=w.inArray(w(e).val(),t)>-1}},d.checkOn||(w.valHooks[this].get=function(e){return null===e.getAttribute(\"value\")?\"on\":e.value})})),d.focusin=\"onfocusin\"in e;var mt=/^(?:focusinfocus|focusoutblur)$/,xt=function(e){e.stopPropagation()};w.extend(w.event,{trigger:function(t,n,r,i){var o,a,s,u,l,f,p,d,y=[r||v],m=c.call(t,\"type\")?t.type:t,x=c.call(t,\"namespace\")?t.namespace.split(\".\"):[];if(a=d=s=r=r||v,3!==r.nodeType&&8!==r.nodeType&&!mt.test(m+w.event.triggered)&&(m.indexOf(\".\")>-1&&(x=m.split(\".\"),m=x.shift(),x.sort()),l=m.indexOf(\":\")<0&&\"on\"+m,(t=t[w.expando]?t:new w.Event(m,\"object\"==typeof t&&t)).isTrigger=i?2:3,t.namespace=x.join(\".\"),t.rnamespace=t.namespace?new RegExp(\"(^|\\\\.)\"+x.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"):null,t.result=void 0,t.target||(t.target=r),n=null==n?[t]:w.makeArray(n,[t]),p=w.event.special[m]||{},i||!p.trigger||!1!==p.trigger.apply(r,n))){if(!i&&!p.noBubble&&!g(r)){for(u=p.delegateType||m,mt.test(u+m)||(a=a.parentNode);a;a=a.parentNode)y.push(a),s=a;s===(r.ownerDocument||v)&&y.push(s.defaultView||s.parentWindow||e)}for(o=0;(a=y[o++])&&!t.isPropagationStopped();)d=a,t.type=o>1?u:p.bindType||m,(f=(Y.get(a,\"events\")||Object.create(null))[t.type]&&Y.get(a,\"handle\"))&&f.apply(a,n),(f=l&&a[l])&&f.apply&&V(a)&&(t.result=f.apply(a,n),!1===t.result&&t.preventDefault());return t.type=m,i||t.isDefaultPrevented()||p._default&&!1!==p._default.apply(y.pop(),n)||!V(r)||l&&h(r[m])&&!g(r)&&((s=r[l])&&(r[l]=null),w.event.triggered=m,t.isPropagationStopped()&&d.addEventListener(m,xt),r[m](),t.isPropagationStopped()&&d.removeEventListener(m,xt),w.event.triggered=void 0,s&&(r[l]=s)),t.result}},simulate:function(e,t,n){var r=w.extend(new w.Event,n,{type:e,isSimulated:!0});w.event.trigger(r,null,t)}}),w.fn.extend({trigger:function(e,t){return this.each((function(){w.event.trigger(e,t,this)}))},triggerHandler:function(e,t){var n=this[0];if(n)return w.event.trigger(e,t,n,!0)}}),d.focusin||w.each({focus:\"focusin\",blur:\"focusout\"},(function(e,t){var n=function(e){w.event.simulate(t,e.target,w.event.fix(e))};w.event.special[t]={setup:function(){var r=this.ownerDocument||this.document||this,i=Y.access(r,t);i||r.addEventListener(e,n,!0),Y.access(r,t,(i||0)+1)},teardown:function(){var r=this.ownerDocument||this.document||this,i=Y.access(r,t)-1;i?Y.access(r,t,i):(r.removeEventListener(e,n,!0),Y.remove(r,t))}}}));var bt=e.location,wt={guid:Date.now()},Tt=/\\?/;w.parseXML=function(t){var n,r;if(!t||\"string\"!=typeof t)return null;try{n=(new e.DOMParser).parseFromString(t,\"text/xml\")}catch(e){}return r=n&&n.getElementsByTagName(\"parsererror\")[0],n&&!r||w.error(\"Invalid XML: \"+(r?w.map(r.childNodes,(function(e){return e.textContent})).join(\"\\n\"):t)),n};var Ct=/\\[\\]$/,Et=/\\r?\\n/g,St=/^(?:submit|button|image|reset|file)$/i,kt=/^(?:input|select|textarea|keygen)/i;function At(e,t,n,r){var i;if(Array.isArray(t))w.each(t,(function(t,i){n||Ct.test(e)?r(e,i):At(e+\"[\"+(\"object\"==typeof i&&null!=i?t:\"\")+\"]\",i,n,r)}));else if(n||\"object\"!==x(t))r(e,t);else for(i in t)At(e+\"[\"+i+\"]\",t[i],n,r)}w.param=function(e,t){var n,r=[],i=function(e,t){var n=h(t)?t():t;r[r.length]=encodeURIComponent(e)+\"=\"+encodeURIComponent(null==n?\"\":n)};if(null==e)return\"\";if(Array.isArray(e)||e.jquery&&!w.isPlainObject(e))w.each(e,(function(){i(this.name,this.value)}));else for(n in e)At(n,e[n],t,i);return r.join(\"&\")},w.fn.extend({serialize:function(){return w.param(this.serializeArray())},serializeArray:function(){return this.map((function(){var e=w.prop(this,\"elements\");return e?w.makeArray(e):this})).filter((function(){var e=this.type;return this.name&&!w(this).is(\":disabled\")&&kt.test(this.nodeName)&&!St.test(e)&&(this.checked||!de.test(e))})).map((function(e,t){var n=w(this).val();return null==n?null:Array.isArray(n)?w.map(n,(function(e){return{name:t.name,value:e.replace(Et,\"\\r\\n\")}})):{name:t.name,value:n.replace(Et,\"\\r\\n\")}})).get()}});var Nt=/%20/g,jt=/#.*$/,Dt=/([?&])_=[^&]*/,qt=/^(.*?):[ \\t]*([^\\r\\n]*)$/gm,Lt=/^(?:GET|HEAD)$/,Ht=/^\\/\\//,Ot={},Pt={},Rt=\"*/\".concat(\"*\"),Mt=v.createElement(\"a\");function It(e){return function(t,n){\"string\"!=typeof t&&(n=t,t=\"*\");var r,i=0,o=t.toLowerCase().match(P)||[];if(h(n))for(;r=o[i++];)\"+\"===r[0]?(r=r.slice(1)||\"*\",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function Wt(e,t,n,r){var i={},o=e===Pt;function a(s){var u;return i[s]=!0,w.each(e[s]||[],(function(e,s){var l=s(t,n,r);return\"string\"!=typeof l||o||i[l]?o?!(u=l):void 0:(t.dataTypes.unshift(l),a(l),!1)})),u}return a(t.dataTypes[0])||!i[\"*\"]&&a(\"*\")}function Ft(e,t){var n,r,i=w.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&w.extend(!0,e,r),e}Mt.href=bt.href,w.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:bt.href,type:\"GET\",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(bt.protocol),global:!0,processData:!0,async:!0,contentType:\"application/x-www-form-urlencoded; charset=UTF-8\",accepts:{\"*\":Rt,text:\"text/plain\",html:\"text/html\",xml:\"application/xml, text/xml\",json:\"application/json, text/javascript\"},contents:{xml:/\\bxml\\b/,html:/\\bhtml/,json:/\\bjson\\b/},responseFields:{xml:\"responseXML\",text:\"responseText\",json:\"responseJSON\"},converters:{\"* text\":String,\"text html\":!0,\"text json\":JSON.parse,\"text xml\":w.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?Ft(Ft(e,w.ajaxSettings),t):Ft(w.ajaxSettings,e)},ajaxPrefilter:It(Ot),ajaxTransport:It(Pt),ajax:function(t,n){\"object\"==typeof t&&(n=t,t=void 0),n=n||{};var r,i,o,a,s,u,l,c,f,p,d=w.ajaxSetup({},n),h=d.context||d,g=d.context&&(h.nodeType||h.jquery)?w(h):w.event,y=w.Deferred(),m=w.Callbacks(\"once memory\"),x=d.statusCode||{},b={},T={},C=\"canceled\",E={readyState:0,getResponseHeader:function(e){var t;if(l){if(!a)for(a={};t=qt.exec(o);)a[t[1].toLowerCase()+\" \"]=(a[t[1].toLowerCase()+\" \"]||[]).concat(t[2]);t=a[e.toLowerCase()+\" \"]}return null==t?null:t.join(\", \")},getAllResponseHeaders:function(){return l?o:null},setRequestHeader:function(e,t){return null==l&&(e=T[e.toLowerCase()]=T[e.toLowerCase()]||e,b[e]=t),this},overrideMimeType:function(e){return null==l&&(d.mimeType=e),this},statusCode:function(e){var t;if(e)if(l)E.always(e[E.status]);else for(t in e)x[t]=[x[t],e[t]];return this},abort:function(e){var t=e||C;return r&&r.abort(t),S(0,t),this}};if(y.promise(E),d.url=((t||d.url||bt.href)+\"\").replace(Ht,bt.protocol+\"//\"),d.type=n.method||n.type||d.method||d.type,d.dataTypes=(d.dataType||\"*\").toLowerCase().match(P)||[\"\"],null==d.crossDomain){u=v.createElement(\"a\");try{u.href=d.url,u.href=u.href,d.crossDomain=Mt.protocol+\"//\"+Mt.host!=u.protocol+\"//\"+u.host}catch(e){d.crossDomain=!0}}if(d.data&&d.processData&&\"string\"!=typeof d.data&&(d.data=w.param(d.data,d.traditional)),Wt(Ot,d,n,E),l)return E;for(f in(c=w.event&&d.global)&&0==w.active++&&w.event.trigger(\"ajaxStart\"),d.type=d.type.toUpperCase(),d.hasContent=!Lt.test(d.type),i=d.url.replace(jt,\"\"),d.hasContent?d.data&&d.processData&&0===(d.contentType||\"\").indexOf(\"application/x-www-form-urlencoded\")&&(d.data=d.data.replace(Nt,\"+\")):(p=d.url.slice(i.length),d.data&&(d.processData||\"string\"==typeof d.data)&&(i+=(Tt.test(i)?\"&\":\"?\")+d.data,delete d.data),!1===d.cache&&(i=i.replace(Dt,\"$1\"),p=(Tt.test(i)?\"&\":\"?\")+\"_=\"+wt.guid+++p),d.url=i+p),d.ifModified&&(w.lastModified[i]&&E.setRequestHeader(\"If-Modified-Since\",w.lastModified[i]),w.etag[i]&&E.setRequestHeader(\"If-None-Match\",w.etag[i])),(d.data&&d.hasContent&&!1!==d.contentType||n.contentType)&&E.setRequestHeader(\"Content-Type\",d.contentType),E.setRequestHeader(\"Accept\",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(\"*\"!==d.dataTypes[0]?\", \"+Rt+\"; q=0.01\":\"\"):d.accepts[\"*\"]),d.headers)E.setRequestHeader(f,d.headers[f]);if(d.beforeSend&&(!1===d.beforeSend.call(h,E,d)||l))return E.abort();if(C=\"abort\",m.add(d.complete),E.done(d.success),E.fail(d.error),r=Wt(Pt,d,n,E)){if(E.readyState=1,c&&g.trigger(\"ajaxSend\",[E,d]),l)return E;d.async&&d.timeout>0&&(s=e.setTimeout((function(){E.abort(\"timeout\")}),d.timeout));try{l=!1,r.send(b,S)}catch(e){if(l)throw e;S(-1,e)}}else S(-1,\"No Transport\");function S(t,n,a,u){var f,p,v,b,T,C=n;l||(l=!0,s&&e.clearTimeout(s),r=void 0,o=u||\"\",E.readyState=t>0?4:0,f=t>=200&&t<300||304===t,a&&(b=function(e,t,n){for(var r,i,o,a,s=e.contents,u=e.dataTypes;\"*\"===u[0];)u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader(\"Content-Type\"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+\" \"+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}(d,E,a)),!f&&w.inArray(\"script\",d.dataTypes)>-1&&w.inArray(\"json\",d.dataTypes)<0&&(d.converters[\"text script\"]=function(){}),b=function(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];for(o=c.shift();o;)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if(\"*\"===o)o=u;else if(\"*\"!==u&&u!==o){if(!(a=l[u+\" \"+o]||l[\"* \"+o]))for(i in l)if((s=i.split(\" \"))[1]===o&&(a=l[u+\" \"+s[0]]||l[\"* \"+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e.throws)t=a(t);else try{t=a(t)}catch(e){return{state:\"parsererror\",error:a?e:\"No conversion from \"+u+\" to \"+o}}}return{state:\"success\",data:t}}(d,b,E,f),f?(d.ifModified&&((T=E.getResponseHeader(\"Last-Modified\"))&&(w.lastModified[i]=T),(T=E.getResponseHeader(\"etag\"))&&(w.etag[i]=T)),204===t||\"HEAD\"===d.type?C=\"nocontent\":304===t?C=\"notmodified\":(C=b.state,p=b.data,f=!(v=b.error))):(v=C,!t&&C||(C=\"error\",t<0&&(t=0))),E.status=t,E.statusText=(n||C)+\"\",f?y.resolveWith(h,[p,C,E]):y.rejectWith(h,[E,C,v]),E.statusCode(x),x=void 0,c&&g.trigger(f?\"ajaxSuccess\":\"ajaxError\",[E,d,f?p:v]),m.fireWith(h,[E,C]),c&&(g.trigger(\"ajaxComplete\",[E,d]),--w.active||w.event.trigger(\"ajaxStop\")))}return E},getJSON:function(e,t,n){return w.get(e,t,n,\"json\")},getScript:function(e,t){return w.get(e,void 0,t,\"script\")}}),w.each([\"get\",\"post\"],(function(e,t){w[t]=function(e,n,r,i){return h(n)&&(i=i||r,r=n,n=void 0),w.ajax(w.extend({url:e,type:t,dataType:i,data:n,success:r},w.isPlainObject(e)&&e))}})),w.ajaxPrefilter((function(e){var t;for(t in e.headers)\"content-type\"===t.toLowerCase()&&(e.contentType=e.headers[t]||\"\")})),w._evalUrl=function(e,t,n){return w.ajax({url:e,type:\"GET\",dataType:\"script\",cache:!0,async:!1,global:!1,converters:{\"text script\":function(){}},dataFilter:function(e){w.globalEval(e,t,n)}})},w.fn.extend({wrapAll:function(e){var t;return this[0]&&(h(e)&&(e=e.call(this[0])),t=w(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map((function(){for(var e=this;e.firstElementChild;)e=e.firstElementChild;return e})).append(this)),this},wrapInner:function(e){return h(e)?this.each((function(t){w(this).wrapInner(e.call(this,t))})):this.each((function(){var t=w(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)}))},wrap:function(e){var t=h(e);return this.each((function(n){w(this).wrapAll(t?e.call(this,n):e)}))},unwrap:function(e){return this.parent(e).not(\"body\").each((function(){w(this).replaceWith(this.childNodes)})),this}}),w.expr.pseudos.hidden=function(e){return!w.expr.pseudos.visible(e)},w.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},w.ajaxSettings.xhr=function(){try{return new e.XMLHttpRequest}catch(e){}};var Bt={0:200,1223:204},$t=w.ajaxSettings.xhr();d.cors=!!$t&&\"withCredentials\"in $t,d.ajax=$t=!!$t,w.ajaxTransport((function(t){var n,r;if(d.cors||$t&&!t.crossDomain)return{send:function(i,o){var a,s=t.xhr();if(s.open(t.type,t.url,t.async,t.username,t.password),t.xhrFields)for(a in t.xhrFields)s[a]=t.xhrFields[a];for(a in t.mimeType&&s.overrideMimeType&&s.overrideMimeType(t.mimeType),t.crossDomain||i[\"X-Requested-With\"]||(i[\"X-Requested-With\"]=\"XMLHttpRequest\"),i)s.setRequestHeader(a,i[a]);n=function(e){return function(){n&&(n=r=s.onload=s.onerror=s.onabort=s.ontimeout=s.onreadystatechange=null,\"abort\"===e?s.abort():\"error\"===e?\"number\"!=typeof s.status?o(0,\"error\"):o(s.status,s.statusText):o(Bt[s.status]||s.status,s.statusText,\"text\"!==(s.responseType||\"text\")||\"string\"!=typeof s.responseText?{binary:s.response}:{text:s.responseText},s.getAllResponseHeaders()))}},s.onload=n(),r=s.onerror=s.ontimeout=n(\"error\"),void 0!==s.onabort?s.onabort=r:s.onreadystatechange=function(){4===s.readyState&&e.setTimeout((function(){n&&r()}))},n=n(\"abort\");try{s.send(t.hasContent&&t.data||null)}catch(e){if(n)throw e}},abort:function(){n&&n()}}})),w.ajaxPrefilter((function(e){e.crossDomain&&(e.contents.script=!1)})),w.ajaxSetup({accepts:{script:\"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript\"},contents:{script:/\\b(?:java|ecma)script\\b/},converters:{\"text script\":function(e){return w.globalEval(e),e}}}),w.ajaxPrefilter(\"script\",(function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type=\"GET\")})),w.ajaxTransport(\"script\",(function(e){var t,n;if(e.crossDomain||e.scriptAttrs)return{send:function(r,i){t=w(\"