import {
  schemeCategory20
} from "./chunk-V2OJLJSK.js";
import {
  appear2 as appear,
  axisstyle,
  disappear2 as disappear,
  export_data,
  flyindi,
  font,
  make_table_2col,
  newpane,
  to_svg
} from "./chunk-SA7APTJR.js";
import "./chunk-HJ6L54YS.js";
import "./chunk-LSEFWW72.js";
import "./chunk-SKREEF3H.js";
import {
  Menu
} from "./chunk-HYOEWQ5P.js";
import "./chunk-HBW42TDT.js";
import "./chunk-G6O3URDN.js";
import "./chunk-FN5XPUPH.js";
import "./chunk-IIT367QZ.js";
import "./chunk-RZGEKL77.js";
import "./chunk-UI7OCM2A.js";
import "./chunk-YZK37YCC.js";
import "./chunk-7EMWHCVW.js";
import "./chunk-7IYJZZQI.js";
import "./chunk-M3J4MINX.js";
import {
  stratinput
} from "./chunk-PF4DSFDR.js";
import "./chunk-QH6W3NVF.js";
import "./chunk-NOEAT6CX.js";
import "./chunk-4UWS5Y3N.js";
import "./chunk-DD4R5P6W.js";
import "./chunk-JNITUVXP.js";
import {
  arc_default
} from "./chunk-KSGA62R2.js";
import {
  axisTop
} from "./chunk-LOZEKOES.js";
import {
  hierarchy,
  partition_default,
  stratify_default
} from "./chunk-TOU7EVFQ.js";
import {
  linear,
  log,
  ordinal
} from "./chunk-OAWQ6LOO.js";
import "./chunk-TLT4YIG3.js";
import "./chunk-KYBIQBXE.js";
import {
  pointer_default,
  select_default
} from "./chunk-I6Y4O3RR.js";
import {
  rgb
} from "./chunk-OMR2DT66.js";
import "./chunk-DQC5FFGV.js";
import "./chunk-HFNDKYVF.js";

