import {
  axisstyle,
  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 "./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 {
  json_default,
  plasma
} from "./chunk-KSGA62R2.js";
import {
  axisBottom,
  axisLeft
} from "./chunk-LOZEKOES.js";
import "./chunk-TOU7EVFQ.js";
import {
  linear
} from "./chunk-OAWQ6LOO.js";
import "./chunk-TLT4YIG3.js";
import "./chunk-KYBIQBXE.js";
import {
  select_default
} from "./chunk-I6Y4O3RR.js";
import {
  rgb_default
} from "./chunk-OMR2DT66.js";
import "./chunk-DQC5FFGV.js";
import "./chunk-HFNDKYVF.js";

// src/e2pca.js
var dullcolor = "#ccc";
function e2pca_inputui(hostURL, jwt) {
  const pane = newpane({ x: 100, y: 100 });
  pane.header.text("PCA - expression plot");
  const butrow = pane.body.append("div").style("margin", "20px");
  const div = pane.body.append("div").style("margin", "20px");
  const ta_pca = butrow.append("input").attr("size", 30).attr("placeholder", "PCA/SNE matrix file path").style("margin", "10px").property("value", "xiang/sep20/set1");
  const ta_db = butrow.append("input").attr("size", 30).attr("placeholder", "numerical db file path").style("margin", "10px").property("value", "xiang/sep20/set1.db");
  butrow.append("button").text("Submit").on("click", () => {
    div.selectAll("*").remove();
    const filepca = ta_pca.property("value");
    if (filepca == "") {
      div.text("No PCA file");
      return;
    }
    const filedb = ta_db.property("value");
    if (filedb == "") {
      div.text("No db file");
      return;
    }
    json_default(hostURL + "/textfile").post(JSON.stringify({ file: filepca, jwt }), (data) => {
      if (data.error) {
        div.text("Error getting file: " + data.error);
        return;
      }
      const [err, numdata2plot] = e2pca_plot({
        holder: div,
        text: data.text
      });
      if (err) {
        sayerror(div, err);
        return;
      }
      e2pca_genesearchui({
        holder: div.append("div"),
        numdata2plot,
        hostURL,
        jwt,
        obj: {
          dbfile: filedb
        }
      });
    });
  });
  butrow.append("button").text("Clear").on("click", () => {
    ta_pca.property("value", "");
    ta_db.property("value", "");
  });
  butrow.append("span").style("padding-left", "10px").html(
    "<a href=https://docs.google.com/document/d/1Midt0rYs1iIJveUMjeng9si3q31YelcNe_PI3Njce9E/edit?usp=sharing target=_blank>Help</a>"
  );
}
function e2pca_plot(arg) {
  const samples = [];
  const lines = arg.text.split(/\r?\n/);
  for (let i = 0; i < lines.length; i++) {
    const line = lines[i];
    if (!line) continue;
    const l = line.split("	");
    const samplename = l[0];
    const x = Number.parseFloat(l[1]);
    const y = Number.parseFloat(l[2]);
    if (Number.isNaN(x)) {
      return ["invalid x value at line " + (i + 1)];
    }
    if (Number.isNaN(y)) {
      return ["invalid y value at line " + (i + 1)];
    }
    const s = {
      sample: samplename,
      x,
      y
    };
    if (arg.mdanno) {
      if (arg.mdanno.annotation[samplename]) {
        s.attr = [];
        for (const termkey in arg.mdanno.annotation[samplename]) {
          if (arg.mdanno.mdh[termkey]) {
            const valuekey = arg.mdanno.annotation[samplename][termkey];
            if (arg.mdanno.mdh[termkey].values[valuekey]) {
              s.attr.push({
                k: arg.mdanno.mdh[termkey].label,
                v: arg.mdanno.mdh[termkey].values[valuekey].label
              });
            } else {
              s.attr.push({
                k: arg.mdanno.mdh[termkey].label,
                v: valuekey
              });
            }
          } else {
            s.attr.push({
              k: termkey,
              v: "unknown term key"
            });
          }
        }
      }
    }
    samples.push(s);
  }
  if (samples.length == 0) {
    return ["no samples"];
  }
  let value2color;
  if (arg.obj && arg.obj.colorscale && arg.obj.colorscale.from && arg.obj.colorscale.to) {
    value2color = rgb_default(arg.obj.colorscale.from, arg.obj.colorscale.to);
  } else {
    value2color = plasma;
  }
  let minx = samples[0].x, maxx = samples[0].x, miny = samples[0].y, maxy = samples[0].y;
  for (const s of samples) {
    minx = Math.min(minx, s.x);
    maxx = Math.max(maxx, s.x);
    miny = Math.min(miny, s.y);
    maxy = Math.max(maxy, s.y);
  }
  const svgholder = arg.holder.append("div").style("display", "inline-block");
  const menu = new Menu({ padding: "5px" });
  const svg = svgholder.append("svg");
  let toppad = 30, bottompad = 50, leftpad = 100, rightpad = 30, vpad = 20, width = 500, height = 500;
  const xaxisg = svg.append("g");
  const yaxisg = svg.append("g");
  const dotg = svg.append("g");
  const dots = dotg.selectAll().data(samples).enter().append("g");
  const circles = dots.append("circle").attr("fill", "#aaa").attr("stroke", "none").on("mouseover", (event, d) => {
    event.target.setAttribute("stroke", "white");
    menu.clear();
    menu.show(event.clientX, event.clientY);
    const lst = [{ k: "name", v: d.sample }];
    if (d.value != void 0) {
      lst.push({ k: "value", v: d.value });
    }
    if (d.attr) {
      for (const v of d.attr) {
        lst.push(v);
      }
    }
    make_table_2col(menu.d, lst);
  }).on("mouseout", (event, d) => {
    event.target.setAttribute("stroke", "none");
    menu.hide();
  });
  if (arg.obj) {
    arg.obj.circles = circles;
  }
  const xscale = linear().domain([minx, maxx]);
  const yscale = linear().domain([miny, maxy]);
  function resize() {
    const radius = 3;
    bottompad = width / 20 + 20;
    svg.attr("width", leftpad + vpad + width + rightpad).attr("height", toppad + height + vpad + bottompad);
    xaxisg.attr("transform", "translate(" + (leftpad + vpad) + "," + (toppad + height + vpad) + ")");
    yaxisg.attr("transform", "translate(" + leftpad + "," + toppad + ")");
    dotg.attr("transform", "translate(" + (leftpad + vpad) + "," + toppad + ")");
    xscale.range([0, width]);
    yscale.range([height, 0]);
    axisstyle({
      axis: xaxisg.call(axisBottom().scale(xscale)),
      color: "black",
      fontsize: width / 40,
      showline: true
    });
    axisstyle({
      axis: yaxisg.call(axisLeft().scale(yscale)),
      color: "black",
      fontsize: height / 40,
      showline: true
    });
    dots.attr("transform", (d) => "translate(" + xscale(d.x) + "," + yscale(d.y) + ")");
    circles.attr("r", radius);
  }
  resize();
  const underdiv = svgholder.append("div").style("position", "relative");
  {
    const row = arg.toprow || underdiv;
    row.append("button").style("margin-right", "20px").text("SVG").on("click", () => to_svg(svg.node(), "plot"));
  }
  const legendholder = underdiv.append("div").style("margin", "10px 10px 10px 30px");
  if (arg.obj) {
    arg.obj.legendholder = legendholder;
  }
  underdiv.append("div").style("position", "absolute").style("right", "0px").style("top", "0px").attr("class", "sja_clbtext").text("drag to resize").on("mousedown", (event) => {
    event.preventDefault();
    const b = select_default(document.body);
    const x = event.clientX;
    const y = event.clientY;
    const w0 = width;
    const h0 = height;
    b.on("mousemove", (event2) => {
      width = w0 + event2.clientX - x;
      height = h0 + event2.clientY - y;
      resize();
    });
    b.on("mouseup", (event2) => {
      b.on("mousemove", null).on("mouseup", null);
    });
  });
  let usezscore = false;
  const numdata2plot = (data, genename) => {
    const sample2data = /* @__PURE__ */ new Map();
    let maxv = data[0].value, minv = data[0].value;
    for (const i of data) {
      sample2data.set(i.sample, i.value);
      maxv = Math.max(maxv, i.value);
      minv = Math.min(minv, i.value);
    }
    let mean, std;
    if (usezscore) {
      mean = data.reduce((i, j) => i + j.value, 0) / data.length;
      std = Math.sqrt(data.reduce((i, j) => i + Math.pow(j.value - mean, 2), 0) / data.length);
      console.log(mean, std);
      minv = maxv = 0;
      data.forEach((i) => {
        const zscore = (i.value - mean) / std;
        minv = Math.min(minv, zscore);
        maxv = Math.max(maxv, zscore);
      });
    }
    circles.attr("fill", (d) => {
      if (sample2data.has(d.sample)) {
        let v = sample2data.get(d.sample);
        d.value = v;
        if (usezscore) {
          v = (v - mean) / std;
          d.value = v;
        }
        const scalev = (v - minv) / (maxv - minv);
        return value2color(scalev);
      }
      d.value = void 0;
      return dullcolor;
    });
    dots.each(function(d) {
      if (d.value != void 0) {
        this.parentNode.appendChild(this);
      }
    });
    legendholder.selectAll("*").remove();
    legendholder.append("span").html(genename + "&nbsp;");
    legendholder.append("span").html("min: " + minv + "&nbsp;");
    const colorlst = [];
    for (let i = 0; i <= 1; i += 0.1) {
      colorlst.push(value2color(i));
    }
    legendholder.append("div").style("display", "inline-block").style("width", "150px").style("height", "20px").style("background", "linear-gradient(to right," + colorlst.join(",") + ")").style("border", "solid 1px " + dullcolor);
    legendholder.append("span").html("&nbsp;max: " + maxv);
    const row = legendholder.append("div").style("margin-top", "10px");
    const id = Math.random().toString();
    row.append("input").attr("type", "checkbox").style("margin-right", "10px").property("checked", usezscore).attr("id", id).on("change", () => {
      usezscore = !usezscore;
      numdata2plot(data, genename);
    });
    row.append("label").attr("for", id).text("apply Z-score");
  };
  return [null, numdata2plot];
}
function e2pca_genesearchui(arg) {
  const geneta = arg.holder.append("input").attr("placeholder", "search gene").attr("padding-right", "20px");
  const genesearchsays = arg.holder.append("span");
  geneta.on("keyup", (event) => {
    genesearchsays.text("");
    if (event.code != "Enter") return;
    const gene = geneta.property("value");
    if (!gene) return;
    geneta.property("value", "");
    json_default(arg.hostURL + "/dbdata").post(
      JSON.stringify({ db: arg.obj.dbfile, tablename: "data", keyname: "gene", key: gene.toLowerCase(), jwt: arg.jwt }),
      (data) => {
        if (data.error) {
          genesearchsays.text("error getting data: " + data.error);
          return;
        }
        if (!data.rows) {
          genesearchsays.text(".rows missing");
          return;
        }
        if (data.rows.length == 0) {
          genesearchsays.text("no match for " + gene);
          return;
        }
        arg.obj.expressiondata = data.rows;
        arg.obj.searchedgene = gene;
        arg.numdata2plot(data.rows, gene);
        if (arg.callback) {
          arg.callback();
        }
      }
    );
  });
}
export {
  e2pca_genesearchui,
  e2pca_inputui,
  e2pca_plot
};
//# sourceMappingURL=e2pca-KOAAU2JX.js.map
