Thomas il y a 1 an
commit
321f8fd804
2 fichiers modifiés avec 220 ajouts et 0 suppressions
  1. BIN
      report.pdf
  2. 220 0
      report.typ

BIN
report.pdf


+ 220 - 0
report.typ

@@ -0,0 +1,220 @@
+#let cr_colors = (
+  dark_grey: rgb("#333333"), beige: rgb("#fdf0d5"), light_grey: rgb("#eeeeee"), dark_red: rgb("#780000"), red: rgb("#c1121f"), blue: rgb("#669bbc"), dark_blue: rgb("#003049"),
+)
+
+#import "@local/svg-emoji:0.1.0": setup-emoji, noto, github
+#show: setup-emoji.with(font: noto)
+
+#set page(paper: "a4", fill: cr_colors.light_grey)
+
+#show heading.where(level: 1): it => [
+  #set align(center)
+  #set text(fill: cr_colors.dark_blue)
+  #it.body
+  #v(18pt)
+]
+#show image: set text(font: "FreeSans")
+
+#set text(size: 16pt, font: "Futura", fill: cr_colors.dark_blue)
+#let contigs = (
+  "chr1", "chr2", "chr3", "chr4", "chr5", "chr6", "chr7", "chr8", "chr9", "chr10", "chr11", "chr12", "chr13", "chr14", "chr15", "chr16", "chr17", "chr18", "chr19", "chr20", "chr21", "chr22", "chrX", "chrY",
+)
+#let parseCustomDate(dateString) = {
+  let parts = dateString.split("T")
+  let datePart = parts.at(0).replace("-", "/")
+  let timePart = parts.at(1).split(":")
+  let hour = timePart.at(0)
+  let minute = timePart.at(1)
+
+  return datePart + " " + hour + "h" + minute
+}
+
+#let formatString(input) = {
+  let words = input.split("_")
+  let capitalizedWords = words.map(word => {
+    if word.len() > 0 {
+      upper(word.first()) + word.slice(1)
+    } else {
+      word
+    }
+  })
+  capitalizedWords.join(" ")
+}
+#let si-fmt(val, precision: 1, sep: "\u{202F}", binary: false) = {
+  let factor = if binary { 1024 } else { 1000 }
+  let gt1_suffixes = ("k", "M", "G", "T", "P", "E", "Z", "Y")
+  let lt1_suffixes = ("m", "μ", "n", "p", "f", "a", "z", "y")
+  let scale = ""
+  let unit = ""
+
+  if type(val) == content {
+    if val.has("text") {
+      val = val.text
+    } else if val.has("children") {
+      val = val.children.map(content => content.text).join()
+    } else {
+      panic(val.children.map(content => content.text).join())
+    }
+  }
+  // if val contains a unit, split it off
+  if type(val) == str {
+    unit = val.find(regex("(\D+)$"))
+    val = float(val.split(unit).at(0))
+  }
+
+  if calc.abs(val) > 1 {
+    for suffix in gt1_suffixes {
+      if calc.abs(val) < factor {
+        break
+      }
+      val /= factor
+      scale += " " + suffix
+    }
+  } else if val != 0 and calc.abs(val) < 1 {
+    for suffix in lt1_suffixes {
+      if calc.abs(val) > 1 {
+        break
+      }
+      val *= factor
+      scale += " " + suffix
+    }
+  }
+
+  let formatted = str(calc.round(val, digits: precision))
+
+  formatted + sep + scale.split().at(-1, default: "") + unit
+}
+
+#let reportCoverage(prefix) = {
+  image(prefix + "_global.svg", width: 100%)
+  for contig in contigs {
+    heading(level: 4, contig)
+    let path = prefix + "_" + contig
+    image(path + "_chromosome.svg")
+    let data = json(path + "_stats.json")
+    grid(
+      columns: (1fr, 2fr), gutter: 3pt, align(
+        left + horizon,
+      )[
+        #set text(size: 12pt)
+        #table(
+          stroke: none, columns: (auto, 1fr), gutter: 3pt, [Mean], [#calc.round(data.mean, digits: 2)], [Standard dev.], [#calc.round(data.std_dev, digits: 2)], ..data.breaks_values.map(r => ([#r.at(0)], [#calc.round(r.at(1) * 100, digits: 1)%])).flatten(),
+        )
+      ], align(right, image(path + "_distrib.svg", width: 100%)),
+    )
+
+    parbreak()
+  }
+}
+
+#let reportBam(path) = {
+  let data = json(path)
+  table(
+    gutter: 3pt, stroke: none, columns: (auto, 1fr), ..for (key, value) in data {
+      if key != "cramino" and key != "composition" and key != "path" and key != "modified" {
+        ([ #formatString(key) ], [ #value ])
+      } else if key == "modified" {
+        ([ Modified Date (UTC) ], [ #parseCustomDate(value) ])
+      } else if key == "composition" {
+        ([ Run(s) ], [
+          #for (i, v) in value.enumerate() {
+            if i > 0 [ \ ]
+            [#v.at(0).slice(0, 5): #calc.round(v.at(1), digits: 0)%]
+          }
+        ])
+      } else if key == "cramino" {
+        for (k, v) in value {
+          if k == "normalized_read_count_per_chromosome" {} else if k != "path" and k != "checksum" and k != "creation_time" and k != "file_name" {
+            let k = formatString(k)
+            let v = if type(v) == "integer" { si-fmt(v) } else { v }
+            ([ #k ], [ #v ])
+          } else {
+            ()
+          }
+        }.flatten()
+      } else {
+        ()
+      }
+    }.flatten(),
+  )
+}
+
+#let formatedReadCount(path) = {
+  let data = json(path)
+  let data = data.cramino.normalized_read_count_per_chromosome
+  let res = ()
+  for contig in contigs {
+    res.push(data.at(contig))
+  }
+  res.push(data.at("chrM"))
+  return res
+}
+
+#let printReadCount(diag_path, mrd_path) = {
+  let index = 14;
+  let c = contigs
+  c.push("chrM")
+  let diag = formatedReadCount(diag_path)
+  let mrd = formatedReadCount(mrd_path)
+  c.insert(0, "")
+  diag.insert(0, "diag")
+  mrd.insert(0, "mrd")
+  let arrays1 = (c.slice(0, index), diag.slice(0, index), mrd.slice(0, index))
+  table(columns: arrays1.at(0).len(), ..arrays1.map(arr => arr.map(item => [#item])).flatten())
+
+  let arrays2 = (c.slice(index), diag.slice(index), mrd.slice(index))
+  arrays2.at(0).insert(0, "")
+  arrays2.at(1).insert(0, "diag")
+  arrays2.at(2).insert(0, "mrd")
+
+  table(columns: arrays2.at(0).len(),  ..arrays2.map(arr => arr.map(item => [#item])).flatten())
+}
+#set heading(numbering: "1.")
+#heading(level: 1, outlined: false)[Compte Rendu]
+
+#outline(
+  title: "Table of Contents",
+  depth: 3
+)
+#pagebreak()
+== Identity
+Camara
+
+== Alignement
+#grid(
+  columns: (1fr, 1fr), gutter: 3pt, [
+    === Diagnostic sample
+    #set text(size: 11pt)
+    #reportBam(
+      "/Turbine-pool/LongReads/report/BECERRA/report/data/BECERRA_diag_hs1_info.json",
+    )
+  ], [
+    === MRD sample
+    #set text(size: 11pt)
+    #reportBam(
+      "/Turbine-pool/LongReads/report/BECERRA/report/data/BECERRA_mrd_hs1_info.json",
+    )
+    #set footnote(numbering: n => { " " })
+    #footnote[Values computed by #link("https://github.com/wdecoster/cramino")[cramino] v0.14.5
+    ]
+  ],
+)
+
+#pagebreak()
+=== Normalized read count by chromosome
+#[
+  #set text(size: 10pt)
+  #printReadCount("/Turbine-pool/LongReads/report/BECERRA/report/data/BECERRA_diag_hs1_info.json", "/Turbine-pool/LongReads/report/BECERRA/report/data/BECERRA_mrd_hs1_info.json")
+]
+
+=== Coverage by chromosome
+==== Proportion at given depth by chromosome
+#reportCoverage("/Turbine-pool/LongReads/report/BECERRA/report/data/scan/BECERRA")
+#set footnote(numbering: n => { " " })
+#footnote[Values computed by Pandora development version]
+#pagebreak()
+
+
+#lorem(150)
+❌
+#emoji.rocket