// src/ep.sun.js
function burst(ep, val1, val2) {
  if (!ep.p.cohort) {
    return;
  }
  ep.grab.min = Math.min(val1, val2);
  ep.grab.max = Math.max(val1, val2);
  let elst = ep.data.filter((i) => i.value >= ep.grab.min && i.value <= ep.grab.max);
  if (elst.length == 0) {
    if (ep.grab.sun) {
      ep.grab.sun.g.remove();
    }
    return;
  }
  if (ep.p.cohort.annotation) {
    const lst = [];
    for (const s of elst) {
      const s2 = {};
      for (const k in s) {
        if (k != "circle") {
          s2[k] = s[k];
        }
      }
      const sanno = ep.p.cohort.annotation[s[ep.p.sampletype]];
      if (sanno) {
        for (const k in sanno) {
          s2[k] = sanno[k];
        }
      }
      lst.push(s2);
    }
    elst = lst;
  }
  const grab = ep.grab;
  if (grab.sun) {
    grab.sun.g.remove();
  } else {
    grab.sun = {
      x: 0,
      y: 0
    };
  }
  const sun = grab.sun;
  sun.g = grab.holder.append("g").attr("transform", "translate(" + sun.x + "," + sun.y + ")").on("mouseover", () => {
    ep.dottip.hide();
  });
  let numsamplewithlevel1 = 0;
  for (const s of elst) {
    if (s[ep.p.cohort.levels[0].k] != void 0) {
      numsamplewithlevel1++;
    }
  }
  if (numsamplewithlevel1 == 0) {
    sun.g.append("text").text("0/" + elst.length).attr("font-size", 40).attr("font-family", font).attr("stroke", "white").attr("stroke-width", 3).attr("text-anchor", "middle");
    sun.g.append("text").text("0/" + elst.length).attr("font-size", 40).attr("font-family", font).attr("fill", ep.p.hlcolor).attr("text-anchor", "middle").attr("fill-opacity", 0.8).on("click", () => {
      removesun(sun, grab, ep);
    });
    return;
  }
  if (ep.samplecart) {
    grab.selectedsamples = elst.map((d2) => d2.sample_name ? d2.sample_name : d2.sample);
    ep.samplecart.setBtns({
      samplelst: grab.selectedsamples,
      basket: "Gene Expression",
      id: ep.genename + (!ep.grab || !elst.length ? "" : " FPKM:" + ep.grab.min + "-" + ep.grab.max),
      container: ep.samplecartWrapper,
      reselectable: true
    });
  }
  const radius = Math.min(ep.width, ep.height) * 0.3;
  const bgpocket = sun.g.append("g");
  let bgpocketrad;
  let emptyspace;
  const arcfunc = arc_default().startAngle((d2) => d2.x0).endAngle((d2) => d2.x1).innerRadius((d2) => {
    if (!d2.parent) {
      emptyspace = Math.sqrt(d2.y1) - radius / 15;
      return emptyspace;
    }
    return Math.sqrt(d2.y0);
  }).outerRadius((d2) => {
    d2.outradius = Math.sqrt(d2.y1);
    if (d2.parent && !d2.parent.parent) {
      bgpocketrad = d2.outradius;
    }
    return d2.outradius;
  });
  const nodes = stratinput(elst, ep.p.cohort.levels);
  const root = stratify_default()(nodes);
  root.sum((d2) => d2.value);
  root.sort((a2, b2) => b2.value - a2.value);
  partition_default().size([Math.PI * 2, radius * radius])(root);
  sun.ring = sun.g.selectAll().data(root.descendants()).enter().append("path").attr("d", arcfunc).attr("stroke", "white").attr("fill-opacity", 1).attr("fill-rule", "evenodd").attr("fill", (d2) => {
    if (!d2.parent) return "white";
    let name;
    if (d2.children) {
      name = d2.id;
    } else {
      if (!d2.parent.parent) {
        name = d2.id;
      } else {
        name = d2.parent.id;
      }
    }
    d2._color = ep.p.cohort.suncolor(name);
    return d2._color;
  }).on("mouseover", (event, d2) => {
    if (!d2.parent) return;
    setnamesays.text(d2.data.name);
    setnamesaysbg.text(d2.data.name);
    numsays.text(d2.value);
    datatypesays.text(d2.data.full || "");
    event.target.setAttribute("fill", rgb(d2._color).darker(0.5).toString());
  }).on("mouseout", (event, d2) => {
    setnamesays.text(grab.min + " - " + grab.max).attr("font-size", setnamefontsize);
    setnamesaysbg.text(grab.min + " - " + grab.max).attr("font-size", setnamefontsize);
    numsays.text(numsamplewithlevel1 == elst.length ? elst.length : numsamplewithlevel1 + "/" + elst.length);
    datatypesays.text(ep.p.datatype);
    event.target.setAttribute("fill", d2._color);
  }).on("click", (event, d2) => {
    if (!ep.samplecart) {
      return;
    }
    const lst = [];
    for (const s of d2.data.lst) {
      lst.push(s.sample_name ? s.sample_name : s.sample);
    }
    ep.samplecart.setBtns({
      samplelst: lst,
      basket: "Gene Expression",
      note: d2.data.name + " samples with " + ep.genename + " " + ep.p.datatype + " between " + ep.grab.min + " and " + ep.grab.max,
      id: ep.genename + (!ep.grab || !d2.data.lst.length || !d2.data.lst[0] ? "" : " FPKM:" + ep.grab.min + "-" + ep.grab.max) + " " + d2.data.lst[0].ancestor_dx,
      container: ep.samplecartWrapper,
      reselectable: true
    });
  });
  bgpocket.append("circle").attr("r", bgpocketrad).attr("fill", "white").attr("fill-opacity", 0.7);
  const a = [], b = [], c = [], d = [];
  for (const i of root.leaves()) {
    const r = (i.x0 + i.x1) / 2;
    if (r <= Math.PI / 2) a.push(i);
    else if (r <= Math.PI) b.push(i);
    else if (r <= Math.PI * 1.5) c.push(i);
    else d.push(i);
  }
  a.sort((a2, b2) => b2.x0 - a2.x0);
  b.sort((a2, b2) => a2.x0 - b2.x0);
  c.sort((a2, b2) => b2.x0 - a2.x0);
  d.sort((a2, b2) => a2.x0 - b2.x0);
  const palst = [...a, ...b, ...c, ...d];
  const lefth = [];
  const righth = [];
  const fontsize = Math.max(13, ep.dotsize * 0.7);
  sun.g.selectAll().data(palst).enter().append("text").text(
    (d2) => (d2.parent.data.name ? d2.parent.data.name == "root" ? "" : d2.parent.data.name + ", " : "") + d2.data.name
  ).attr("font-size", fontsize).attr("font-family", font).attr("stroke", "white").attr("stroke-width", 3).attr("fill", "none").each(function(d2) {
    const texth = this.getBBox().height;
    const a2 = (d2.x0 + d2.x1) / 2;
    let rr = radius + 5;
    let y0 = -rr * Math.cos(a2);
    if (a2 <= Math.PI) {
      let nf = true;
      for (const h of righth) {
        if (y0 >= h[0] && y0 <= h[1]) {
          nf = false;
          if (a2 <= Math.PI / 2) {
            y0 = h[0] - 2;
            rr = -y0 / Math.cos(a2);
            h[0] = y0 - texth;
          } else {
            y0 = 2 + h[1];
            rr = -y0 / Math.cos(a2);
            h[1] = y0 + texth;
          }
          break;
        }
      }
      if (nf) {
        if (a2 <= Math.PI / 2) {
          righth.push([y0 - texth, y0]);
        } else {
          righth.push([y0, y0 + texth]);
        }
      }
    } else {
      let nf = true;
      for (const h of lefth) {
        if (y0 >= h[0] && y0 <= h[1]) {
          nf = false;
          if (a2 <= Math.PI * 1.5) {
            y0 = 2 + h[1];
            rr = -y0 / Math.cos(a2);
            h[1] = y0 + texth;
          } else {
            y0 = h[0] - 2;
            rr = -y0 / Math.cos(a2);
            h[0] = y0 - texth;
          }
          break;
        }
      }
      if (nf) {
        if (a2 <= Math.PI * 1.5) {
          lefth.push([y0, y0 + texth]);
        } else {
          lefth.push([y0 - texth, y0]);
        }
      }
    }
    d2.labely = y0;
    d2.labelx = rr * Math.sin(a2);
  }).attr("x", (d2) => d2.labelx).attr("y", (d2) => d2.labely).attr("text-anchor", (d2) => (d2.x0 + d2.x1) / 2 <= Math.PI ? "start" : "end").attr("dominant-baseline", (d2) => {
    var a2 = (d2.x0 + d2.x1) / 2;
    if (a2 <= Math.PI / 2 || a2 >= Math.PI * 1.5) return "";
    return "hanging";
  });
  sun.g.selectAll().data(palst).enter().append("text").text((d2) => (d2.parent.parent ? d2.parent.data.name + ", " : "") + d2.data.name).attr("font-size", fontsize).attr("font-family", font).attr("fill", "#858585").attr("x", (d2) => d2.labelx).attr("y", (d2) => d2.labely).attr("text-anchor", (d2) => (d2.x0 + d2.x1) / 2 <= Math.PI ? "start" : "end").attr("dominant-baseline", (d2) => {
    var a2 = (d2.x0 + d2.x1) / 2;
    if (a2 <= Math.PI / 2 || a2 >= Math.PI * 1.5) return "";
    return "hanging";
  });
  sun.g.selectAll().data(palst).enter().append("line").attr("x1", (d2) => d2.outradius * Math.sin((d2.x0 + d2.x1) / 2)).attr("y1", (d2) => -d2.outradius * Math.cos((d2.x0 + d2.x1) / 2)).attr("x2", (d2) => d2.labelx).attr("y2", (d2) => d2.labely).attr("stroke", "#858585");
  const bigfont = Math.max(18, emptyspace * 0.6);
  const smallfont = Math.max(14, emptyspace * 0.2);
  let y = -3;
  let setnamefontsize;
  let w;
  const sampletypesays = sun.g.append("text").text(ep.p.sampletype.toUpperCase()).attr("font-size", smallfont).attr("font-family", font).attr("y", -bigfont).attr("fill", ep.p.hlcolor).attr("text-anchor", "middle");
  const numsays = sun.g.append("text").text(numsamplewithlevel1 == elst.length ? elst.length : numsamplewithlevel1 + "/" + elst.length).attr("font-size", bigfont).attr("font-family", font).attr("y", y).attr("fill", ep.p.hlcolor).attr("text-anchor", "middle").attr("fill-opacity", 0.8);
  y = 5;
  const datatypesays = sun.g.append("text").text(ep.p.datatype).attr("font-size", smallfont).attr("font-family", font).attr("y", y).attr("dominant-baseline", "hanging").attr("text-anchor", "middle").attr("fill", "#b5b5b5");
  const text = grab.min + " - " + grab.max;
  const sf = linear().domain([5, 15]).range([emptyspace, emptyspace * 2]);
  const setnamesaysbg = sun.g.append("text").text(text).attr("font-size", 1).each(function() {
    var b2 = this.getBBox();
    setnamefontsize = Math.min(sf(text.length) / b2.width, emptyspace * 0.4 / b2.height);
  }).attr("font-size", setnamefontsize).attr("font-family", font).attr("y", y + smallfont).attr("dominant-baseline", "hanging").attr("text-anchor", "middle").attr("stroke", "white").attr("stroke-width", 3).attr("fill", "none");
  const setnamesays = sun.g.append("text").text(text).attr("font-size", setnamefontsize).attr("font-family", font).attr("y", y + smallfont).attr("dominant-baseline", "hanging").attr("text-anchor", "middle").attr("fill", "#858585");
  sun.g.append("circle").attr("r", emptyspace + radius / 15).attr("fill", "white").attr("fill-opacity", 0).on("click", () => {
    if (sun.busy) return;
    removesun(sun, grab, ep);
  }).on("mousedown", (event) => {
    const x0 = sun.x, y0 = sun.y, mx = event.clientX, my = event.clientY, body = select_default(document.body);
    body.on("mousemove", (event2) => {
      event2.preventDefault();
      sun.busy = true;
      sun.x = x0 + event2.clientX - mx;
      sun.y = y0 + event2.clientY - my;
      sun.g.attr("transform", "translate(" + sun.x + "," + sun.y + ")");
    }).on("mouseup", () => {
      body.on("mousemove", null).on("mouseup", null);
      setTimeout(() => sun.busy = false, 10);
    });
  });
}
function removesun(sun, grab, ep) {
  if (sun.ring) {
    sun.ring.transition().attr("fill-opacity", 0);
  }
  sun.g.transition().attr("transform", "scale(.5,.5)").on("end", () => {
    sun.g.remove();
    grab.shade.attr("transform", "translate(0,1000)");
  });
  grab.shadebox.transition().duration(500).attr("stroke-opacity", 0).attr("fill-opacity", 0);
  grab.shadehandle1.transition().duration(500).attr("fill-opacity", 0);
  grab.shadehandle2.transition().duration(500).attr("fill-opacity", 0);
  delete grab.x;
  if (ep.selectsample_button) {
    ep.selectsample_button.style("display", "none").text("");
  }
}

