---
title: "Dataset"
date: 2019-09-27 16:41
draft: false
---
<link rel="stylesheet" type="text/css" href="/css/modal.css" />
<link rel="stylesheet" type="text/css" href="/css/form.css" />
<link rel="stylesheet" type="text/css" href="/css/table.css" />
<link rel="stylesheet" type="text/css" href="/css/emoji.css" />
<script src="/js/data.js" type="text/javascript"></script>
<script src="/js/loadAllData.js" type="text/javascript"></script>
<script src="/js/getFullDataPath.js" type="text/javascript"></script>
<script src="/js/getTextFromFile.js" type="text/javascript"></script>
<script src="/js/trueTypeOf.js" type="text/javascript"></script>
<script src="/js/uniq.js"></script>
<script src="/js/processingIndicator.js"></script>
<script src="/js/noNan.js"></script>
<script src="/js/websiteFile.js"></script>
<script src="/js/getPublis.js"></script>
<script src="/js/DOICache.js"></script>
<script src="/js/nestedCheckbox.js"></script>
<script src="/js/selectSelectAll.js"></script>
<script src="/js/numberRangeChange.js"></script>
<script src="/js/DebugMode.js"></script>
<script src="/js/numberUtils.js"></script>
<script src="/js/PubliDB.js"></script>
<script>
  function adjustSticky() {
    const height = $("nav").height()
    $("thead.sticky > tr > th ").css("top", height)
  }
  window.onload = async () => {
    window.browser = bowser.getParser(window.navigator.userAgent);
    $("input[type='checkbox']").trigger("change")
    $("input[type='number'].range").trigger("change")
    adjustSticky();
    $(window).resize(adjustSticky)

    var slist = $("#SelectList")
    getAllSelect().each(function () {
      $("<li/>").text($('label[for="' + $(this).attr('id') + '"]').text()).appendTo(slist)
    })
    $('[data-needbrowser],[data-neednotbrowser]').each(function () {
      function test(key, value) {
        switch (key) {
          case "Engine":
            return value.some((v) => browser.isEngine(v))
            break;
          case "Browser":
            return value.some((v) => browser.isBrowser(v))
          case "Platform":
            return value.some((v) => browser.isPlatform(v))
          case "OS":
            return value.some((v) => browser.isOS(v))
          default:
            return true
            break;
        }
      }
      const needdata = $(this).data("needbrowser")
      const neednotdata = $(this).data("neednotbrowser")
      const need = ((needdata == null) ? true : Object.entries(needdata).every(kv => test(kv[0], kv[1])))
      const neednot = ((neednotdata == null) ? true : Object.entries(neednotdata).some(kv => !test(kv[0], kv[1])))
      if (need && neednot) {
        $(this).show()
      } else {
        $(this).hide()
      }
    })
    var cbextl = $("#cb_exTypeList")
    var extl = $("#exTypeList")
    var vertkindtl = $("#exVertKindList")
    for (const [name, value] of VertExcitationKinds.All) {
      $("<li/>").text(name).appendTo(vertkindtl)
    }
    for (const [name, value] of excitationTypes.All) {
      var txt = value.description.string
      if (value.description.isLaTeX) {
        txt = MathJaxUtils.getMathJaxString(txt)
      }
      $("<li/>").text(txt).appendTo(extl)
      var cbli = $("<li/>")
      if (!DebugMode.Enabled && value == (1 << 31)) {
        cbli.hide()
      }
      $("<input/>", { type: "checkbox", id: "cb_" + name, name: name, value: Number(value) }).change(nestedCheckbox_change).appendTo(cbli);
      $('<label />', { 'for': 'cb_' + name, text: txt }).appendTo(cbli);
      cbextl.append(cbli);
    }
    await MathJax.typesetPromise();
    delete (cbextl)
    delete (extl)
    delete (vertkindtl)
    window.doiCache = new DOICache()
    await loadFiles()
  }
  async function loadFiles() {
    processingIndicator.isActive = true
    var chks = []
    var data = await loadAllData()
    window.defaultDats = []
    for (const sub of Object.values(data)) {
      for (const doi of uniq(sub.map(d => (d.DOI == null ? "" : d.DOI.string)))) {
        const subdoi = sub.filter(d => (d.DOI == null ? "" : d.DOI.string) === doi)
        for (mol of uniq(subdoi.map(d => d.molecule))) {
          const submol = subdoi.filter(d => d.molecule === mol)
          const source = submol.find((d) => {
            if ((d.DOI == null ? "" : d.DOI.string) === "10.1021/acs.jctc.8b01205") {
              return d.method.name === "CASPT2" && d.method.basis === "aug-cc-pVDZ"
            } else {
              return d.method.isTBE
            }
          })
          if (source !== undefined) {
            for (const dat of submol.filter((d) => d !== source)) {
              dat.CopyExcitationsTypeFrom(source)
            }
          }
        }
      }

      window.defaultDats = window.defaultDats.concat(sub)
    }
    await doiCache.addRange(Array.from(new Set(window.defaultDats.filter(d => d.DOI !== null).map(d => d.DOI.string))))
    window.defaultDats = window.defaultDats.sort((datfa, datfb) => {
      const DOIa = datfa.DOI
      const DOIb = datfb.DOI
      if (DOIa == null && DOIb == null) {
        return 0
      }
      else if (DOIa == null) {
        return 1
      }
      else if (DOIb == null) {
        return -1
      }
      else {
        const puba = doiCache.get(DOIa.string).format('data', { format: 'object' })[0]
        const pubb = doiCache.get(DOIb.string).format('data', { format: 'object' })[0]
        return pubUtils.getIssuedDate(puba) - pubUtils.getIssuedDate(pubb)
      }
    })
    processingIndicator.isActive = false
    reloadCustomFiles()
  }
  async function reloadCustomFiles() {
    window.dats = window.defaultDats;
    const kinds = new Map([["file_abs", VertExcitationKinds.Absorbtion], ["file_fluo", VertExcitationKinds.Fluorescence]])
    for (const el of $('#form_dat > fieldset > fieldset > div > input[type="file"')) {
      if (kinds.has(el.name)) {
        for (const f of el.files) {
          const dat = await VertDataFile.loadAsync(f, kinds.get(this.name))
          window.dats.push(dat)
        }
      }
    }
    reloadSelect("DOI")
  }
  async function clearSelect(BeforeName = null) {
    var selects = ((BeforeName == null) ? getAllSelect() : getAllSelectAfter(BeforeName, true))
    selects.add($('#sel_ref'))
    selects.each(function () {
      $(this).empty()
    })
  }

  function getAllSelect() {
    return $('#form_dat > fieldset > fieldset > div > select')
  }

  function getAllSelectAfter(Name, include = false) {
    const selects = getAllSelect()
    var index = selects.index($(`[name="${Name}"]`))
    if (!include) {
      index++
    }
    return selects.slice(index)
  }
  function getAllSelectBefore(Name, include = false) {
    const selects = getAllSelect()
    var index = selects.index($(`[name="${Name}"]`))
    if (include) {
      index++
    }
    return selects.slice(0, index)
  }
  async function reloadNextSelect(e) {
    const afters = getAllSelectAfter(e.target.name)
    const isLast = afters.length == 0
    if (!isLast) {
      await reloadSelect(afters.prop("name"))
    }
    const fillArray = ["molecule"]
    if (fillArray.includes(afters.prop("name"))) {
      selectSelectAll(afters.first())
    }
  }
  function getAllVals(select) {
    var baseval = $(select).val()
    switch (select.name) {
      case "DOI":
        vals=baseval.reduce((accumulator,currentValue)=>accumulator.concat(JSON.parse(currentValue)),[])
        return vals
        break;
      default:
        return baseval
    }
  }
  async function reloadSelect(name) {
    clearSelect(name)
    var selects = getAllSelectBefore(name, true)
    var currentselect = selects.last()
    selects = selects.slice(0, selects.length - 1)
    var AllValsCache = new Map()
    selects.each(function() {
      AllValsCache.set(this.name,getAllVals(this))
    })
    var AAllValsCache = Array.from(AllValsCache)
    var vals = uniq(window.dats.filter(d => {
      return AAllValsCache.every(([k,v]) => {
        return v.indexOf(getSelectValue(d, k)) !== -1
      })
    }).map((d) => getSelectValue(d, name)))
    const publis = await (async () => {
      if (name === "DOI") {
        const publis = await publiDB.loadAsync()
        return publis
      }
      else {
        return undefined
      }
    })()
    if (name === "DOI") {
      let newvals = []
      for (const val of vals) {
        for (const set of publis.sets.values()) {
          if (set.includes(val)) {
            newvals.push(set)
          }
        }
      }
      vals = newvals
    }
    textSelctor = function (value) {
      switch (name) {
        case "DOI":
          setname = publis.findNameFromSet(value, true)
          return setname === null ? value.toString() : setname
          break;
        case "molecule":
          const mhchemCE = /^\\ce\{(.*)\}$/
          const m = value.match(mhchemCE)
          if (m) {
            return m[1]
          } else {
            return value
          }
          break;
        default:
          return value.toString()
      }
    }
    valueSelector = function (value) {
      if (typeof value === 'object') {
        return JSON.stringify(value)
      }
      else {
        return value
      }
    }
    for (const val of vals) {
      if (val !== null) {
        $("<option/>", {
          value: valueSelector(val)
        }).text(textSelctor(val)).appendTo(currentselect)
      }
      if (name === "molecule") {
        await MathJax.typesetPromise()
      }
    }
  }
  function getSelectValue(data, name) {
    switch (name) {
      case "method":
        return data.method.name
        break;
      case "basis":
        return data.method.basis
      case "DOI":
        return data.DOI === null ? "" : data.DOI.string
      default:
        return data[name]
        break;
    }
  }
  async function reloadStat() {
    processingIndicator.isActive = true
    var stb = $("#stat_table > tbody")
    $("#graph_div").empty()
    $(stb).empty()
    var refstr = $("#sel_ref option:selected").val()
    var sdatdic = new Map()
    for (const d of window.filtData) {
      const key = JSON.stringify(d.method)
      if (!(sdatdic.has(key))) {
        sdatdic.set(key, new Map())
      }
      const myT1s = T1ref.get(d.DOI == null ? "" : d.DOI.string).get(d.molecule)
      for (const exc of d.excitations) {
        var allowT1 = false
        const T1Key = JSON.stringify((exc.initial, exc.final))
        const T1range = filterParams.T1
        if (T1range.min === 0 && T1range.max === 100) {
          allowT1 = true
        } else if (myT1s.has(T1Key)) {
          const T1Val = myT1s.get(T1Key)
          if (T1range.min <= T1Val && T1Val <= T1range.max) {
            allowT1 = true
          }
        }
        const key2 = JSON.stringify([d.molecule, exc.initial, exc.final, exc.cVertExcitationKind])
        const keydic = sdatdic.get(key)
        if ((!exc.isUnsafe || window.filterParams.unsafe) && ((exc.type & window.filterParams.exType) !== 0) && ((exc.VertExcitationKind & window.filterParams.exVertKind) !== 0) && allowT1) {
          if (!(keydic.has(key2))) {
            keydic.set(key2, exc.value)
          }
        }
      }
    }

    var sdic = new Map()
    for (const [key, sdat] of sdatdic) {
      for (const [key2, exval] of sdat) {
        if (!(sdic.has(key))) {
          sdic.set(key, [])
        }
        sdic.get(key).push(exval - ((sdatdic.has(refstr)) ? sdatdic.get(refstr).get(key2) : NaN))
      }
    }
    sdic.delete(refstr)
    var graphdat = []
    for (const [keystr, vals] of sdic) {
      row = $("<tr/>")
      key = JSON.parse(keystr)
      Reflect.setPrototypeOf(key, method.prototype)
      th = $("<th/>", { scope: "column" })
      const meth = key
      th.clone().text(meth.toString("\n").split('-').join('\u2011')).appendTo(row)
      const noNanVals = (vals.every((v) => Number.isNaN(v))) ? vals : (vals.filter((v) => !Number.isNaN(v)))
      const avals = noNanVals.map(v => Math.abs(v))
      th.clone().text(noNanVals.length).appendTo(row)
      for (const val of [ss.min(noNanVals), ss.max(noNanVals), ss.mean(noNanVals), ss.mean(avals), ss.median(noNanVals), ss.median(avals), ss.rootMeanSquare(noNanVals), ss.variance(noNanVals), ss.standardDeviation(noNanVals)]) {
        $("<td/>").text(noNanFixed(val, 2)).appendTo(row)
      }
      $(stb).append(row)
      var box = {
        x: noNanVals,
        amean: ss.mean(avals).toFixed(3),
        name: key.toString() + " MAD : " + ss.mean(avals).toPrecision(4),
        type: 'box',
        boxmean: 'sd'
      };
      graphdat.push(box)
    }
    var layout = {
      paper_bgcolor: 'rgba(0,0,0,0)',
      plot_bgcolor: 'rgba(0,0,0,0)',
      gap: 0,
      legend: {
        traceorder: 'reversed',
      },
      xaxis: {
        title: {
          text: 'Energy (eV)',
        }
      },
      bgcolor: '#E2E2E2',
      bordercolor: '#FFFFFF',
      borderwidth: 2,
      // autosize: false,
      width: 850,
      height: 500,
      margin: {
        l: 0,
        r: 10,
        b: 15,
        t: 20,
        pad: 0,
      },
    }
    Plotly.newPlot('graph_div', graphdat, layout);
    processingIndicator.isActive = false
  }
  async function reloadContent() {
    window.filterParams = {
      unsafe: $("#cb_unsafe").prop("checked"),
      exType: Array.from(Array.from($("#cb_exTypeList>li>input[type=checkbox]:checked")).map(el => parseInt(el.value))).reduce((pv, cv) => pv + cv, 0),
      exVertKind: Array.from(Array.from($("#cb_exVertKindList>li>input[type=checkbox]:checked")).map(el => parseInt(el.value))).reduce((pv, cv) => pv + cv, 0),
      T1: {
        min: parseFloat($("#T1min").val()),
        max: parseFloat($("#T1max").val())
      }
    }
    doiCache.clear()
    processingIndicator.isActive = true
    window.filtData = window.dats
    getAllSelect().each(function () {
      const prop = $(this).attr("name")
      const values = getAllVals(this)
      window.filtData = window.filtData.filter((d) => {
        if (typeof values == "undefined" || values == null) {
          return false
        }
        return values.includes(getSelectValue(d, prop))
        delete (val)
      })
    })
    window.T1ref = new Map()
    var dois = new Set(window.filtData.map((d) => d.DOI === null ? "" : d.DOI.string))
    var mols = new Set(window.filtData.map((d) => d.molecule))
    await window.doiCache.addRange(dois)
    for (const doi of dois) {
      window.T1ref.set(doi, new Map())
      for (const mol of mols) {
        window.T1ref.get(doi).set(mol, new Map())
        var TBESortdat = window.dats.filter(d => (d.DOI === null ? "" : d.DOI.string) === doi && d.molecule === mol).sort((d1, d2) => {
          if (d1.method.isTBE && !d2.method.isTBE) {
            return -1
          } else if (!d1.method.isTBE && d2.method.isTBE) {
            return 1
          } else if (d1.method.isTBE && d2.method.isTBE) {
            if (d1.method.name === "TBE(FC)" && d2.method.name === "TBE") {
              return -1
            } else if (d1.method.name === "TBE" && d2.method.name === "TBE(FC)") {
              return 1
            }
            else {
              return 0
            }
          }
        })
        if (TBESortdat.length > 0 && TBESortdat[0].method.isTBE) {
          for (const exc of TBESortdat[0].excitations) {
            window.T1ref.get(doi).get(mol).set(JSON.stringify((exc.initial, exc.final)), exc.T1)
          }
        }
      }
    }
    $(sel_ref).empty()
    for (const el of uniq(window.filtData.map(d => [d.method, (d.DOI === null ? null : d.DOI.string)]))) {
      op = $("<option/>", {
        value: JSON.stringify(el)
      }).text(el[0])
      if (el[0].name.includes("TBE")) {
        $(sel_ref).prepend(op)
      }
      else {
        $(sel_ref).append(op)
      }
    }
    $(sel_ref).prop("selectedIndex", 0);
    var data = $("#data")
    $(data).empty();
    if (window.filtData.length > 0) {
      var publis = await publiDB.loadAsync()
      var PreviousSetName = undefined
      var CurrentsetName = undefined
      for (const doi of doiCache.keys()) {
        paperdata = window.filtData.filter((d) => {
          return (d.DOI === null ? "" : d.DOI.string) == doi
        })
        var methods = uniq(paperdata.map(d => d.method))
        const sortedMethods = methods.sort((a, b) => {
          if (a.isTBE && !b.isTBE) {
            return -1
          }
          else if (a.isTBE && b.isTBE) {
            if (a.basis !== "CBS" && b.basis === "CBS") {
              return -1
            }
            else {
              return 1
            }
          }
          else if (!a.isTBE && b.isTBE) {
            return 1
          }
          else {
            return 0
          }
        })
        var div = $('<div/>').appendTo(data)
        CurrentsetName = publis.findSetNameFromDOI(doi, true)
        if (PreviousSetName !== CurrentsetName) {
          $("<h1/>").text(CurrentsetName).appendTo(div)
        }
        const doiDat = doiCache.get(doi).format('data', { format: 'object' })[0]
        $("<h2/>").append($("<a>",{href:doiDat.URL,target:"_blank"}).text(doiDat.title)).appendTo(div)
        var table = $("<table/>").addClass("datatable").appendTo(div)
        var head = $("<tr/>")
        $("<thead/>").addClass("sticky").append(head).appendTo(table)
        var tbody = $("<tbody/>").appendTo(table)
        var th = $("<th/>", { scope: "column" })
        head.append(["Molecule", "Transition"].map(x => th.clone().text(x)))
        head.append(sortedMethods.map(x => th.clone().text(x.toString("\n").split('-').join('\u2011'))))
        adjustSticky();
        datadic = new Map()
        for (const dat of paperdata) {
          const key1 = dat.molecule;
          const myT1s = T1ref.get(dat.DOI == null ? "" : dat.DOI.string).get(dat.molecule)
          if (!datadic.has(key1)) {
            datadic.set(key1, new Map())
          }
          const key3 = JSON.stringify(dat.method)
          for (const ex of dat.excitations) {
            Reflect.setPrototypeOf(ex.type, excitationType.prototype)
            var allowT1 = false
            const T1Key = JSON.stringify((ex.initial, ex.final))
            const T1range = filterParams.T1
            if (T1range.min === 0 && T1range.max === 100) {
              allowT1 = true
            } else if (myT1s.has(T1Key)) {
              const T1Val = myT1s.get(T1Key)
              if (T1range.min <= T1Val && T1Val <= T1range.max) {
                allowT1 = true
              }
            }
            if (((window.filterParams.exType & ex.type) !== 0) && ((window.filterParams.exVertKind & ex.VertExcitationKind) !== 0) && allowT1) {
              const key2 = JSON.stringify([ex.initial, ex.final, ex.type, ex.VertExcitationKind])
              if (!datadic.get(key1).has(key2)) {
                datadic.get(key1).set(key2, new Map())
              }
              datadic.get(key1).get(key2).set(key3, [ex.value, ex.isUnsafe])
            }
          }
        }
        for (const [molecule, moldat] of datadic.entries()) {
          var printmol = true;
          const mhchemCE = /^\\ce\{.*\}$/
          for (const [jsonex, exdat] of moldat.entries()) {
            const ex = JSON.parse(jsonex)
            Reflect.setPrototypeOf(ex[0], state.prototype)
            Reflect.setPrototypeOf(ex[1], state.prototype)
            Reflect.setPrototypeOf(ex[2], excitationType.prototype)
            Reflect.setPrototypeOf(ex[3], VertExcitationKind.prototype)
            var tr = $("<tr/>")
            if (printmol) {
              $("<th/>", { scope: "row", rowspan: moldat.size }).text((mhchemCE.test(molecule) ? MathJaxUtils.getMathJaxString(molecule.toString()) : molecule)).appendTo(tr)
              printmol = false
            }
            var Vertkindtext = ""
            if (ex[3].Value == VertExcitationKinds.Fluorescence.Value) {
              Vertkindtext = String.raw`[\mathrm{F}]`
            }
            desctex = ""
            if (ex[2].description.string) {
              desctex = "(" + ex[2].description.string + ")"
            }
            $("<th/>", { scope: "rowgroup" }).text(MathJaxUtils.getMathJaxString(String.raw`${ex[0].toLaTeX()} \rightarrow ${ex[1].toLaTeX()} ${Vertkindtext} ${desctex}`)).appendTo(tr)
            var entries = Array.from(exdat.entries())
            for (const method of sortedMethods) {
              td = $("<td/>").addClass("NumberCell")
              kv = entries.find(x => {
                return JSON.stringify(method) == x[0]
              })
              if (kv !== undefined) {
                const [val, unsafe] = kv[1]
                if (unsafe) {
                  td.append($("<span/>", { title: "unsafe value", role: "img", "aria-label": "Warning" }).addClass("emoji").text('⚠'))
                }
                if (unsafe && !filterParams.unsafe) {
                  td.append($("<s/>").append(val.toString()))
                }
                else {
                  td.append(val.toString())
                }
              }
              tr.append(td)
            }
            tbody.append(tr)
          }
        }
        PreviousSetName === CurrentsetName
      }
      await MathJax.typesetPromise()
    }
    await reloadRef()
  }
  async function reloadRef() {
    $(sel_ref).empty()
    for (const el of uniq(window.filtData.map(d => d.method))) {
      op = $("<option/>", {
        value: JSON.stringify(el)
      }).text(el)
      if (el.name.includes("TBE")) {
        $(sel_ref).prepend(op)
      }
      else {
        $(sel_ref).append(op)
      }
    }
    $(sel_ref).prop("selectedIndex", 0);
    $(sel_ref).trigger("change")
  }
  async function submitdat() {
    if (!DebugMode.Enabled) {
      window.onbeforeunload = () => { return ''; }
      window.onbeforeunload = () => { return ''; }
      window.onbeforeunload = () => { return ''; }
    }
    await reloadContent();
  }
