import {
  ase_color,
  init_config,
  measure,
  showsingleitem_table
} from "./chunk-KPJZBCVI.js";
import {
  appear2 as appear,
  axisstyle,
  disappear2 as disappear,
  font,
  make_table_2col,
  newpane,
  sayerror,
  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 {
  dofetch2
} from "./chunk-7EMWHCVW.js";
import "./chunk-7IYJZZQI.js";
import "./chunk-M3J4MINX.js";
import "./chunk-PF4DSFDR.js";
import "./chunk-QH6W3NVF.js";
import "./chunk-NOEAT6CX.js";
import "./chunk-4UWS5Y3N.js";
import "./chunk-DD4R5P6W.js";
import "./chunk-JNITUVXP.js";
import "./chunk-KSGA62R2.js";
import {
  axisTop
} from "./chunk-LOZEKOES.js";
import "./chunk-TOU7EVFQ.js";
import {
  linear,
  log
} from "./chunk-OAWQ6LOO.js";
import "./chunk-TLT4YIG3.js";
import "./chunk-KYBIQBXE.js";
import "./chunk-I6Y4O3RR.js";
import "./chunk-OMR2DT66.js";
import "./chunk-DQC5FFGV.js";
import "./chunk-HFNDKYVF.js";

// src/block.mds.geneboxplot.js
var label_cnvgain = "CNV gain";
var label_cnvloss = "CNV loss";
var label_sv = "SV";
var label_ase = "Allele-specific expression";
var label_outlier = "Outlier expression";
async function init(p) {
  if (!p.genome) return alert("cannot initiate plot: genome missing");
  const plot = p;
  plot.tip = new Menu({ padding: "0px" });
  if (plot.file || plot.url) {
    plot.gecfg = {};
  } else {
    if (!plot.dslabel) return alert("dslabel missing");
    if (!plot.querykey) return alert("querykey missing");
    const d = plot.genome.datasets[plot.dslabel];
    if (!d) return alert("invalid dataset label: " + plot.dslabel);
    plot.gecfg = d.queries[plot.querykey];
    if (!plot.gecfg) return alert("invalid query key: " + plot.querykey);
  }
  init_config(plot.gecfg);
  if (p.block && p.block.debugmode) {
    window.plot = plot;
  }
  plot.errdiv = plot.holder.append("div").style("margin", "10px");
  const buttonrow = plot.holder.append("div").style("margin", "10px");
  plot.buttonrow = buttonrow;
  mayaddgrouperselect(plot);
  const configdiv = plot.holder.append("div").style("margin", "10px").style("border", "solid 1px #ededed").style("padding", "10px").style("display", "none");
  plot.table_boxplotstats = plot.holder.append("table").style("margin", "10px").style("border-spacing", "4px").style("border-collapse", "separate");
  buttonrow.append("button").text("Log10").on("click", (event) => {
    plot.uselog = !plot.uselog;
    event.target.innerHTML = plot.uselog ? "Linear" : "Log10";
    plot.place();
  });
  if (plot.sample) {
    plot.sample.shown = true;
    buttonrow.append("button").text(plot.sample.name + " toggle").on("click", () => {
      plot.sample.shown = !plot.sample.shown;
      plot.sample.line.attr("stroke-opacity", plot.sample.shown ? 1 : 0);
      plot.sample.svgtext.attr("fill-opacity", plot.sample.shown ? 1 : 0);
    });
  }
  if (plot.svcnv) {
    buttonrow.append("button").text("SV/CNV options").on("click", () => {
      if (configdiv.style("display") == "none") appear(configdiv);
      else disappear(configdiv);
    });
    plot.svcnv.useloss = true;
    plot.svcnv.usegain = true;
    plot.cnvconfig = {};
    plot.svconfig = {};
    {
      const row = configdiv.append("div");
      const id = Math.random().toString();
      row.append("input").attr("type", "checkbox").property("checked", true).attr("id", id).on("change", (event) => {
        plot.svcnv.usegain = event.target.checked;
        plot.cnvconfig.div.style("display", plot.svcnv.usegain || plot.svcnv.useloss ? "block" : "none");
        loadplot(plot);
      });
      row.append("label").attr("for", id).attr("class", "sja_clbtext").html("&nbsp;Add boxplot for samples with copy number gain over " + plot.gene).style("color", plot.color.cnvgain);
    }
    {
      const row = configdiv.append("div");
      const id = Math.random().toString();
      row.append("input").attr("type", "checkbox").property("checked", true).attr("id", id).on("change", (event) => {
        plot.svcnv.useloss = event.target.checked;
        plot.cnvconfig.div.style("display", plot.svcnv.usegain || plot.svcnv.useloss ? "block" : "none");
        loadplot(plot);
      });
      row.append("label").attr("for", id).attr("class", "sja_clbtext").html("&nbsp;Add boxplot for samples with copy number loss over " + plot.gene).style("color", plot.color.cnvloss);
    }
    {
      const d = configdiv.append("div");
      plot.cnvconfig.div = d;
      const d2 = d.append("div").style("display", "inline-block").style("margin", "5px 10px 10px 30px").style("border", "solid 1px #ededed").style("padding", "10px");
      {
        const row = d2.append("div").style("margin-bottom", "15px");
        row.append("span").html("CNV log2(ratio) cutoff&nbsp;");
        row.append("input").property("value", plot.svcnv.valueCutoff || 0).attr("type", "number").style("width", "50px").on("keyup", (event) => {
          if (event.code != "Enter" && event.code != "NumpadEnter") return;
          let v = Number.parseFloat(event.target.value);
          if (!v || v < 0) {
            v = 0;
          }
          if (v == 0) {
            if (plot.svcnv.valueCutoff) {
              plot.svcnv.valueCutoff = 0;
              loadplot(plot);
            } else {
            }
            return;
          }
          if (plot.svcnv.valueCutoff) {
            if (plot.svcnv.valueCutoff == v) {
            } else {
              plot.svcnv.valueCutoff = v;
              loadplot(plot);
            }
          } else {
            plot.svcnv.valueCutoff = v;
            loadplot(plot);
          }
        });
        row.append("div").style("font-size", ".7em").style("color", "#858585").html("CNV with absolute log2(ratio) lower than cutoff will not be considered. Set to 0 to cancel.");
      }
      {
        const row = d2.append("div");
        row.append("span").html("CNV segment size limit&nbsp;");
        row.append("input").property("value", plot.svcnv.bplengthUpperLimit || 0).attr("type", "number").style("width", "80px").on("keyup", (event) => {
          if (event.code != "Enter" && event.code != "NumpadEnter") return;
          let v = Number.parseInt(event.target.value);
          if (!v || v < 0) {
            v = 0;
          }
          if (v == 0) {
            if (plot.svcnv.bplengthUpperLimit) {
              plot.svcnv.bplengthUpperLimit = 0;
              loadplot(plot);
            } else {
            }
            return;
          }
          if (plot.svcnv.bplengthUpperLimit) {
            if (plot.svcnv.bplengthUpperLimit == v) {
            } else {
              plot.svcnv.bplengthUpperLimit = v;
              loadplot(plot);
            }
          } else {
            plot.svcnv.bplengthUpperLimit = v;
            loadplot(plot);
          }
        });
        row.append("span").html("&nbsp;bp");
        row.append("div").style("font-size", ".7em").style("color", "#858585").html("CNV segment longer than cutoff will not be considered. Set to 0 to cancel.");
      }
    }
    {
      const row = configdiv.append("div");
      const id = Math.random().toString();
      row.append("input").attr("type", "checkbox").property("checked", false).attr("id", id).on("change", (event) => {
        plot.svcnv.usesv = event.target.checked;
        plot.svconfig.div.style("display", plot.svcnv.usesv ? "block" : "none");
        loadplot(plot);
      });
      row.append("label").attr("for", id).attr("class", "sja_clbtext").html("&nbsp;Add boxplot for samples with structural variation over " + plot.gene).style("color", plot.color.sv);
    }
    {
      const d = configdiv.append("div").style("display", "none");
      plot.svconfig.div = d;
      const d2 = d.append("div").style("display", "inline-block").style("margin", "5px 10px 10px 30px").style("border", "solid 1px #ededed").style("padding", "10px");
      {
        const row = d2.append("div");
        row.append("span").html("Include SV from flanking region of length:&nbsp;");
        row.append("input").property("value", 0).attr("type", "number").style("width", "80px").on("keyup", (event) => {
          if (event.code != "Enter" && event.code != "NumpadEnter") return;
          let v = Number.parseInt(event.target.value);
          if (!v || v < 0) {
            v = 0;
          }
          if (v == 0) {
            if (plot.svcnv.svflank) {
              plot.svcnv.svflank = 0;
              loadplot(plot);
            } else {
            }
            return;
          }
          if (plot.svcnv.svflank) {
            if (plot.svcnv.svflank == v) {
            } else {
              plot.svcnv.svflank = v;
              loadplot(plot);
            }
          } else {
            plot.svcnv.svflank = v;
            loadplot(plot);
          }
        });
        row.append("span").html("&nbsp;bp");
        row.append("div").style("font-size", ".7em").style("color", "#858585").html("Set to 0 to cancel.");
      }
    }
  }
  plot.buttonholder_boxplot = buttonrow.append("span");
  plot.buttonholder_sampleexpdata = buttonrow.append("span");
  buttonrow.append("button").text("SVG").on("click", () => {
    to_svg(plot.svg.node(), "Expression");
  });
  plot.svg = plot.holder.append("svg");
  const axisg = plot.svg.append("g");
  plot.g0 = plot.svg.append("g");
  const axisheight = 50;
  const lablspace = 10;
  const axisw = 500;
  const rowheight = 16;
  const rowspace = 10;
  const _rowspace = 2;
  const axispad2 = 30;
  const fontsize = 14;
  const circleyshift = 2;
  plot.place = () => {
    plot.axislabel.attr("x", axisw / 2);
    let labwidth = 0;
    let rightwidth = 0;
    const scale0 = (plot.uselog ? log() : linear()).domain([plot.data.min == 0 ? 1e-3 : plot.data.min, plot.data.max]).range([0, axisw]);
    const scale = (v) => {
      if (plot.uselog) {
        if (v == 0) return 0;
      }
      return scale0(v);
    };
    axisstyle({
      axis: axisg.transition().call(axisTop().scale(scale0)),
      showline: 1
    });
    let y = rowspace;
    if (plot.data.lst) {
      labwidth = 20;
      rightwidth = 20;
      for (const d of plot.data.lst) {
        d.circle.transition().attr("cx", scale(d.value)).attr("cy", y).attr("r", rowheight / 2);
        y += circleyshift;
      }
    } else {
      for (const g of plot.data.groups) {
        g.g.attr("transform", "translate(0," + y + ")");
        const _rowheight = rowheight * (g.boxplots.length > 1 ? 0.8 : 1);
        let _y = 0;
        for (const bp of g.boxplots) {
          if (bp.label) {
            bp.label.attr("font-size", _rowheight).attr("x", axisw + 5).attr("y", _y + _rowheight / 2).each(function() {
              rightwidth = Math.max(rightwidth, this.getBBox().width);
            });
          }
          if (bp.hline) {
            const w1 = scale(bp.w1);
            const w2 = scale(bp.w2);
            const p25 = scale(bp.p25);
            const p50 = scale(bp.p50);
            const p75 = scale(bp.p75);
            bp.hline.transition().attr("x1", w1).attr("x2", w2).attr("y1", _y + _rowheight / 2).attr("y2", _y + _rowheight / 2);
            bp.linew1.transition().attr("x1", w1).attr("x2", w1).attr("y1", _y).attr("y2", _y + _rowheight);
            bp.linew2.transition().attr("x1", w2).attr("x2", w2).attr("y1", _y).attr("y2", _y + _rowheight);
            bp.box.transition().attr("x", p25).attr("y", _y).attr("width", p75 - p25).attr("height", _rowheight);
            bp.linep50.transition().attr("x1", p50).attr("x2", p50).attr("y1", _y).attr("y2", _y + _rowheight);
          }
          for (const d of bp.out) {
            d.circle.transition().attr("cx", scale(d.value)).attr("cy", _y + _rowheight / 2).attr("r", _rowheight / 3);
          }
          _y += _rowheight + _rowspace;
        }
        const h = (_rowheight + _rowspace) * g.boxplots.length - _rowspace;
        g.label.attr("x", -lablspace).attr("y", h / 2).attr("font-size", fontsize).each(function() {
          labwidth = Math.max(labwidth, this.getBBox().width);
        });
        if (g.bg)
          g.bg.attr("y", -rowspace / 2).attr("width", axisw).attr("height", h + rowspace);
        y += h + rowspace;
      }
    }
    plot.g0.attr("transform", "translate(" + (labwidth + lablspace) + "," + axisheight + ")");
    axisg.attr("transform", "translate(" + (labwidth + lablspace) + "," + axisheight + ")");
    if (plot.sample) {
      plot.sample.g.transition().attr("transform", "translate(" + scale(plot.sample.value) + "," + y + ")");
      plot.sample.line.attr("y1", -y);
    }
    plot.svg.attr("width", labwidth + lablspace + axisw + axispad2 + rightwidth).attr("height", axisheight + y + 30);
  };
  try {
    await loadplot(plot);
  } catch (e) {
    sayerror(plot.errdiv, "Error: " + (e.message || e));
    if (e.stack) console.log(e.stack);
  }
}
async function loadplot(plot) {
  const arg = {
    genome: plot.genome.name,
    gene: plot.gene,
    chr: plot.chr,
    start: plot.start,
    stop: plot.stop,
    svcnv: plot.svcnv,
    index_boxplotgroupers: plot.index_boxplotgroupers,
    sampleset: plot.sampleset
  };
  if (plot.dslabel) {
    arg.dslabel = plot.dslabel;
    arg.querykey = plot.querykey;
  } else {
    arg.iscustom = 1;
    arg.file = plot.file;
    arg.url = plot.url;
    arg.indexURL = plot.indexURL;
  }
  plot.g0.append("text").text("Loading ...").attr("font-size", 20).attr("text-anchor", "center").attr("dominant-baseline", "central").attr("x", plot.svg.attr("width") / 2).attr("y", plot.svg.attr("height") / 2);
  const data = await dofetch2("mdsgeneboxplot", { method: "POST", body: JSON.stringify(arg) });
  if (data.error) throw data.error;
  plot.g0.selectAll("*").remove();
  plot.axislabel = plot.g0.append("text").attr("font-size", 14).attr("font-family", font).attr("text-anchor", "middle").attr("y", -25).text(plot.gene + " " + plot.gecfg.datatype);
  plot.data = data;
  const color0 = "green";
  if (data.lst) {
    addbutton_showdata_fromlst(plot);
    for (const d of data.lst) {
      d.circle = plot.g0.append("circle").attr("fill", "white").attr("fill-opacity", 0).attr("stroke", color0).attr("stroke-opacity", 0.8).on("mouseover", (event) => {
        plot.tip.clear().d.append("div").style("margin", "10px").html(d.sample + "<br>" + d.value);
        plot.tip.show(event.clientX, event.clientY);
      }).on("mouseout", () => plot.tip.hide());
      if (plot.clicksample) {
        d.circle.on("click", () => {
          plot.clicksample(d, null, plot);
        });
      }
    }
  } else {
    addbutton_boxplotstats(plot);
    addbutton_showdata_newquery(plot);
    for (const [i, g] of data.groups.entries()) {
      g.g = plot.g0.append("g");
      if (i % 2 == 0) {
        g.bg = g.g.append("rect").attr("fill", "#f5f5f5");
      }
      g.label = g.g.append("text").attr("font-family", font).attr("text-anchor", "end").attr("dominant-baseline", "central").attr("class", "sja_clbtext").text(g.name).on("click", (event) => {
        init2(Math.max(100, event.clientX - 100), Math.max(100, event.clientY - 100), plot, g);
      });
      if (g.attributes) {
        g.label.on("mouseover", (event) => {
          plot.tip.clear().show(event.clientX, event.clientY);
          const d = plot.tip.d.append("div").style("margin", "10px");
          for (const a of g.attributes) {
            d.append("div").html(
              a.kvalue + (a.fullvalue ? ' <span style="opacity:.5;font-size:.8em;">' + a.fullvalue + "</span>" : "")
            );
          }
        }).on("mouseout", () => {
          plot.tip.hide();
        });
      }
      for (const bp of g.boxplots) {
        let color;
        if (bp.iscnvgain) {
          color = plot.color.cnvgain;
          bp.label = g.g.append("text").text("CNV gain (" + bp.samplecount + ")");
        } else if (bp.iscnvloss) {
          color = plot.color.cnvloss;
          bp.label = g.g.append("text").text("CNV loss (" + bp.samplecount + ")");
        } else if (bp.issv) {
          color = "black";
          bp.label = g.g.append("text").text("SV (" + bp.samplecount + ")");
        } else {
          color = color0;
        }
        if (bp.label) {
          bp.label.attr("fill", color).attr("font-family", font).attr("dominant-baseline", "central");
        }
        if (bp.w1 != void 0) {
          bp.hline = g.g.append("line").attr("stroke", color).attr("shape-rendering", "crispEdges");
          bp.linew1 = g.g.append("line").attr("stroke", color).attr("shape-rendering", "crispEdges");
          bp.linew2 = g.g.append("line").attr("stroke", color).attr("shape-rendering", "crispEdges");
          bp.box = g.g.append("rect").attr("fill", "white").attr("stroke", color).attr("shape-rendering", "crispEdges");
          bp.linep50 = g.g.append("line").attr("stroke", color).attr("shape-rendering", "crispEdges");
        }
        for (const d of bp.out) {
          d.circle = g.g.append("circle").attr("stroke", color).attr("fill", "white").attr("fill-opacity", 0).on("mouseover", (event) => {
            plot.tip.clear().d.append("div").style("margin", "10px").html(d.sample + "<br>" + d.value);
            plot.tip.show(event.clientX, event.clientY);
          }).on("mouseout", () => {
            plot.tip.hide();
          });
          if (plot.clicksample) {
            d.circle.on("click", () => {
              plot.clicksample(d, g, plot);
            });
          }
        }
      }
    }
  }
  if (plot.sample) {
    plot.sample.g = plot.g0.append("g");
    plot.sample.svgtext = plot.sample.g.append("text").text(plot.sample.name).attr("font-family", font).attr("font-size", 12).attr("text-anchor", "middle").attr("dominant-baseline", "hanging").attr("fill", "blue");
    plot.sample.line = plot.sample.g.append("line").attr("shape-rendering", "crispEdges").attr("stroke", "blue");
  }
  plot.place();
}
function addbutton_boxplotstats(plot) {
  plot.buttonholder_boxplot.selectAll("*").remove();
  plot.buttonholder_boxplot.append("button").text("Boxplots").on("click", () => {
    if (plot.table_boxplotstats.style("display") == "block") {
      disappear(plot.table_boxplotstats);
      return;
    }
    plot.table_boxplotstats.selectAll("*").remove();
    const tr = plot.table_boxplotstats.append("tr");
    tr.append("td").text("Group").style("font-size", ".8em").style("opacity", 0.5);
    tr.append("td").text("1st quartile").style("font-size", ".8em").style("opacity", 0.5);
    tr.append("td").text("Median").style("font-size", ".8em").style("opacity", 0.5);
    tr.append("td").text("3rd quartile").style("font-size", ".8em").style("opacity", 0.5);
    for (const [i, g] of plot.data.groups.entries()) {
      const tr2 = plot.table_boxplotstats.append("tr").style("background", i % 2 ? "" : "#f1f1f1");
      tr2.append("td").text(g.name);
      const boxplot = g.boxplots ? g.boxplots[0] : null;
      tr2.append("td").text(boxplot ? boxplot.p25 : "");
      tr2.append("td").text(boxplot ? boxplot.p50 : "");
      tr2.append("td").text(boxplot ? boxplot.p75 : "");
    }
    appear(plot.table_boxplotstats);
  });
}
function addbutton_showdata_fromlst(plot) {
  plot.buttonrow.append("button").text(plot.gecfg.datatype).on("click", () => {
    const pane = newpane({ x: 100, y: 100 });
    pane.header.text(plot.gene + " " + plot.gecfg.datatype);
    const table = pane.body.append("table").style("border-spacing", "4px").style("border-collapse", "separate");
    const tr = table.append("tr");
    tr.append("td").text("Sample").style("font-size", ".8em").style("opacity", 0.5);
    tr.append("td").text(plot.gecfg.datatype).style("font-size", ".8em").style("opacity", 0.5);
    for (const i of plot.data.lst) {
      const tr2 = table.append("tr");
      tr2.append("td").text(i.sample);
      tr2.append("td").text(i.value);
    }
  });
}
function addbutton_showdata_newquery(plot) {
  plot.buttonholder_sampleexpdata.selectAll("*").remove();
  plot.buttonholder_sampleexpdata.append("button").text(plot.gecfg.datatype).on("click", async () => {
    const pane = newpane({ x: 100, y: 100 });
    pane.header.text(plot.gene + " " + plot.gecfg.datatype);
    const wait = pane.body.append("div").style("margin", "30px").text("Loading...");
    const arg = {
      genome: plot.genome.name,
      gene: plot.gene,
      chr: plot.chr,
      start: plot.start,
      stop: plot.stop,
      getalllst: 1
    };
    if (plot.dslabel) {
      arg.dslabel = plot.dslabel;
      arg.querykey = plot.querykey;
    } else {
      arg.iscustom = 1;
      arg.file = plot.file;
      arg.url = plot.url;
      arg.indexURL = plot.indexURL;
    }
    try {
      const data = await dofetch2("mdsgeneboxplot", { method: "POST", body: JSON.stringify(arg) });
      if (data.error) throw data.error;
      wait.remove();
      const table = pane.body.append("table").style("border-spacing", "4px").style("border-collapse", "separate");
      const tr = table.append("tr");
      tr.append("td").text("Sample").style("font-size", ".8em").style("opacity", 0.5);
      tr.append("td").text(plot.gecfg.datatype).style("font-size", ".8em").style("opacity", 0.5);
      for (const i of data.lst) {
        const tr2 = table.append("tr");
        tr2.append("td").text(i.sample);
        tr2.append("td").text(i.value);
      }
    } catch (e) {
      wait.text("Error: " + (e.message || e));
      if (e.stack) console.log(e.stack);
    }
  });
}
function init2(x, y, plot, group) {
  const pane = newpane({ x, y });
  pane.header.text(plot.gene + " " + plot.gecfg.datatype + " in " + group.name);
  const pp = {
    _plot: plot,
    holder: pane.body,
    uselog: plot.uselog
  };
  if (group.attributes) {
    pp.getgroup = group.attributes;
  } else {
    pp.getgroup = 1;
    pp.getgroup_unannotated = 1;
  }
  pp.errdiv = pp.holder.append("div").style("margin", "10px");
  const buttonrow = pp.holder.append("div").style("margin", "10px");
  const configdiv = pp.holder.append("div").style("margin", "10px").style("border", "solid 1px #ededed").style("padding", "10px").style("display", "none");
  buttonrow.append("button").text("Log10").on("click", (event) => {
    pp.uselog = !pp.uselog;
    event.target.innerHTML = pp.uselog ? "Linear" : "Log10";
    pp.place();
  });
  buttonrow.append("button").text("Data").on("click", () => {
    const pane2 = newpane({ x: 200, y: 200 });
    pane2.header.text(pane.header.node().innerHTML);
    const table = pane2.body.append("table").style("border-spacing", "2px").style("border-collapse", "separate");
    const tr = table.append("tr");
    tr.append("td").text("Sample").style("font-size", ".8em").style("opacity", 0.5);
    tr.append("td").text(plot.gecfg.datatype).style("font-size", ".8em").style("opacity", 0.5);
    for (const [i, d] of pp.data.lst.entries()) {
      const tr2 = table.append("tr");
      const td = tr2.append("td").text(d.sample);
      if (plot.clicksample) {
        td.attr("class", "sja_clbtext").on("click", () => {
          plot.clicksample(d, group, plot);
        });
      }
      tr2.append("td").text(d.value);
    }
  });
  pp.svg = pp.holder.append("svg");
  pp.g0 = pp.svg.append("g");
  const axisg = pp.svg.append("g");
  const axiswidth = 400;
  const circleradius = 6;
  const axisticksize = 6;
  const axislabelfontsize = 14;
  const axispad = 10;
  const statuscolpad = 5;
  const circleyshift = 2;
  pp.place = () => {
    for (const col of pp.statuscolumns) {
      col.width = 20;
      for (const d of pp.data.lst) {
        if (!d.status2cell) continue;
        const cell = d.status2cell.get(col.name);
        if (!cell) continue;
        if (cell.label) {
          cell.label.attr("font-size", circleradius * 2 - 2).each(function() {
            col.width = Math.max(col.width, this.getBBox().width + 2);
          });
        }
      }
    }
    let samplenamewidth = 0;
    for (const d of pp.data.lst) {
      if (d.samplelabel) {
        d.samplelabel.attr("font-size", circleradius * 2 - 1).attr("x", -statuscolpad).attr("y", circleradius).each(function() {
          samplenamewidth = Math.max(samplenamewidth, this.getBBox().width);
        });
      }
    }
    let statuslabelheight = 0;
    let statustotalwidth = 0;
    for (const col of pp.statuscolumns) {
      if (!col.g) {
        col.g = pp.g0.append("g");
        col.namelabel = col.g.append("text").attr("font-family", font).attr("dominant-baseline", "central").attr("transform", "rotate(-90)").text(col.name);
      }
      col.g.attr("transform", "translate(" + (statustotalwidth + col.width / 2) + ",0)");
      col.namelabel.attr("font-size", Math.min(15, col.width)).each(function() {
        statuslabelheight = Math.max(statuslabelheight, this.getBBox().width);
      });
      statustotalwidth += col.width + statuscolpad;
    }
    statustotalwidth += circleradius;
    const topheight = Math.max(statuslabelheight, axisticksize + axislabelfontsize + 20);
    pp.g0.attr("transform", "translate(" + (samplenamewidth + statuscolpad) + "," + topheight + ")");
    pp.axislabel.attr("x", statustotalwidth + axiswidth / 2);
    axisg.attr("transform", "translate(" + (samplenamewidth + statuscolpad + statustotalwidth) + "," + topheight + ")");
    const scale0 = (pp.uselog ? log() : linear()).domain([pp.data.min == 0 ? 1e-3 : pp.data.min, pp.data.max]).range([0, axiswidth]);
    const scale = (v) => {
      if (pp.uselog) {
        if (v == 0) return 0;
      }
      return scale0(v);
    };
    axisstyle({
      axis: axisg.transition().call(
        axisTop().scale(scale0).tickSize(axisticksize)
      ),
      showline: 1
    });
    let y2 = axispad;
    for (const [idx, d] of pp.data.lst.entries()) {
      d.rowg.attr("transform", "translate(0," + y2 + ")");
      if (d.rowbg) {
        d.rowbg.attr("width", statustotalwidth + axiswidth).attr("height", circleradius * 2);
      }
      d.circle.transition().attr("r", circleradius).attr("cx", statustotalwidth + scale(d.value)).attr("cy", circleradius);
      if (d.samplelabel) {
        if (idx > 0 && !pp.data.lst[idx - 1].samplelabel) {
          y2 += circleradius * 2 - circleyshift;
          d.rowg.attr("transform", "translate(0," + y2 + ")");
        }
        if (d.status2cell) {
          let x2 = 0;
          for (const col of pp.statuscolumns) {
            const cell = d.status2cell.get(col.name);
            if (cell) {
              cell.g.attr("transform", "translate(" + (x2 + col.width / 2) + "," + circleradius + ")");
              cell.rect.attr("x", -col.width / 2).attr("y", -circleradius).attr("width", col.width).attr("height", circleradius * 2);
            }
            x2 += col.width + statuscolpad;
          }
        }
        y2 += circleradius * 2;
      } else {
        y2 += circleyshift;
      }
    }
    pp.svg.attr("width", samplenamewidth + statuscolpad + statustotalwidth + axiswidth + circleradius).attr("height", topheight + axispad + y2 + circleradius * 2);
  };
  pp.makegraph = () => {
    const _p = pp._plot;
    pp.axislabel = pp.g0.append("text").attr("font-size", 14).attr("font-family", font).attr("text-anchor", "middle").attr("y", -25).text(_p.gene + " " + _p.gecfg.datatype);
    for (const d of pp.data.lst) {
      measure(d, _p.gecfg);
    }
    let hasgain = false, hasloss = false, hassv = false, hasase = false, hasoutlier = false;
    for (const d of pp.data.lst) {
      if (d.gain) hasgain = true;
      if (d.loss) hasloss = true;
      if (d.sv) hassv = true;
      if (d.estat.ase_monoallelic || d.estat.ase_uncertain || d.estat.ase_biallelic) hasase = true;
      if (d.estat.outlier || d.estat.outlier_asehigh) hasoutlier = true;
    }
    pp.statuscolumns = [];
    if (hasgain) {
      pp.statuscolumns.push({
        name: label_cnvgain
        //width:20,
      });
    }
    if (hasloss) {
      pp.statuscolumns.push({
        name: label_cnvloss
        //width:20,
      });
    }
    if (hassv) {
      pp.statuscolumns.push({
        name: label_sv,
        width: 20
      });
    }
    if (hasase) {
      pp.statuscolumns.push({
        name: label_ase,
        width: 20
      });
    }
    if (hasoutlier) {
      pp.statuscolumns.push({
        name: label_outlier,
        width: 20
      });
    }
    for (const d of pp.data.lst) {
      d.rowg = pp.g0.append("g");
      if (d.gain || d.loss || d.sv || d.estat.ase_monoallelic || d.estat.ase_biallelic || d.estat.ase_uncertain) {
        d.rowbg = d.rowg.append("rect").attr("class", "sja_bgbox");
      }
      d.circle = d.rowg.append("circle").attr("fill", "white").attr("fill-opacity", 0).attr("stroke", "#858585").on("mouseover", (event) => {
        tooltip_pp(d, _p.tip.clear().d, pp);
        _p.tip.show(event.clientX, event.clientY);
      }).on("mouseout", () => {
        _p.tip.hide();
      });
      if (_p.clicksample) {
        d.circle.on("click", () => {
          _p.clicksample(d, group, _p);
        });
      }
      const status2cell = /* @__PURE__ */ new Map();
      if (d.gain) {
        const cell = { g: d.rowg.append("g") };
        cell.rect = cell.g.append("rect").attr("fill", _p.color.cnvgain);
        status2cell.set(label_cnvgain, cell);
      }
      if (d.loss) {
        const cell = { g: d.rowg.append("g") };
        cell.rect = cell.g.append("rect").attr("fill", _p.color.cnvloss);
        status2cell.set(label_cnvloss, cell);
      }
      if (d.sv) {
        const cell = { g: d.rowg.append("g") };
        cell.rect = cell.g.append("rect").attr("fill", _p.color.sv);
        status2cell.set(label_sv, cell);
      }
      if (d.estat.ase_monoallelic || d.estat.ase_biallelic || d.estat.ase_uncertain) {
        const cell = { g: d.rowg.append("g") };
        cell.rect = cell.g.append("rect").attr("fill", ase_color(d, _p.gecfg)), cell.label = cell.g.append("text").text(d.estat.ase_monoallelic ? "Mono" : d.estat.ase_biallelic ? "Bi" : "?").attr("font-family", font).attr("dominant-baseline", "central").attr("text-anchor", "middle").attr("fill", "white");
        status2cell.set(label_ase, cell);
      }
      if (d.estat.outlier) {
        const cell = { g: d.rowg.append("g") };
        cell.rect = cell.g.append("rect").attr("fill", _p.gecfg.outlier.color_outlier);
        status2cell.set(label_outlier, cell);
      } else if (d.estat.outlier_asehigh) {
        const cell = { g: d.rowg.append("g") };
        cell.rect = cell.g.append("rect").attr("fill", _p.gecfg.outlier.color_outlier_asehigh);
        status2cell.set(label_outlier, cell);
      }
      if (status2cell.size) {
        d.status2cell = status2cell;
        d.samplelabel = d.rowg.append("text").attr("font-family", font).attr("text-anchor", "end").attr("dominant-baseline", "central").text(d.sample);
      }
    }
    pp.place();
  };
  loadplot2(pp);
}
async function loadplot2(pp) {
  const _p = pp._plot;
  const arg = {
    genome: _p.genome.name,
    gene: _p.gene,
    chr: _p.chr,
    start: _p.start,
    stop: _p.stop,
    getgroup: pp.getgroup,
    getgroup_unannotated: pp.getgroup_unannotated,
    svcnv: _p.svcnv,
    sampleset: _p.sampleset
  };
  if (_p.dslabel) {
    arg.dslabel = _p.dslabel;
    arg.querykey = _p.querykey;
  } else {
    arg.iscustom = 1;
    arg.file = _p.file;
    arg.url = _p.url;
    arg.indexURL = _p.indexURL;
  }
  pp.g0.append("text").text("Loading ...").attr("font-size", 20).attr("text-anchor", "center").attr("dominant-baseline", "central").attr("x", pp.svg.attr("width") / 2).attr("y", pp.svg.attr("height") / 2);
  try {
    const data = await dofetch2("mdsgeneboxplot", { method: "POST", body: JSON.stringify(arg) });
    if (data.error) throw data.error;
    pp.g0.selectAll("*").remove();
    pp.data = data;
    pp.makegraph();
  } catch (e) {
    sayerror(pp.errdiv, "Error: " + (e.message || e));
    if (e.stack) console.log(e.stack);
  }
}
function tooltip_pp(d, holder, pp) {
  const lst = [{ k: "sample", v: d.sample }, { k: pp._plot.gecfg.datatype, v: d.value }];
  if (d.gain || d.loss || d.sv) {
    const l2 = [];
    if (d.gain) {
      l2.push(
        '<span style="padding:0px 5px;color:white;background:' + pp._plot.color.cnvgain + '">Copy number gain</span>'
      );
    }
    if (d.loss) {
      l2.push(
        '<span style="padding:0px 5px;color:white;background:' + pp._plot.color.cnvloss + '">Copy number loss</span>'
      );
    }
    if (d.sv) {
      l2.push('<span style="padding:0px 5px;color:white;background:' + pp._plot.color.sv + '">SV</span>');
    }
    lst.push({ k: "Overlap", v: l2.join(" ") });
  }
  const table = make_table_2col(holder, lst);
  showsingleitem_table(d, pp._plot.gecfg, table);
}
function mayaddgrouperselect(plot) {
  if (!plot.boxplotgroupers) return;
  const select = plot.buttonrow.append("select").on("change", (event) => {
    plot.index_boxplotgroupers = event.target.selectedIndex;
    loadplot(plot);
  });
  for (const [idx, name] of plot.boxplotgroupers.entries()) {
    select.append("option").text(name);
  }
}
export {
  init
};
//# sourceMappingURL=block.mds.geneboxplot-4BAJJWCC.js.map