// src/ep.boxplot.js
function newboxplot(ep, data, label, id, handle) {
  for (const bp of ep.boxplots) {
    if (bp.id == id) return;
  }
  handle.style("border-color", ep.boxcolor);
  for (const bp of ep.boxplots) {
    bp.highlight = false;
    bp.label.attr("fill", ep.boxcolor);
    bp.label2.attr("fill", ep.boxcolor);
  }
  let free = [[0, ep.height]];
  for (const bp of ep.boxplots) {
    const y2 = bp.yoff;
    const h = bp.height;
    for (const i of free) {
      if (Math.max(y2, i[0]) < Math.min(y2 + h, i[1])) {
        if (y2 + h < i[1]) {
          free.push([y2 + h + 1, i[1]]);
        }
        i[1] = y2 - 1;
      }
    }
  }
  const labelfontsize = ep.sf_boxlabelfontsize(Math.log(data.length));
  const boxheight = ep.sf_boxheight(data.length);
  let y = 0;
  for (const s of free) {
    if (s[1] - s[0] > Math.max(boxheight, labelfontsize)) {
      y = s[0] + 3;
      break;
    }
  }
  const holder = ep.boxbag.append("g").attr("transform", "translate(0," + y + ")");
  const box = {
    labeltext: label,
    lst: data,
    holder,
    yoff: y,
    highlight: false,
    id,
    handle,
    height: Math.max(boxheight, labelfontsize),
    lookuphash: {}
  };
  for (const d of data) {
    box.lookuphash[d[ep.p.sampletype]] = 1;
  }
  ep.boxplots.push(box);
  const p9 = data[Math.floor((data.length - 1) * 0.91)].value, p25 = data[Math.floor((data.length - 1) * 0.75)].value, p50 = data[Math.floor((data.length - 1) * 0.5)].value, p75 = data[Math.floor((data.length - 1) * 0.25)].value, p91 = data[Math.floor((data.length - 1) * 0.09)].value;
  box.percentile = {
    9: p9 == 0 ? 1e-4 : p9,
    25: p25 == 0 ? 1e-4 : p25,
    50: p50 == 0 ? 1e-4 : p50,
    75: p75 == 0 ? 1e-4 : p75,
    91: p91 == 0 ? 1e-4 : p91
  };
  box.hline = holder.append("line").attr("y1", boxheight / 2).attr("y2", boxheight / 2).attr("stroke", ep.boxcolor).attr("stroke-dasharray", "5,3").attr("shape-rendering", "crispEdges");
  box.hline.transition().duration(ep.dur).attr("x1", Math.max(0, ep.x_scale(p9))).attr("x2", Math.max(0, ep.x_scale(p91)));
  box.label = holder.append("text").attr("y", boxheight / 2).attr("font-size", labelfontsize).attr("font-family", font).attr("text-anchor", "end").attr("dominant-baseline", "middle").attr("fill", box.highlight ? ep.p.hlcolor : ep.boxcolor).style("cursor", "default").text(label).on("mousedown", (event) => boxplot_md(ep, box, event)).on("click", () => boxplot_clicklabel(ep, box)).each(function() {
    box.labelwidth = this.getBBox().width;
  }).attr("x", ep.width + ep.width2 + box.labelwidth);
  box.label.transition().duration(ep.dur).attr("x", ep.width + ep.width2 - ep.width2_ - 3);
  box.label2 = holder.append("text").attr("x", ep.width + ep.width2 + box.labelwidth).attr("y", boxheight / 2).attr("font-size", labelfontsize).attr("font-family", font).attr("dominant-baseline", "middle").attr("fill", box.highlight ? ep.p.hlcolor : ep.boxcolor).style("cursor", "default").text(data.length).on("mousedown", () => boxplot_md(ep, box)).on("click", () => boxplot_clicklabel(ep, box));
  box.label2.transition().duration(ep.dur).attr("x", ep.width + ep.width2 - ep.width2_ + 3);
  box.connline = holder.append("line").attr("y1", boxheight / 2).attr("y2", boxheight / 2).attr("stroke", ep.boxcolor).attr("stroke-dasharray", "1,3").attr("shape-rendering", "crispEdges");
  box.connline.transition().duration(ep.dur).attr("x1", Math.max(0, ep.x_scale(box.percentile[91]))).attr("x2", Math.max(0, ep.width + ep.width2 - box.labelwidth - ep.width2_ - 3));
  box.box = holder.append("rect").attr("height", boxheight).attr("shape-rendering", "crispEdges").attr("fill", "white").attr("stroke", ep.boxcolor).on("click", () => boxplotremove(ep, box)).on("mousedown", (event) => {
    const t = event.target;
    t.setAttribute("fill", "#FFeeee");
    t.setAttribute("stroke", "#D10000");
  }).on("mouseover", (event) => {
    ep.dottip.show(event.clientX, event.clientY).clear();
    const lst = [
      { k: "Group", v: box.labeltext || "All samples" },
      { k: "1st quartile", v: box.percentile[25] },
      { k: "Median", v: box.percentile[50] },
      { k: "3rd quartile", v: box.percentile[75] }
    ];
    make_table_2col(ep.dottip.d.append("div"), lst);
  }).on("mouseout", () => {
    ep.dottip.hide();
  });
  box.box.transition().duration(ep.dur).attr("x", Math.max(0, ep.x_scale(box.percentile[25]))).attr("width", Math.max(0, ep.x_scale(box.percentile[75])) - Math.max(0, ep.x_scale(box.percentile[25])));
  box.vlines = holder.selectAll().data([box.percentile[9], box.percentile[25], box.percentile[50], box.percentile[75], box.percentile[91]]).enter().append("line").attr("x1", 0).attr("x2", 0).attr("y1", 0).attr("y2", boxheight).attr("stroke", ep.boxcolor).attr("shape-rendering", "crispEdges");
  box.vlines.transition().duration(ep.dur).attr("x1", (d) => Math.max(0, ep.x_scale(d))).attr("x2", (d) => Math.max(0, ep.x_scale(d)));
  if (label != "") {
    boxplot_clicklabel(ep, box);
  }
}
function boxplotremove(ep, arg) {
  let box = null;
  if (typeof arg == "object") {
    box = arg;
  } else {
    for (const b of ep.boxplots) {
      if (b.id == arg) box = b;
    }
  }
  if (!box) {
    console.log("cannot remove boxplot");
    return;
  }
  box.handle.style("border-color", "transparent");
  if (box.label.attr("fill") == ep.p.hlcolor) {
    boxplot_clicklabel(ep, box);
  }
  box.holder.transition().attr("transform", "translate(" + (ep.width + 20) + "," + box.yoff + ")").each(() => box.holder.remove());
  for (let i = 0; i < ep.boxplots.length; i++) {
    if (ep.boxplots[i].id == box.id) {
      ep.boxplots.splice(i, 1);
      return;
    }
  }
}
function boxplot_clicklabel(ep, box) {
  if (ep.busy) return;
  for (const b of ep.boxplots) {
    if (b.id != box.id) b.highlight = false;
  }
  box.highlight = !box.highlight;
  ep.epdot.transition().duration(1e3).attr("r", (d) => {
    if (d[ep.p.sampletype] in box.lookuphash) return box.highlight ? ep.dotsize * 0.7 : ep.dotsize / 2;
    return box.highlight ? ep.dotsize * 0.2 : ep.dotsize / 2;
  }).attr("stroke", (d) => {
    if (d[ep.p.sampletype] in box.lookuphash) return box.highlight ? ep.p.hlcolor : "black";
    return "black";
  }).attr("stroke-opacity", (d) => {
    if (d[ep.p.sampletype] in box.lookuphash) return box.highlight ? 0.4 : 0.2;
    return box.highlight ? 0.1 : 0.2;
  });
  for (const b of ep.boxplots) {
    b.label.attr("fill", b.highlight ? ep.p.hlcolor : ep.boxcolor);
    b.label2.attr("fill", b.highlight ? ep.p.hlcolor : ep.boxcolor);
  }
}
function boxplot_md(ep, box, event) {
  event.preventDefault();
  const y = event.clientY, oldboxy = box.yoff;
  const b = select_default(document.body);
  b.on("mousemove", (event2) => {
    ep.busy = true;
    box.yoff = oldboxy + event2.clientY - y;
    box.holder.attr("transform", "translate(0," + box.yoff + ")");
  }).on("mouseup", () => {
    b.on("mousemove", null).on("mouseup", null);
    setTimeout(() => ep.busy = false, 100);
  });
}