</script>
{{< getDataFilesName >}}
<noscript>
  <p style="background-color: red; color: white; font-size: 20; font-weight: bold;">
    <span role="img" aria-label="Warning" class="emoji">⚠</span>
    <span>This website work only if JavaScript is enable. You must enable
      JavaScript.
      <a href="https://www.enable-javascript.com/" target="_blank">How to enable JavaScript ?</a></span>
  </p>
</noscript>
<p>
  On this page you can compare multiple dataset and have some statistics to evaluate method accuracy (All fields marked
  with a red asterisk (<span style="color: red;">*</span>) are mandatory).
</p>
<form id="form_dat" action="javascript:submitdat()" method="post">
  <fieldset class="main">
    <fieldset>
      <legend>Import custom files</legend>
      <p>
        Import custom files to compare it's data to the reference datasets.
      </p>
      <div>
        <label for="absFiles_input">Import custom absorption data files</label>
        <input type="file" multiple onchange="reloadCustomFiles()" id="absFiles_input" name="file_abs"></input>
      </div>
      <div>
        <label for="fluoFiles_input">import custom fluorescence data files</label>
        <input type="file" multiple onchange="reloadCustomFiles()" id="fluoFiles_input" name="file_fluo"></input>
      </div>
    </fieldset>
    <fieldset class="table">
      <legend>Data selection</legend>
      <p>Choose each parameter (of course you can select multiple values for each) you can use the <button
          disabled>Select all</button> button to select all items <span hidden
          data-needbrowser='{"Engine":["WebKit","Blink"],"Platform":["desktop"]}'>or use the <kbd
            data-needbrowser='{"OS":["MacOS"]}'>⌘</kbd><kbd
            data-neednotbrowser='{"OS":["MacOS"]}'>Ctrl</kbd>+<kbd>A</kbd> shortcut key</span>
      </p>
      <div style="display: inline-block;">
        <label for="DOI_select" class="required">Sets</label>
        <button class="SelectAll" type="button" onclick="selectSelectAll_click(event)">Select all</button>
        <select multiple id="DOI_select" required name="DOI" onchange="reloadNextSelect(event)"></select>
      </div>
      <div style="display:inline-block">
        <label for="mol_select" class="required">Molecules</label>
        <button class="SelectAll" type="button" onclick="selectSelectAll_click(event)">Select all</button>
        <select multiple id="mol_select" required name="molecule" onchange="reloadNextSelect(event)"></select>
      </div>
      <br />
      <div style="display: inline-block;">
        <label for="method_select" class="required">Methods</label>
        <button class="SelectAll" type="button" onclick="selectSelectAll_click(event)">Select all</button>
        <select multiple id="method_select" required name="method" onchange="reloadNextSelect(event)"></select>
      </div>
      <div style="display: inline-block;">
        <label for="basis_select" class="required">Basis sets</label>
        <button class="SelectAll" type="button" onclick="selectSelectAll_click(event)">Select all</button>
        <select multiple id="basis_select" required name="basis" onchange="reloadNextSelect(event)"></select>
      </div>
    </fieldset>
    <fieldset>
      <legend class="required">Vertical excitation kind</legend>
      <p>Choose what kind of vertical excitations you want</p>
      <ul class="nestedCbList" style="padding-left: 0em;">
        <li>
          <input type="checkbox" data-onerequired="true" checked onchange="nestedCheckbox_change(event)"
            id="cb_fileType_All"></input>
          <label for="cb_fileType_All"> All</label>
        </li>
        <ul class="nestedCbList" id="cb_exVertKindList">
          <li>
            <input type="checkbox" onchange="nestedCheckbox_change(event)" id="cb_abs" value="1" name="datatype">
            <label for="cb_abs">Absorption</label>
          </li>
          <li>
            <input type="checkbox" onchange="nestedCheckbox_change(event)" id="cb_fluo" value="2" name="datatype">
            <label for="fluo">Fluorescence</label>
          </li>
        </ul>
      </ul>
    </fieldset>
    <fieldset id="excitationFilter">
      <legend class="required">Filters</legend>
      <p>Choose other excitation parameters you want</p>
      <ul class="nestedCbList" style="padding-left: 0em;">
        <li>
          <input type="checkbox" data-onerequired="true" onchange="nestedCheckbox_change(event)"
            id="cb_exType_All"></input>
          <label for="cb_exType_All"> All</label>
        </li>
        <ul id="cb_exTypeList" class="nestedCbList">
        </ul>
        <p>Choose if you want to include unsafe values in statistics</p>
        <li id="li_cb_unsafe">
          <input type="checkbox" id="cb_unsafe" name="unsafe">
          <label for="cb_unsafe">Unsafe</label>
        </li>
    </fieldset>
    <fieldset>
      <legend>\(\mathrm{\%T_1}\)</legend>
      <p>Chose the range of \(\mathrm{\%T_1}\) range using the two number box</p>
      <input class="range min" airia-label="Minimum value" type="number" id="T1min" onchange="numberRangeChange(event)"
        min="0" value="0">
      <span>\(\leq \mathrm{\%T_1} \leq\)</span>
      <input class="range max" airia-label="Maximum value" type="number" id="T1max" onchange="numberRangeChange(event)"
        max="100" value="100">
    </fieldset>
  </fieldset>
  <input type="submit" value="Load"></input>
