How would I normalise and stack plots in lilaq

Bit of background - I have just submitted my PhD in Chemistry which I wrote in Latex (via Overleaf) and was reasonably happy with that. All of the graphs in my thesis were generated in OriginPro and exported as .png for compilation into Latex, but I have since discovered the world of typst and lilaq and am attempting to switch all of my future research reports/journal publication drafting etc. to typst. My use case is pretty simple but I’m relatively new to the language of typst and I guess coding in general, but am keen to learn.

I have been able to get lilaq to work in reading data from two csv files containing the data I want to plot and it produces a nice overlay graph (attached) using this code. What I would like to produce is is a graph similar to the attached image which plots multiple datasets which are normalised (i.e., the y-values in column 2 of Dataset 1 are scaled such that they are divided by the highest value in that column, resulting in y-values between [0,1], and then same for Dataset 2. I would then like to be able to stack them by a constant value (i.e. offset the y-values for Dataset 2 by 1). It doesn’t seem to let me upload the csv files as I’m a new user, but am sure an example could be made with any kind of curve to illustrate the point.

#import "@preview/lilaq:0.5.0" as lq

#let (x, y) = lq.load-txt(read("PXP2291_RW211g_Cuthz-R-3m_DMF_12min.csv"))
#let (q, r) = lq.load-txt(read("PXP2290_RW211f_Cuthz-R-3m_DMF_12min.csv"))

#lq.diagram(
  width: 10cm,height: 8cm,
  xlim: (3, 30),
  ylim: (0, 9000),
  legend: (position: top + right),
  margin: (top: 20%),
  xaxis: (subticks: 4, mirror: (ticks:false)),
  yaxis: (subticks: none),
  title: [PXRD Pattern],
  xlabel: [2θ (degrees)],
  ylabel: [Intensity (a.u.)],
  lq.plot(x, y, 
    label: [Experiment 1],
    mark-size: 2pt,
    color: red,
    smooth:false),

    lq.plot(q, r, 
    label: [Experiment 2],
    mark-size: 2pt,
    color: blue,
    smooth:false),
    
)

Any help would be greatly appreciated!

Hi @robbo911 and welcome to Typst and Lilaq!

In Typst, it is quite easy to do some scripting. For example, you can write a function for normalizing your data

#let normalize(values) = {
  let max = calc.max(..values)
  values.map(value => value / max)
}

so you can reuse this function for both your y and r arrays. Do you want to also rescale the bottom of your data, I mean bring the minimum down to 0? In this case, you’ll want this as your normalization function:

#let normalize(values) = {
  let min = calc.min(..values)
  let range = calc.max(..values) - min
  values.map(value => (value - min) / range)
}

After normalization, all that remains is to add 1 to the second array because now you know that both arrays will cover the range [0, 1].

Two tips for your diagram:

  • smooth: false is already the default, so you can omit it. Smoothing will usually only be useful very few scenarios.
  • If you have more than one plot like this, you can define a color cycle with one line of code instead of defining the colors within lq.plot: #show: lq.set-diagram(cycle: (red, blue)), see Using style cycles − Lilaq.
#let normalize(values) = {
  let min = calc.min(..values)
  let range = calc.max(..values) - min
  values.map(value => (value - min) / range)
}

#show: lq.set-diagram(cycle: (red, blue))

#lq.diagram(
  width: 10cm, height: 8cm,
  xlim: (3, 30),
  ylim: (0, 9000),
  legend: (position: top + right),
  margin: (top: 20%),
  xaxis: (subticks: 4, mirror: (ticks:false)),
  yaxis: (subticks: none),
  title: [PXRD Pattern],
  xlabel: [2θ (degrees)],
  ylabel: [Intensity (a.u.)],
  lq.plot(
    x, 
    normalize(y),
    label: [Experiment 1],
    mark-size: 2pt,
  ),
  lq.plot(
    q, 
    normalize(r).map(v => v + 1),
    label: [Experiment 2],
    mark-size: 2pt,
  )
)

2 Likes