// src/ep.js
var minwidth = 300;
var maxwidth = 500;
var minheight = 400;
var maxheight = 700;
var hl_strokeopacity = 0.6;
var normal_strokeopacity = 0.2;
var EPaint = class {
  constructor(arg) {
    this.p = arg.expp;
    if (this.p.cohort) {
      if (!this.p.cohort.suncolor) {
        this.p.cohort.suncolor = ordinal(schemeCategory20);
      }
    }
    this.boxcolor = "#006600";
    this.boxplots = [];
    this.const_all = "All " + this.p.sampletype + "s";
    this.uselog = false;
    this.dotmoved = false;
    this.genename = arg.genename;
    this.presize = arg.presize;
    this.dsname = arg.dsname;
    this.genome = arg.genome;
    this.hostURL = arg.block ? arg.block.hostURL : arg.hostURL;
    this.samplecart = arg.samplecart;
    if (arg.block) {
      const p = arg.block.holder.node().getBoundingClientRect();
      this.presize = {
        x: p.left + arg.block.leftheadw + arg.block.width + 20,
        y: p.top,
        width: Math.min(maxwidth, Math.max(minwidth, document.body.scrollWidth - p.left - p.width - 100)),
        height: Math.min(maxheight, Math.max(minheight, document.body.clientHeight - 270))
      };
    }
    this.source = arg.source;
    this.data = arg.data;
    this.data.sort((a, b) => b.value - a.value);
    this.minvalue = 0;
    this.maxvalue = 0;
    if (this.data.length > 0) {
      this.minvalue = this.maxvalue = this.data[0].value;
    }
    this.sampletype2value = {};
    for (const d of this.data) {
      const v = d.value;
      this.minvalue = Math.min(this.minvalue, v);
      this.maxvalue = Math.max(this.maxvalue, v);
      this.sampletype2value[d[this.p.sampletype]] = v;
    }
    if (this.p.scaleminvalue != void 0) {
      this.minvalue = this.p.scaleminvalue;
    }
    this.pane = newpane({
      x: this.presize.x,
      y: this.presize.y
    });
    this.pane.pane.classed("sja_ep_pane", true);
    this.dottip = new Menu({ padding: "10px" });
    if (arg.block) {
      const closebut = select_default(this.pane.header.node().previousSibling);
      closebut.on("click", () => {
        this.epaintfold(arg.block);
      });
    }
    this.pane.body.style("padding", "10px");
    const error = (m) => {
      this.pane.body.append("p").text(m);
    };
    if (this.data.length == 0) {
      this.pane.header.text(this.p.name);
      error("No expression data for " + this.genename);
      return;
    }
    this.pane.header.text(this.genename + " " + this.p.name + (this.dsname ? " from " + this.dsname : ""));
    makeButtons(this);
    this.treediv = this.pane.body.append("div").style("display", "none").style("margin", "20px 0px 30px 0px").style("padding", "10px").style("background-color", "#FFFFE8");
    this.treediv.append("div").style("font-size", ".7em").style("color", "#858585").style("text-align", "center").text("Click on a row to show/hide boxplot");
    this.svg = this.pane.body.append("svg");
    if (this.samplecart) {
      this.samplecartWrapper = this.pane.body.append("div");
      this.samplecart.setBtns({
        samplelst: this.grab && this.grab.selectedsamples ? this.grab.selectedsamples : [],
        basket: "Gene Expression",
        id: this.genename + (!this.grab ? "" : " FPKM:" + this.grab.min + "-" + this.grab.max),
        container: this.samplecartWrapper,
        reselectable: true,
        replaceable: false
      });
    }
    this.pane.body.append("div").style("text-align", "right").append("span").text("drag to resize").attr("font-size", ".8em").attr("font-family", font).attr("class", "sja_clbtext").on("mousedown", (event) => {
      event.preventDefault();
      const x = event.clientX;
      const y = event.clientY;
      const width = this.width;
      const height = this.height;
      const b = select_default(document.body);
      b.on("mousemove", (e2) => {
        this.render(width + e2.clientX - x, height + e2.clientY - y);
      });
      b.on("mouseup", () => {
        b.on("mousemove", null).on("mouseup", null);
      });
    });
    this.sf_boxheight = linear().domain([0, this.data.length]);
    this.sf_boxlabelfontsize = linear();
    this.boxplots = [];
    if (this.svgg) {
      this.svgg.remove();
    }
    this.svgg = this.svg.append("g");
    this.axisg = this.svgg.append("g");
    this.grabbar = this.svgg.append("rect").attr("x", 0).attr("y", 0).attr("fill", "white").attr("fill-opacity", 0).on("mousedown", (event) => {
      if (!this.p.cohort) {
        console.log("no .p.cohort");
        return;
      }
      this.busy = true;
      const x = pointer_default(event, this.grabbar.node())[0];
      const val1 = Number.parseFloat(this.x_scale.invert(x).toFixed(1));
      this.grab.x = x;
      this.grab.width = 1;
      this.grab.shade.attr("transform", "translate(" + x + "," + this.grab.y + ")");
      this.grab.shadebox.attr("width", 2).attr("height", this.grab.height).attr("stroke-opacity", 0.7).attr("fill-opacity", 0.1);
      this.grab.shadehandle1.attr("fill-opacity", 0.5);
      this.grab.shadehandle2.attr("x", 2).attr("fill-opacity", 0.5);
      burst(this, val1, Number.parseFloat(this.x_scale.invert(x + 1).toFixed(1)));
      const b = select_default(document.body);
      b.on("mousemove", (event2) => {
        event2.preventDefault();
        let x2 = pointer_default(event2, this.grabbar.node())[0];
        x2 = Math.max(-this.dotsize, x2);
        x2 = Math.min(this.width + this.dotsize, x2);
        this.grab.width = Math.max(1, Math.abs(x2 - x));
        this.grab.shadebox.attr("width", this.grab.width);
        this.grab.shadehandle2.attr("x", this.grab.width);
        if (x2 < x) {
          this.grab.x = x2;
          this.grab.shade.attr("transform", "translate(" + this.grab.x + "," + this.grab.y + ")");
        }
        burst(this, val1, Number.parseFloat(this.x_scale.invert(x2).toFixed(1)));
      });
      b.on("mouseup", () => {
        this.busy = false;
        b.on("mousemove", null).on("mouseup", null);
      });
    });
    this.verticalline = this.svgg.append("line").attr("stroke", this.boxcolor).attr("stroke-opacity", 0.1).attr("shape-rendering", "crispEdges");
    this.dur = 2e3;
    this.boxbag = this.svgg.append("g");
    this.graph = this.svgg.append("g");
    this.sung = this.svgg.append("g");
    this.grab = {
      shade: this.sung.append("g"),
      holder: this.sung.append("g")
    };
    this.grab.shadebox = this.grab.shade.append("rect").attr("stroke", this.p.hlcolor).attr("stroke-width", 1).attr("fill", this.p.hlcolor).style("cursor", "move").on("mousedown", (event) => {
      if (!this.p.cohort) {
        return;
      }
      this.busy = true;
      let x = event.clientX;
      const b = select_default(document.body);
      b.on("mousemove", (event2) => {
        event2.preventDefault();
        const x2 = event2.clientX;
        this.grab.x += x2 - x;
        x = x2;
        this.grab.shade.attr("transform", "translate(" + this.grab.x + "," + this.grab.y + ")");
        burst(
          this,
          Number.parseFloat(this.x_scale.invert(this.grab.x).toFixed(1)),
          Number.parseFloat(this.x_scale.invert(this.grab.x + this.grab.width).toFixed(1))
        );
      }).on("mouseup", () => {
        this.busy = false;
        b.on("mousemove", null).on("mouseup", null);
      });
    });
    this.grab.shadehandle1 = this.grab.shade.append("rect").attr("x", -5).attr("width", 5).attr("height", 40).attr("fill", this.p.hlcolor).attr("fill-opacity", 0).style("cursor", "ew-resize").on("mousedown", (event) => {
      this.busy = true;
      let x = event.clientX;
      const b = select_default(document.body);
      b.on("mousemove", (event2) => {
        event2.preventDefault();
        const x2 = event2.clientX;
        this.grab.width += x - x2;
        if (this.grab.width <= 0) {
          this.grab.width -= x - x2;
          return;
        }
        this.grab.x += x2 - x;
        x = x2;
        this.grab.shade.attr("transform", "translate(" + this.grab.x + "," + this.grab.y + ")");
        this.grab.shadebox.attr("width", this.grab.width);
        this.grab.shadehandle2.attr("x", this.grab.width);
        burst(
          this,
          Number.parseFloat(this.x_scale.invert(this.grab.x).toFixed(1)),
          Number.parseFloat(this.x_scale.invert(this.grab.x + this.grab.width).toFixed(1))
        );
      }).on("mouseup", () => {
        this.busy = false;
        b.on("mousemove", null).on("mouseup", null);
      });
    });
    this.grab.shadehandle2 = this.grab.shade.append("rect").attr("x", 0).attr("width", 5).attr("height", 40).attr("fill", this.p.hlcolor).attr("fill-opacity", 0).style("cursor", "ew-resize").on("mousedown", (event) => {
      let x = event.clientX;
      const b = select_default(document.body);
      b.on("mousemove", (event2) => {
        event2.preventDefault();
        const x2 = event2.clientX;
        this.grab.width += x2 - x;
        if (this.grab.width <= 0) {
          this.grab.width -= x2 - x;
          return;
        }
        x = x2;
        this.grab.shadebox.attr("width", this.grab.width);
        this.grab.shadehandle2.attr("x", this.grab.width);
        burst(
          this,
          Number.parseFloat(this.x_scale.invert(this.grab.x).toFixed(1)),
          Number.parseFloat(this.x_scale.invert(this.grab.x + this.grab.width).toFixed(1))
        );
      }).on("mouseup", () => {
        this.busy = false;
        b.on("mousemove", null).on("mouseup", null);
      });
    });
    this.epdotg = this.graph.selectAll().data(this.data).enter().append("g");
    this.epdot = this.epdotg.append("circle").attr("fill", this.p.hlcolor).attr("fill-opacity", 0).attr("stroke", "black").attr("stroke-width", 2).attr("stroke-opacity", normal_strokeopacity).each(function(d) {
      d.circle = this;
    }).on("mouseover", (event, d) => {
      if (this.busy) return;
      d.circle.setAttribute("transform", "scale(1.5)");
      this.dottip.clear();
      const lst = [
        {
          k: this.p.datatype,
          v: '<span style="font-size:150%">' + d.value + "</span>"
        }
      ];
      if (this.p.attrlst) {
        for (const a of this.p.attrlst) {
          lst.push({
            k: a.label || a.k,
            v: d[a.k]
          });
        }
      }
      const cangetmore = this.getsampleinfo(d, lst);
      make_table_2col(this.dottip.d, lst).style("zoom", 0.7);
      this.dottip.show(event.clientX, event.clientY);
      if (cangetmore) {
        this.dottip.d.append("div").text("Full details").attr("class", "sja_menuoption").on("click", () => {
          samplefulldetail(d, this.p.cohort, event.clientX - 100, event.clientY - 100);
        });
      }
    }).on("mouseout", (event, d) => {
      d.circle.setAttribute("transform", "scale(1)");
    }).on("mousedown", (event, d) => {
      event.preventDefault();
      const y0 = event.clientY;
      const b = select_default(document.body);
      const median = this.data[Math.floor(this.data.length / 2)].value;
      if (d.value < median) {
        const inity = this.dotgraph_y;
        b.on("mousemove", (event2) => {
          this.busy = true;
          this.dotmoved = true;
          this.dotgraph_y = inity + event2.clientY - y0;
          this.graph.attr("transform", "translate(0," + this.dotgraph_y + ")");
        });
      } else {
        const inith = this.heightmove;
        b.on("mousemove", (event2) => {
          this.dotmoved = true;
          this.heightmove = inith + y0 - event2.clientY;
          const rowheight = this.heightmove / this.data.length;
          this.epdotg.attr("transform", (d2, i) => {
            d2._y = this.height - this.heightmove + i * rowheight;
            return "translate(" + Math.max(0, this.x_scale(d2.value)) + "," + d2._y + ")";
          });
        });
      }
      b.on("mouseup", () => {
        setTimeout(() => this.busy = false, 50);
        b.on("mousemove", null).on("mouseup", null);
      });
    });
    this.render();
    const allsamplerow = this.treediv.append("div").style("margin", "10px").style("padding", "2px").style("border", "solid 1px transparent").html("All samples&nbsp;&nbsp;" + this.data.length).attr("class", "sja_clb").on("click", () => {
      let nf = true;
      for (const b of this.boxplots) {
        if (b.id == "all") nf = false;
      }
      if (nf) {
        newboxplot(this, this.data, "", "all", allsamplerow);
      } else {
        boxplotremove(this, "all");
      }
    });
    if (this.p.cohort) {
      if (this.p.cohort && this.p.cohort.annotation && this.p.cohort.key4annotation) {
        for (const m of this.data) {
          const k4a = m[this.p.cohort.key4annotation];
          if (k4a) {
            const sanno = this.p.cohort.annotation[k4a];
            if (sanno) {
              if (this.p.cohort.levels) {
                for (const l of this.p.cohort.levels) {
                  m[l.k] = sanno[l.k];
                  if (l.full) {
                    m[l.full] = sanno[l.full];
                  }
                }
              } else {
                for (const k in sanno) {
                  m[k] = sanno[k];
                }
              }
            }
          }
        }
      }
      const div = this.treediv.append("div").style("margin", "10px").style("height", "400px").style("overflow-y", "scroll").style("resize", "vertical");
      const input = stratinput(this.data, this.p.cohort.levels);
      const root = hierarchy(stratify_default()(input));
      root.sum((i) => i.value);
      root.eachBefore((n) => {
        if (!n.parent) return;
        const row = div.append("div").style("margin", "2px").style("padding", "2px").style("border", "solid 1px transparent").attr("class", "sja_clb");
        for (let i = 1; i < n.depth; i++) {
          row.append("span").style("color", "#ccc").style("padding", "0px 15px").text("|");
        }
        const d = n.data.data;
        row.append("span").html(d.name + "&nbsp;");
        if (d.full) {
          row.append("span").html(d.full + "&nbsp;").style("font-size", ".7em").style("color", "#858585");
        }
        if (d.lst && d.lst.length) {
          row.append("span").text(d.lst.length);
          row.on("click", () => {
            let nf = true;
            for (const b of this.boxplots) {
              if (b.id == d.id) nf = false;
            }
            if (nf) {
              newboxplot(this, d.lst, d.name, d.id, row);
            } else {
              boxplotremove(this, d.id);
            }
          });
        }
      });
    } else {
      this.treediv.append("div").style("margin", "10px").text("Cannot stratify sample: no cohort information.");
    }
    newboxplot(this, this.data, "", "all", allsamplerow);
  }
  epaintfold(block) {
    if (!this.handle) {
      const ds = this.genome.datasets[this.dsname];
      if (!ds) {
        alert("invalid dataset name: " + this.dsname);
        return;
      }
      this.handle = block.ds2handle[this.dsname].handle.append("div").classed("sja_opaque8", true).style("background-color", "#999").style("color", "white").style("padding", "2px 4px").style("margin-left", "1px").text("e");
      this.handle.on("click", () => {
        this.pane.pane.style("display", "block");
        flyindi(this.handle, this.pane.pane);
        this.handle.style("display", "none");
      });
    }
    this.handle.style("display", "inline-block");
    flyindi(this.pane.pane, this.handle);
    this.pane.pane.style("display", "none");
  }
  makescale_ep() {
    const axish = this.axish - 2;
    if (this.uselog) {
      this.x_scale = log().domain([1, this.maxvalue]).range([0, this.width]);
    } else {
      this.x_scale = linear().domain([this.minvalue, this.maxvalue]).range([0, this.width]);
    }
    const scale = axisTop().scale(this.x_scale).tickSizeInner(this.tickh);
    if (this.uselog) {
      scale.ticks(6, ",.0f");
    } else {
      let fontwidth;
      this.axisg.append("text").text(Math.ceil(this.maxvalue)).attr("font-size", axish - this.tickh).each(function() {
        fontwidth = this.getBBox().width;
      }).remove();
      scale.ticks(Math.floor(this.width / (fontwidth + 20)));
    }
    if (this.axis) {
      this.axis.remove();
    }
    this.axis = this.axisg.append("g").attr("transform", "translate(0," + axish + ")").call(scale);
    axisstyle({
      axis: this.axis,
      fontsize: axish - this.tickh,
      showline: true
    });
  }
  render(width, height) {
    if (!width) {
      width = this.presize.width;
      height = this.presize.height;
    }
    this.width = width;
    this.width2 = width * 0.05;
    this.dotsize = Math.max(13, width / 30);
    this.height = height;
    this.sf_boxheight.range([10, this.height / 8]);
    const groupmax = Math.min(this.data.length * 0.7, 300);
    this.sf_boxlabelfontsize.domain([0, Math.log(groupmax), Math.log(this.data.length)]).range([8, this.sf_boxheight(groupmax) / 2, 1 + this.sf_boxheight(groupmax) / 2]);
    this.heightmove = this.height;
    this.rowheight_reset();
    this.svgg.attr("transform", "translate(" + this.dotsize + ",0)");
    this.axish = Math.max(18, this.width * 0.04);
    this.tickh = this.axish * 0.3;
    this.makescale_ep();
    this.grabbar.attr("width", this.width);
    this.grabbar.attr("height", this.axish);
    const tmp = this.svgg.append("text").text(this.data.length).attr("font-family", font).attr("font-size", this.sf_boxlabelfontsize(Math.log(this.data.length)));
    this.width2_ = tmp.node().getBBox().width + 3;
    tmp.remove();
    const tmp2 = this.svgg.append("text").text("COUNT").attr("font-size", 1).attr("font-family", font);
    const size2 = Math.max(8, (this.width2_ - 3) / tmp2.node().getBBox().width);
    tmp2.remove();
    this.axispad = 5 + size2 + this.dotsize / 2;
    this.verticalline.attr("x1", this.width + this.width2 - this.width2_).attr("y1", this.axish + 5).attr("x2", this.width + this.width2 - this.width2_).attr("y2", this.axish + this.height + this.axispad);
    this.dotgraph_y = this.axish + this.axispad;
    this.dotgraph_y_default = this.dotgraph_y;
    this.boxbag.attr("transform", "translate(0," + this.dotgraph_y + ")");
    this.graph.attr("transform", "translate(0," + this.dotgraph_y + ")");
    this.sung.attr("transform", "translate(0," + this.dotgraph_y + ")");
    this.grab.y = -this.dotgraph_y - 10;
    this.grab.height = this.height + this.dotgraph_y + 30;
    this.grab.holder.attr("transform", "translate(" + this.width / 2 + "," + this.height / 2 + ")");
    this.grab.shadehandle1.attr("y", 12 + this.axish);
    this.grab.shadehandle2.attr("y", 12 + this.axish);
    this.epdotg.attr("transform", (d, i) => {
      d._y = i * this.rowheight;
      return "translate(0," + d._y + ")";
    });
    this.epdot.attr("r", this.dotsize / 2);
    this.epdotg.attr("transform", (d) => "translate(" + Math.max(0, this.x_scale(d.value)) + "," + d._y + ")");
    if (this.grab.x) {
      let x1 = this.x_scale(this.grab.min), x2 = this.x_scale(this.grab.max);
      this.grab.x = x1;
      this.grab.width = x2 - x1;
      this.grab.shade.attr("transform", "translate(" + x1 + "," + this.grab.y + ")");
      this.grab.shadebox.attr("width", this.grab.width).attr("height", this.grab.height);
      this.grab.shadehandle2.attr("x", this.grab.width);
      burst(this, this.grab.min, this.grab.max);
    }
    for (const box of this.boxplots) {
      const labelfontsize = this.sf_boxlabelfontsize(Math.log(box.lst.length));
      const boxheight = this.sf_boxheight(box.lst.length);
      box.holder.attr("transform", "translate(0," + box.yoff + ")");
      box.hline.attr("y1", boxheight / 2).attr("y2", boxheight / 2).attr("x1", Math.max(0, this.x_scale(box.percentile[9]))).attr("x2", Math.max(0, this.x_scale(box.percentile[91])));
      box.label.attr("x", this.width + this.width2 - this.width2_ - 3).attr("y", boxheight / 2).attr("font-size", labelfontsize);
      box.label2.attr("x", this.width + this.width2 - this.width2_ + 3).attr("y", boxheight / 2).attr("font-size", labelfontsize);
      box.connline.attr("y1", boxheight / 2).attr("y2", boxheight / 2).attr("x1", Math.max(0, this.x_scale(box.percentile[91]))).attr("x2", Math.max(0, this.width + this.width2 - box.labelwidth - this.width2_ - 3));
      box.box.attr("height", boxheight).attr("x", Math.max(0, this.x_scale(box.percentile[25]))).attr("width", Math.max(0, this.x_scale(box.percentile[75])) - Math.max(0, this.x_scale(box.percentile[25])));
      box.vlines.attr("x1", (d) => Math.max(0, this.x_scale(d))).attr("x2", (d) => Math.max(0, this.x_scale(d))).attr("y1", 0).attr("y2", boxheight);
    }
    this.svg.attr("width", this.width + this.width2 + this.dotsize).attr("height", this.height + this.axish + this.axispad + this.dotsize / 2);
  }
  getsampleinfo(d, lst) {
    if (this.p.cohort) {
      if (this.p.cohort.annotation && this.p.cohort.key4annotation) {
        const k4a = d[this.p.cohort.key4annotation];
        if (k4a) {
          lst.push({ k: this.p.cohort.key4annotation, v: k4a });
          const sanno = this.p.cohort.annotation[k4a];
          if (sanno) {
            let numberofkeys = 0;
            for (const k in sanno) numberofkeys++;
            if (this.p.cohort.levels) {
              for (const l of this.p.cohort.levels) {
                lst.push({
                  k: l.label || l.k,
                  v: sanno[l.k] == void 0 ? "" : sanno[l.k]
                });
              }
              return numberofkeys > this.p.cohort.levels.length;
            }
            let shownum = 0;
            for (const k in sanno) {
              lst.push({ k, v: sanno[k] });
              if (++shownum == numberofkeys) return true;
            }
            return false;
          }
        }
      } else if (this.p.cohort.levels) {
        for (const l of this.p.cohort.levels) {
          const v = d[l.k];
          if (!v) continue;
          lst.push({
            k: l.label || l.k,
            v: d[l.k] + (l.full ? d[l.full] ? ' <span style="font-size:.8em;color:#858585">' + d[l.full] + "</span>" : "" : "")
          });
        }
        return false;
      }
    }
    for (const k in d) {
      if (k == "circle" || k == "_y") continue;
      if (typeof k == "string") {
        const v = d[k];
        if (v) {
          lst.push({ k, v });
        }
      }
    }
    return false;
  }
  rowheight_reset() {
    if (this.data) {
      this.rowheight = this.height / this.data.length;
      return;
    }
    this.rowheight = 0;
  }
  dot_appendtext(set, lookup) {
    const used = [];
    set.append("text").text((d) => lookup.get(d[this.p.sampletype])).attr("font-family", font).attr("font-size", this.dotsize).each(function(d) {
      d.bb = this.getBBox();
    }).each((d) => {
      const dotx = this.x_scale(d.value);
      const onleft = dotx - this.dotsize > d.bb.width;
      let y1 = d._y - d.bb.height / 2, y2 = y1 + d.bb.height;
      for (const u of used) {
        if (u.onleft == onleft && Math.max(u.y1, y1) < Math.min(u.y2, y2)) {
          y1 = u.y2;
          y2 = y1 + d.bb.height;
        }
      }
      delete d.bb;
      d.mafrect = { y1, y2, onleft };
      used.push(d.mafrect);
    }).attr("class", "sja_svgtext").attr("dominant-baseline", "central").attr("fill", this.p.hlcolor).attr("text-anchor", (d) => d.mafrect.onleft ? "end" : "start").attr("x", (d) => (d.mafrect.onleft ? -1 : 1) * this.dotsize).attr("y", (d) => d.mafrect.y1 - d._y + this.dotsize / 2).on("click", (event, d) => {
      select_default(d.circle).attr("stroke-width", 1).attr("stroke-opacity", normal_strokeopacity).attr("stroke", "black").attr("r", this.dotsize / 2);
      d.showtext = false;
      select_default(event.target).remove();
    }).attr("font-size", 1).transition().attr("font-size", this.dotsize);
  }
  may_hl(mlst, hl) {
    if (!this.data) return;
    const samples = /* @__PURE__ */ new Set();
    let nohit = true;
    for (const m of mlst) {
      const sn = m[this.p.sampletype];
      if (!sn) continue;
      samples.add(sn);
      if (this.sampletype2value[sn]) {
        nohit = false;
      }
    }
    if (nohit) return;
    this.epdot.filter((d) => samples.has(d[this.p.sampletype])).attr("r", hl ? this.dotsize * 0.8 : this.dotsize / 2).attr("stroke", hl ? this.p.hlcolor : "black").attr("stroke-opacity", hl ? hl_strokeopacity : normal_strokeopacity);
    const maf = this.p.maf;
    if (!maf) return;
    const lookup = /* @__PURE__ */ new Map();
    for (const m of mlst) {
      const sn = m[this.p.sampletype];
      const v = this.p.maf.get(m);
      if (!v) continue;
      if (typeof v == "string") {
        lookup.set(sn, v);
      } else {
        lookup.set(
          sn,
          v.v2 == 0 ? "No " + this.p.maf.label + ": site not covered" : this.p.maf.label + ": " + (v.f * 100).toFixed(0) + "% (" + v.v1 + "/" + v.v2 + ")"
        );
      }
    }
    const set = this.epdotg.filter((d) => lookup.has(d[this.p.sampletype]) && !d.showtext);
    if (hl) {
      this.dot_appendtext(set, lookup);
    } else {
      set.select("text").remove();
    }
  }
  // end of class
};
function showgene(ep, name) {
  const ds = ep.genome.datasets[ep.dsname];
  if (ds.dbexpression) {
    const par = {
      db: ds.dbexpression.dbfile,
      tablename: ds.dbexpression.tablename,
      keyname: ds.dbexpression.keyname,
      key: name
    };
    fetch(
      new Request(ep.hostURL + "/dbdata", {
        method: "POST",
        body: JSON.stringify(par)
      })
    ).then((data) => {
      return data.json();
    }).then((data) => {
      if (data.error) throw { message: data.error };
      if (ds.dbexpression.tidy) {
        ds.dbexpression.tidy(data.rows);
      }
      const p = ep.pane.pane.node().getBoundingClientRect();
      new EPaint({
        hostURL: ep.hostURL,
        data: data.rows,
        expp: ep.p,
        presize: {
          x: p.left + 30,
          y: p.top + 50,
          width: ep.width,
          height: ep.height
        },
        genome: ep.genome,
        dsname: ep.dsname,
        genename: name,
        samplecart: ep.samplecart
      });
    }).catch((err) => {
      window.alert(err.message);
      if (err.stack) console.log(err.stack);
    });
    return;
  }
  fetch(
    new Request(ep.hostURL + "/dsdata", {
      method: "POST",
      body: JSON.stringify({ genome: ep.genome.name, dsname: ep.dsname, expressiononly: 1, genename: name })
    })
  ).then((data) => {
    return data.json();
  }).then((data) => {
    if (data.error) throw { message: data.error };
    const p = ep.pane.pane.node().getBoundingClientRect();
    new EPaint({
      hostURL: ep.hostURL,
      data: data.data[0].lst,
      expp: ep.p,
      presize: {
        x: p.left + 30,
        y: p.top + 50,
        width: ep.width,
        height: ep.height
      },
      genome: ep.genome,
      dsname: ep.dsname,
      genename: name,
      samplecart: ep.samplecart
    });
  }).catch((err) => {
    window.alert(err.message);
    if (err.stack) console.log(err.stack);
  });
}
function samplefulldetail(d, cohort, x, y) {
  const pane = newpane({ x, y });
  const k4a = d[cohort.key4annotation];
  pane.header.text(k4a);
  const lst = [];
  const anno = cohort.annotation[k4a];
  for (const k in anno) {
    lst.push({ k, v: anno[k] });
  }
  make_table_2col(pane.body, lst);
}
function makeButtons(ep) {
  const butrow = ep.pane.body.append("div").style("margin-bottom", "10px");
  butrow.append("button").text("Cohort").on("click", () => {
    if (ep.treediv.style("display") == "none") {
      appear(ep.treediv);
    } else {
      disappear(ep.treediv);
    }
  });
  butrow.append("button").text("Log10").on("click", () => {
    const dur = 700;
    ep.uselog = !ep.uselog;
    ep.makescale_ep();
    ep.epdotg.transition().duration(dur).attr(
      "transform",
      (d, i) => "translate(" + (ep.uselog && d.value == 0 ? 0 : Math.max(0, ep.x_scale(d.value))) + "," + d._y + ")"
    );
    for (const bp of ep.boxplots) {
      bp.vlines.transition().duration(dur).attr("x1", (v) => Math.max(0, ep.x_scale(v))).attr("x2", (v) => Math.max(0, ep.x_scale(v)));
      bp.box.transition().duration(dur).attr("x", Math.max(0, ep.x_scale(bp.percentile[25]))).attr("width", Math.max(0, ep.x_scale(bp.percentile[75])) - Math.max(0, ep.x_scale(bp.percentile[25])));
      bp.hline.transition().duration(dur).attr("x1", Math.max(0, ep.x_scale(bp.percentile[9]))).attr("x2", Math.max(0, ep.x_scale(bp.percentile[91])));
      bp.connline.transition().duration(dur).attr("x1", Math.max(0, ep.x_scale(bp.percentile[91]))).attr("x2", ep.width + ep.width2 - bp.labelwidth - ep.width2_ - 3);
    }
    if (ep.grab.x) {
      let x1 = ep.x_scale(ep.grab.min), x2 = ep.x_scale(ep.grab.max);
      ep.grab.x = x1;
      ep.grab.width = x2 - x1;
      ep.grab.shade.transition().duration(dur).attr("transform", "translate(" + x1 + "," + ep.grab.y + ")");
      ep.grab.shadebox.transition().duration(dur).attr("width", ep.grab.width);
      ep.grab.shadehandle2.transition().duration(dur).attr("x", ep.grab.width);
    }
  });
  butrow.append("button").text("SVG").on("click", () => {
    to_svg(ep.svg.node(), ep.genename + "_expression");
  });
  butrow.append("button").text("Data").on("click", () => {
    const header = [ep.p.sampletype, ep.p.datatype];
    const attrlst = [];
    if (ep.p.attrlst) {
      for (const a of ep.p.attrlst) {
        header.push(a.k);
        attrlst.push(a.k);
      }
    }
    if (ep.p.cohort) {
      for (const a of ep.p.cohort.levels) {
        header.push(a.k);
        attrlst.push(a.k);
      }
    }
    const rows = [];
    for (const d of ep.data) {
      const row = [d[ep.p.sampletype], d.value];
      for (const k of attrlst) {
        row.push(d[k] || "");
      }
      rows.push(row.join("	"));
    }
    export_data(ep.genename + " " + ep.p.name + " data", [
      { text: header.join("	") + "\n" + rows.join("\n") }
    ]);
  });
  butrow.append("input").attr("placeholder", "Sample").style("width", "60px").style("margin-left", "5px").on("keyup", (event) => {
    const str = event.target.value;
    if (str == "") {
      ep.epdot.attr("r", ep.dotsize / 2).attr("stroke", "black").attr("stroke-opacity", normal_strokeopacity);
      return;
    }
    const lstr = str.toLowerCase();
    const set = /* @__PURE__ */ new Set();
    for (const n in ep.sampletype2value) {
      if (n.toLowerCase().indexOf(lstr) != -1) {
        set.add(n);
      }
    }
    ep.epdot.filter((i) => set.has(i[ep.p.sampletype])).attr("r", ep.dotsize).attr("stroke", ep.p.hlcolor).attr("stroke-opacity", hl_strokeopacity);
    ep.epdot.filter((i) => !set.has(i[ep.p.sampletype])).attr("r", ep.dotsize / 2).attr("stroke", "black").attr("stroke-opacity", normal_strokeopacity);
  });
  butrow.append("input").attr("placeholder", "Gene").style("width", "60px").style("margin-left", "5px").on("keyup", (event) => {
    const str = event.target.value;
    if (event.code == "Enter") {
      showgene(ep, str);
      event.target.value = "";
      return;
    }
  });
  if (ep.p.gtexlink) {
    butrow.append("span").html("&nbsp;<a target=_blank href=https://www.gtexportal.org/home/gene/" + ep.genename + ">GTeX normal</a>");
  }
}
export {
  EPaint as default
};
//# sourceMappingURL=ep-CXCATXYH.js.map