</form>
<form id="form_ref">
  <fieldset class="main">
    <fieldset>
      <legend>statistics</legend>
      <p>Select a reference from <strong>already selected data</strong> (by default first is selected -it's the <abbr
          title="Theoretical best estimate">TBE</abbr> if present- is already selected)</p>
      <label for="sel_ref">Reference</label>
      <select id="sel_ref" onchange="reloadStat()"></select>
    </fieldset>
  </fieldset>
</form>
<p>Now you can see the list of selected data and some statistics about these data</p>
<section id="data">
</section>
<section>
  <table id="stat_table" class="datatable">
    <thead class="sticky">
      <th scope="col">Method</th>
      <th scope="col">Count</th>
      <th scope="col">Min</th>
      <th scope="col">Max</th>
      <th scope="col"><abbr title="Mean signed error">MSE</abbr></th>
      <th scope="col"><abbr title="Mean absolute error">MAE</abbr></th>
      <th scope="col">Median</th>
      <th scope="col">Absolute Median</th>
      <th scope="col"><abbr title="Root-mean square error ">RMSE</abbr></th>
      <th scope="col">Variance</th>
      <th scope="col"><abbr title="Standard deviation of the errors">SDE</abbr></th>
    </thead>
    <tbody>
    </tbody>
    <div id="graph_div"></div>
  </table>
</section>
{{< waitModal >}}