Automatic calculator using input variables

I am essentially trying to re-create this website (https://wetflag.com/) where I input two values (a child’s age and weight) and then the page gives me a beautifully formatted (ideally in a table) set of calculated doses as determined by their age and weight:

Input:

Age: 12
Weight: 43 ← Ideally this input would be optional and if omitted it would be estimated from the age.

Typical output:

Title Formula (could be hidden) Output
Weight ( Age + 4 ) x 2 43kg
Energy 4 J x Weight 172J
Tube Internal Diameter = Age / 4 + 4 Length (oral) = Age / 2 + 12 Length (nasal) = Age /2 + 15 Internal Diameter: 7cm Length (oral): 18cm Length (nasal): 21cm
Fluids Medical = 20 ml x Weight Trauma = 10 ml x Weight Medical = 860mls Trauma = 430mls
Lorazepam 0.1mg x Weight 4.3mg
Adrenaline 0.1ml x Weight of 1:10,000 Adrenaline 4.3mls
Glucose 2ml x Weight of 10% Dextrose 86mls

This may be a feature request asking for a generic version of this: linked post only relates to generating pages from templates Executable templates and data driven documents

Edit: looks like I could do this with Macros, but I am not really interested in generating content for keeping - mostly just as a reference. And then when the next patient comes along, I would just input their values and the table would update.

Here you are:

  • Add a macro inside file config.edn , inside macros{} :
    :wetflag
    "
    <table id=\"results_table\" class=\"table kit\" data-kit=\"wetflag\" data-age=\"$1\" data-weight=\"$2\">
    <thead class=\"table-danger\">
    <tr>
        <th class=\"col1\" scope=\"col\">
        </th><th class=\"col2\" scope=\"col\">Formula</th>
        <th class=\"col3\" scope=\"col\">Result</th>
    </tr>
    </thead>
    <tbody>
    <tr>
        <th class=\"col1\">Age</th>
        <td class=\"col2\"> [given] </td>
        <td class=\"col3\"><span id=\"age_wetflag\"></span>years</td>
    </tr>
    <tr>
        <th class=\"col1\">Weight</th>
        <td class=\"col2\"> [given] </td>
        <td class=\"col3\"><span id=\"weight_wetflag\"></span>kg</td>
    </tr>
    <tr>
        <th class=\"col1\">Energy</th>
        <td class=\"col2\">4 J x Weight</td>
        <td class=\"col3\"><span id=\"energy_wetflag\"></span>J</td>
    </tr>
    <tr>
        <th class=\"col1\">Tube</th>
        <td class=\"col2\"><p>Internal Diameter = Age / 4 + 4</p><p>Length (oral) = Age / 2 + 12</p><p>Length (nasal) = Age /2 + 15</p></td>
        <td class=\"col3\"><p>Internal Diameter: <span id=\"ETT_ID_wetflag\"></span>cm</p><p>Length (oral): <span id=\"ETT_length_oral_wetflag\"></span>cm</p><p>Length (nasal): <span id=\"ETT_length_nasal_wetflag\"></span>cm</p></td>
    </tr>
    <tr>
        <th class=\"col1\">Fluids</th>
        <td class=\"col2\"><p>Medical = 20 ml x Weight</p><p>Trauma = 10 ml x Weight</p></td>
        <td><p>Medical = <span id=\"fluid_medical_wetflag\"></span>mls</p><p>Trauma = <span id=\"fluid_trauma_wetflag\"></span>mls</p></td>
    </tr>
    <tr>
        <th class=\"col1\">Lorazepam</th>
        <td class=\"col2\"><p>0.1mg x Weight</p></td>
        <td class=\"col3\"><span id=\"lorazepam_wetflag\"></span>mg</td>
    </tr>
    <tr>
        <th class=\"col1\">Adrenaline</th>
        <td class=\"col2\"><p>0.1ml x Weight of 1:10,000 Adrenaline</p></td>
        <td class=\"col3\"><span id=\"adrenaline_wetflag\"></span>mls</td>
    </tr>
    <tr>
        <th class=\"col1\">Glucose</th>
        <td class=\"col2\"><p>2ml x Weight of 10% Dextrose</p></td>
        <td class=\"col3\"><span id=\"glucose_wetflag\"></span>mls</td>
    </tr>
    </tbody>
    </table>
    "
    
  • The code below requires having kits inside file custom.js .
  • Inside page WetFlag in Logseq, put the following code in a javascript code-block:
    function weightFromAge(age){
        if (age < 1.5) return 0.5 * age + 4
        if (age < 5.5) return 2 * age + 8
        if (age < 13.5 ) return 3 * age + 7
        if (age < 16.5) return 4 * age + 2
        return 70
    }
      
    logseq.kits.wetflag = function wetflag(table){
        const dataAge = Number(table.dataset.age)
        const age = isNaN(dataAge) ? 1 : dataAge
      
        const dataWeight = Number(table.dataset.weight)
        const weight = isNaN(dataWeight) ? weightFromAge(age) : dataWeight
      
        const result = {
            age,
            weight,
            energy: 4 * weight,
            ETT_ID: age / 4 + 4,
            ETT_length_oral: age / 2 + 12,
            ETT_length_nasal: age / 2 + 15,
            fluid_medical: 20 * weight,
            fluid_trauma: 10 * weight,
            lorazepam: 0.1 * weight,
            adrenaline: 0.1 * weight / 1,
            glucose: 2 * weight
        }
      
        for (const id in result) {
            table.querySelector(`#${id}_wetflag`).textContent = result[id]
        }
    }
    
  • Now you can use it like {{wetflag 12, 40}}
    • Or omit the weight, e.g. {{wetflag 12}}
  • Though the calculations look doubtful.
  • It renders like this:
1 Like

Hello, @Harvs!

As an alternative, you could use 🏛 Full House Templates plugin.

Demo

2023-12-13 03.38.51

Setup

  1. Install plugin
  2. Copy the «wetflag» template code to any block in your graph
  3. Use command «Insert :classical_building:template or :classical_building:view» (⌘T or Ctrl+T) and insert «wetflag»

Template

- template:: wetflag
  template-list-as:: view
  template-usage:: `:age "{|}", :weight ""`
	- ```typescript
	  ``{
	    function weightFromAge(age) {
	      if (age <= 1)  return [0.5 * age + 4, '(Age / 2) + 4']
	      if (age <= 5)  return   [2 * age + 8, '(Age × 2) + 8']
	      if (age <= 13) return   [3 * age + 7, '(Age × 3) + 7']
	      if (age <= 16) return   [4 * age + 2, '(Age × 4) + 2']
	      return 70
	    }
	    
	    var age = Number(c.args.age)
	    var [weight, weightFormula] = weightFromAge(age)
	    if (c.args.weight) {
	      weight = Number(c.args.weight)
	      weightFormula = '[given]'
	    }
	  _}``
	  
	  <table id="results_table" class="table">
	  <thead class="table-danger">
	  <tr>
	      <th class="col1" scope="col"></th>
	      <th class="col2" scope="col">Formula</th>
	      <th class="col3" scope="col">Result</th>
	  </tr>
	  </thead>
	  <tbody>
	  <tr>
	      <th class="col1">Age</th>
	      <td class="col2">[given]</td>
	      <td class="col3"><span id="age_wetflag">``age``</span>years</td>
	  </tr>
	  <tr>
	      <th class="col1">Weight</th>
	      <td class="col2">``weightFormula``</td>
	      <td class="col3"><span id="weight_wetflag">``weight``</span>kg</td>
	  </tr>
	  <tr>
	      <th class="col1">Energy</th>
	      <td class="col2">4 J × Weight</td>
	      <td class="col3"><span id="energy_wetflag">``4 * weight``</span>J</td>
	  </tr>
	  <tr>
	      <th class="col1">Tube</th>
	      <td class="col2">
	        <p>Internal Diameter = Age / 4 + 4</p>
	        <p>Length (oral) = Age / 2 + 12</p>
	        <p>Length (nasal) = Age / 2 + 15</p>
	      </td>
	      <td class="col3">
	        <p>Internal Diameter: <span id="ETT_ID_wetflag">``age / 4 + 4``</span>cm</p>
	        <p>Length (oral): <span id="ETT_length_oral_wetflag">``age / 2 + 12``</span>cm</p>
	        <p>Length (nasal): <span id="ETT_length_nasal_wetflag">``age / 2 + 15``</span>cm</p>
	      </td>
	  </tr>
	  <tr>
	      <th class="col1">Fluids</th>
	      <td class="col2">
	        <p>Medical = 20 ml × Weight</p>
	        <p>Trauma = 10 ml × Weight</p>
	      </td>
	      <td class="col3">
	          <p>Medical = <span id="fluid_medical_wetflag">``weight * 20``</span>mls</p>
	          <p>Trauma = <span id="fluid_trauma_wetflag">``weight * 10``</span>mls</p>
	      </td>
	  </tr>
	  <tr>
	      <th class="col1">Lorazepam</th>
	      <td class="col2"><p>0.1mg × Weight</p></td>
	      <td class="col3"><span id="lorazepam_wetflag">``weight * 0.1``</span>mg</td>
	  </tr>
	  <tr>
	      <th class="col1">Adrenaline</th>
	      <td class="col2"><p>0.1ml × Weight of 1:10,000 Adrenaline</p></td>
	      <td class="col3"><span id="adrenaline_wetflag">``weight * 0.1``</span>mls</td>
	  </tr>
	  <tr>
	      <th class="col1">Glucose</th>
	      <td class="col2"><p>2ml × Weight of 10% Dextrose</p></td>
	      <td class="col3"><span id="glucose_wetflag">``weight * 2``</span>mls</td>
	  </tr>
	  </tbody>
	  </table>
	  ```

And another approach via template (not view) and properties:
2023-12-13 04.03.05

And then you could use queries to list all clients data!

Template

- template:: wetflag via props
  template-list-as:: template
  template-usage:: `:client [[client {|}]], :age "", :weight ""`
	- ```typescript
	  ``{
	    function weightFromAge(age) {
	      if (age <= 1)  return [0.5 * age + 4, '(Age / 2) + 4']
	      if (age <= 5)  return   [2 * age + 8, '(Age × 2) + 8']
	      if (age <= 13) return   [3 * age + 7, '(Age × 3) + 7']
	      if (age <= 16) return   [4 * age + 2, '(Age × 4) + 2']
	      return 70
	    }
	  
	    var age = Number(c.args.age)
	    var [weight, weightFormula] = weightFromAge(age)
	    if (c.args.weight) {
	      weight = Number(c.args.weight)
	      weightFormula = '[given]'
	    }
	  _}``
	  
	  #work ``[c.args.client]``
	  Age:: ``age``years
	  Weight:: ``weight``kg
	  Energy:: ``4 * weight``J
	  Tube/Internal-Diameter:: ``age / 4 + 4``cm
	  Tube/Length-oral:: ``age / 2 + 12``cm
	  Tube/Length-nasal:: ``age / 2 + 15``cm
	  Fluids/Medical:: ``weight * 20``mls
	  Fluids/Trauma:: ``weight * 10``mls
	  Lorazepam:: ``weight * 0.1``mg
	  Adrenaline:: ``weight * 0.1``mls
	  Glucose:: ``weight * 2``mls
	  ```

I hope the folks answering feel useful, this is a really helpful set of responses and looks like they took some work to give the OP what they were asking for. Well done!

5 Likes

Thank you for your replies.

Whilst the templating function is certainly useful and will no doubt be useful to many people, the solution I was looking for was a static page with a field box that updated the table. Im still hunting

@Harvs here is another approach, when you could use blocks as an input boxes and auto-refreshable table.

2024-04-11 01.14.39

Template

- template:: wetflag
  template-list-as:: view
	- ```typescript
	  ``{
	    function weightFromAge(age) {
	      if (age <= 1)  return [0.5 * age + 4, '(Age / 2) + 4']
	      if (age <= 5)  return   [2 * age + 8, '(Age × 2) + 8']
	      if (age <= 13) return   [3 * age + 7, '(Age × 3) + 7']
	      if (age <= 16) return   [4 * age + 2, '(Age × 4) + 2']
	      return [70, 'value for Age > 16']
	    }
	    
	    var [age, weight] = (await logseq.Editor.getBlock(c.block.id, {includeChildren: true})).children
	    if (!age || !age.content)
	      return 'Specify Age in the first child block. And optional Weight in the second one.'
	  
	    age = Number(age.content)
	    var weightFormula
	    if (weight && weight.content) {
	      weight = Number(weight.content)
	      weightFormula = '[given]'
	    } else {
	      [weight, weightFormula] = weightFromAge(age)
	    }
	  _}``
	  
	  <table id="results_table" class="table">
	  <thead class="table-danger">
	  <tr>
	      <th class="col1" scope="col"></th>
	      <th class="col2" scope="col">Formula</th>
	      <th class="col3" scope="col">Result</th>
	  </tr>
	  </thead>
	  <tbody>
	  <tr>
	      <th class="col1">Age</th>
	      <td class="col2">[given]</td>
	      <td class="col3"><span id="age_wetflag">``age``</span>years</td>
	  </tr>
	  <tr>
	      <th class="col1">Weight</th>
	      <td class="col2">``weightFormula``</td>
	      <td class="col3"><span id="weight_wetflag">``weight``</span>kg</td>
	  </tr>
	  <tr>
	      <th class="col1">Energy</th>
	      <td class="col2">4 J × Weight</td>
	      <td class="col3"><span id="energy_wetflag">``4 * weight``</span>J</td>
	  </tr>
	  <tr>
	      <th class="col1">Tube</th>
	      <td class="col2">
	        <p>Internal Diameter = Age / 4 + 4</p>
	        <p>Length (oral) = Age / 2 + 12</p>
	        <p>Length (nasal) = Age / 2 + 15</p>
	      </td>
	      <td class="col3">
	        <p>Internal Diameter: <span id="ETT_ID_wetflag">``age / 4 + 4``</span>cm</p>
	        <p>Length (oral): <span id="ETT_length_oral_wetflag">``age / 2 + 12``</span>cm</p>
	        <p>Length (nasal): <span id="ETT_length_nasal_wetflag">``age / 2 + 15``</span>cm</p>
	      </td>
	  </tr>
	  <tr>
	      <th class="col1">Fluids</th>
	      <td class="col2">
	        <p>Medical = 20 ml × Weight</p>
	        <p>Trauma = 10 ml × Weight</p>
	      </td>
	      <td class="col3">
	          <p>Medical = <span id="fluid_medical_wetflag">``weight * 20``</span>mls</p>
	          <p>Trauma = <span id="fluid_trauma_wetflag">``weight * 10``</span>mls</p>
	      </td>
	  </tr>
	  <tr>
	      <th class="col1">Lorazepam</th>
	      <td class="col2"><p>0.1mg × Weight</p></td>
	      <td class="col3"><span id="lorazepam_wetflag">``(weight * 0.1).toPrecision(2)``</span>mg</td>
	  </tr>
	  <tr>
	      <th class="col1">Adrenaline</th>
	      <td class="col2"><p>0.1ml × Weight of 1:10,000 Adrenaline</p></td>
	      <td class="col3"><span id="adrenaline_wetflag">``(weight * 0.1).toPrecision(2)``</span>mls</td>
	  </tr>
	  <tr>
	      <th class="col1">Glucose</th>
	      <td class="col2"><p>2ml × Weight of 10% Dextrose</p></td>
	      <td class="col3"><span id="glucose_wetflag">``weight * 2``</span>mls</td>
	  </tr>
	  </tbody>
	  </table>
	  ```
1 Like
  • What if we:
    • forget about tables and html
    • use directly Logseq’s outliner
  • Steps:
    • Setup Synthesis
    • Paste the following markdown
      -
      - Age: {{cell 1 years}}
      - Weight: {{cell weight from (Age) ) as kg}}
      - Energy: {{cell 4 * (Weight) ) as J}}
      - Tube
      	- Internal Diameter: {{cell (Age) / 4 + 4 ) as cm}}
      	- Length
      		- oral: {{cell (Age) / 2 + 12 ) as cm}}
      		- nasal: {{cell (Age) / 2 + 15 ) as cm}}
      - Fluids
      	- Medical: {{cell 20 * (Weight) ) as mls}}
      	- Trauma: {{cell 10 * (Weight) ) as mls}}
      - Lorazepam: {{cell 0.1 * (Weight) ) as mg}}
      - Adrenaline: {{cell 0.1 * (Weight) / 1 ) as mls}}
      - Glucose: {{cell 2 * (Weight) ) as mls}}
      -
      - Code
        collapsed:: true
      	- some num some word: that num as that word
      	- weight from some input-years: age= value of that input; age-1
      		- age-1: if (?age < 1.5) then (0.5 * ?age + 4) else age-2
      		- age-2: if (?age < 5.5) then (2 * ?age + 8) else age-3
      		- age-3: if (?age < 13.5 ) then (3 * ?age + 7) else age-4
      		- age-4: if (?age < 16.5) then (4 * ?age + 2) else 70
      -
      
    • Get live cell-blocks:
      image
2 Likes

Hi, I am trying to do something similar, albeit simpler, by calculating PERT times, which basically calculate a project’s expected timeline via this formula: E=(o+4*m+p)/6 where E stands for expected time, o for optimistic time and p for pessimistic time. To make things simpler and since I don’t have very long term projects I am doing my calculations in days. Any ideas on how I could incorporate this in logseq?

You can do it with many approaches. You have to choose one of them based on criteria like these ones:

  • How would you like to provide the formula’s parameters?
  • Do you need a formatted output or just a plain number?
  • Which approach do you prefer?
    • a simple calculator: Logseq already provides this one
    • an advanced plugin: 🏛 Full House Templates
      • Plugins don’t currently work on mobile.
    • a macro:
    • Could even try all of them and see which one is more intuitive to you.
1 Like