- Bacterial growth curve: rate, doubling time, carrying capacity
- Enzyme kinetics: Km, kcat and catalytic efficiency
- Serial dilution plate counts and log reduction
- Predator-prey cycles of Lotka-Volterra
- qPCR: efficiency from the standard curve and relative expression
- Hemocytometer count: Poisson check and concentration
- Kleiber's law: allometry of the metabolic rate
- Flow cytometry: automatic gating of leukocytes
- Photosynthesis-irradiance curve (Jassby-Platt)
- Resting membrane potential: Nernst and Goldman
Bacterial growth curve: rate, doubling time, carrying capacity
The OD600 of an E. coli culture was read every hour. The script fits the logistic model OD = K/(1 + a.exp(-r.t)) and gives the growth rate, the doubling time in the exponential phase, the carrying capacity, the inflection time and the maximum growth rate r.K/4.
#1. OD600 of an E. coli culture, time in h; -> "[t]" "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12]"; -> "[od]" "[0.03, 0.056, 0.101, 0.182, 0.302, 0.496, 0.723, 1.028, 1.245, 1.466, 1.686, 1.708]"; #2. Logistic fit OD = K / 1 + a.exp of -r.t; json load "rx_ch_lg" (stat fit [t] [od] "logistic"); -> "[r]" (json select "rx_ch_lg" /b); -> "[a]" (json select "rx_ch_lg" /a); -> "[kk]" (json select "rx_ch_lg" /c); #3. Doubling time in exponential phase, inflection time, max growth rate; concat "r = " (math round [r] 3) " 1/h, doubling time = " (math round (math calc "ln(2)/[r]*60") 0) " min, K = " (math round [kk] 2) " OD, inflection at " (math round (math calc "ln([a])/[r]") 2) " h, max rate = " (math round (math calc "[r]*[kk]/4") 3) " OD/h"
r = 0.622 1/h, doubling time = 67 min, K = 1.81 OD, inflection at 6.6 h, max rate = 0.281 OD/h
- Fit the Gompertz model with
stat fit_modelto get the lag time. - Compare the growth rates of two strains with
stat ttest_2on replicates.
Enzyme kinetics: Km, kcat and catalytic efficiency
Initial rates were measured at eight substrate concentrations with 0.050 uM enzyme. The script fits the Michaelis-Menten equation by non-linear least squares (no Lineweaver-Burk bias), gives Km with its error, the turnover number kcat = Vmax/[E] and the catalytic efficiency kcat/Km in 1/M.s.
#1. Initial rates v in uM/s versus substrate S in uM, enzyme 0.050 uM; -> "[s]" "[1, 2.5, 5, 10, 20, 40, 80, 160]"; -> "[v]" "[0.3, 0.676, 1.224, 1.738, 2.573, 2.983, 3.752, 3.919]"; #2. Non-linear Michaelis-Menten fit, no Lineweaver-Burk bias; json load "rx_ch_mm" (stat fit_model "Vmax*S/(Km+S)" "S" [s] [v] "{\"Vmax\": 4, \"Km\": 10}"); -> "[vm]" (json select "rx_ch_mm" /parameters/Vmax); -> "[km]" (json select "rx_ch_mm" /parameters/Km); #3. Turnover number kcat and catalytic efficiency kcat/Km in 1/M.s; -> "[kcat]" (math calc "[vm]/0.050"); -> "[eff]" (unit calc (concat [kcat] " / (1 s) / (" [km] " umol/L)") "L/(mol*s)"); -> "[_format]" "sci 3"; concat "Vmax = " (math round [vm] 2) " uM/s, Km = " (math round_uncertainty [km] (json select "rx_ch_mm" /errors/Km)) " uM, kcat = " (math round [kcat] 1) " 1/s, kcat/Km = " (math calc "[eff]") " 1/M.s"
Vmax = 4.26 uM/s, Km = 13.8 ± 1.1 uM, kcat = 85.1 1/s, kcat/Km = 6.19E6 1/M.s
- Fit a competitive inhibition model on a second series with
stat fit_model. - Use the [_format] session variable to choose the display (sci, eng, fix).
Serial dilution plate counts and log reduction
Triplicate plates (0.1 mL spread) were counted at 10^-6 for the culture and at 10^-2 after a disinfectant. The script computes the CFU/mL with the relative 95 % margin of the triplicate and the log reduction of the treatment.
#1. Plate counts, 0.1 mL spread: culture at 10^-6, after disinfection at 10^-2; -> "[n0]" "[187, 203, 176]"; -> "[n1]" "[42, 51, 38]"; json load "rx_ch_cfu" (stat conf_interval_mean [n0] 0.95); #2. CFU per mL = mean count / dilution x plated volume; -> "[c0]" (math calc (concat (json select "rx_ch_cfu" /mean) "/(1e-6*0.1)")); -> "[c1]" (math calc (concat (stat mean [n1]) "/(1e-2*0.1)")); #3. Log reduction of the disinfectant, scientific display; -> "[_format]" "sci 3"; concat "N0 = " (math calc "[c0]") " CFU/mL +- " (math round (math calc (concat "100*" (json select "rx_ch_cfu" /margin) "/" (json select "rx_ch_cfu" /mean))) 1) " %, N = " (math round [c1] 0) " CFU/mL, log reduction = " (math round (math calc "log10([c0]/[c1])") 2)
N0 = 1.89E9 CFU/mL +- 17.9 %, N = 43700 CFU/mL, log reduction = 4.64
- Use
stat dist_inv "poisson"for an exact interval on a single plate. - Check the 30-300 countable range before averaging.
Predator-prey cycles of Lotka-Volterra
Hares and lynx follow the Lotka-Volterra equations. The script integrates the system, measures the period of the cycle with the autocorrelation of the prey population, and draws the phase portrait (lynx against hares), a closed orbit.
#1. Lotka-Volterra predator-prey: hares x, lynx y; json load "rx_lv" (num ode "{\"x\": \"1.0*x-0.1*x*y\", \"y\": \"0.075*x*y-1.5*y\"}" "{\"x\": 10, \"y\": 5}" 0 60 "{\"points\": 601}"); #2. Period of the cycle from the autocorrelation of the prey, time step 0.1; -> "[r]" (dsp autocorr (json select "rx_lv" /x) 300); json load "rx_ac" (dsp peaks [r] "{\"height\": 0.3}"); -> "[T]" (math calc (concat "0.1*" (json select "rx_ac" /indices[0]))); #3. Phase portrait: lynx against hares, a closed orbit; plot ode (json select "rx_lv" /) "x" "y"
The chart is shown in the Plot tab of the editor.
qPCR: efficiency from the standard curve and relative expression
From a dilution series, get the slope of Ct against log10 copies (covariance over variance) and the amplification efficiency; then compare a target gene in treated and control cells, normalized by GAPDH, with the Livak 2^-ddCt and the Pfaffl methods.
#1. qPCR standard curve: log10 of the copies per reaction and mean Ct; -> "[lq]" "[7, 6, 5, 4, 3]"; -> "[ct]" "[15.12, 18.49, 21.83, 25.21, 28.60]"; #2. Slope = covariance over variance of log10 Q, amplification efficiency E = 10^-1/slope; -> "[slope]" (/ (stat covariance [lq] [ct]) (stat variance [lq])); -> "[E]" (math calc "10^(-1/[slope])"); #3. Target gene and reference gene GAPDH, triplicate Ct, control versus treated cells; -> "[dT]" (- (stat mean "[24.12, 24.31, 24.05]") (stat mean "[21.93, 22.18, 22.02]")); -> "[dR]" (- (stat mean "[18.21, 18.10, 18.33]") (stat mean "[18.42, 18.30, 18.51]")); #4. Livak 2^-ddCt with E = 2, and Pfaffl ratio with the measured efficiency, reference gene E = 1.98; -> "[livak]" (math calc "2^([dT]-[dR])"); -> "[pfaffl]" (math calc "[E]^[dT]/1.98^[dR]"); concat "slope = " (math round [slope] 3) ", efficiency = " (math round (math calc "100*([E]-1)") 1) " %, R2 = " (math round (math pow (stat correlation [lq] [ct]) 2) 6) "; dCt target = " (math round [dT] 3) ", dCt GAPDH = " (math round [dR] 3) "; fold change Livak = " (math round [livak] 2) ", Pfaffl = " (math round [pfaffl] 2)
slope = -3.368, efficiency = 98.1 %, R2 = 0.999993; dCt target = 2.117, dCt GAPDH = -0.197; fold change Livak = 4.97, Pfaffl = 4.86
- Test the dCt of the biological replicates with
stat ttest_2before reporting the fold change - Get the limit of detection from the Ct of the lowest standards with
stat conf_interval_mean
Hemocytometer count: Poisson check and concentration
Yeast cells are counted in the 16 small squares of a Neubauer chamber. The script builds the frequency table, checks the Poisson distribution of the counts with the index of dispersion, and gives the cell concentration of the culture.
#1. Yeast cells counted in the 16 small squares of a Neubauer chamber, sample diluted 1:10; -> "[c]" "[7, 5, 9, 6, 8, 4, 7, 6, 10, 5, 7, 8, 6, 9, 7, 6]"; -> "[n]" 16; -> "[m]" (stat mean [c]); #2. Count distribution and Poisson check: variance over mean near 1, chi-square dispersion test; -> "[freq]" (stat frequency [c]); -> "[vm]" (/ (stat variance [c]) [m]); -> "[chi2]" (* (- [n] 1) [vm]); -> "[p]" (- 1 (stat dist_cdf "chi2" "[15]" [chi2])); #3. Concentration: a small square is 1/250 mm3, i.e. 4e-6 mL, times the dilution; -> "[conc]" (/ (* [m] 10) 0.000004); concat "mode = " (stat mode [c]) ", mean = " [m] ", population variance = " (stat pvariance [c]) ", variance/mean = " (math round [vm] 3) ", dispersion chi2 = " (math round [chi2] 2) " p = " (math round [p] 3) ", concentration = " (math round_sig [conc] 3) " cells/mL, squares with 7 cells: " (json load select "rx_p4d_freq" [freq] "/[3]/count") ", cumulative frequency up to 7: " (json select "rx_p4d_freq" "/[3]/cumulative_frequency")
mode = [6,7], mean = 6.875, population variance = 2.484375, variance/mean = 0.385, dispersion chi2 = 5.78 p = 0.983, concentration = 17200000 cells/mL, squares with 7 cells: 4, cumulative frequency up to 7: 0.6875
- A variance/mean far above 1 means clumping: re-vortex the sample and count again.
- Compute the 95 % Poisson confidence interval of the total count with
stat dist_invchi2.
Kleiber's law: allometry of the metabolic rate
Basal metabolic rates of seven mammals from the mouse to the cow are fitted with the allometric law B = a.M^b, then used for a 25 kg dog with its metabolic body mass M^3/4.
#1. Basal metabolic rate in W versus body mass in kg of 7 mammals, mouse to cow; -> "[m]" "[0.021, 0.29, 2.5, 11, 70, 160, 600]"; -> "[b]" "[0.17, 1.45, 7.6, 22.5, 82, 150, 410]"; #2. Allometric law B = a.M^b fitted by log-log regression; -> "[fit]" (stat fit [m] [b] "power"); -> "[a]" (json load select "rx_p4d_klb" [fit] "/a"); -> "[e]" (json select "rx_p4d_klb" "/b"); #3. Kleiber metabolic body mass M^3/4 as the fourth root of M^3, for a 25 kg dog; -> "[mb]" (math nroot (math power 25 3) 4); -> "[pred]" (* [a] (math power 25 [e])); #4. Mass-specific rate of the mouse against the cow; -> "[ratio]" (/ (/ 0.17 0.021) (/ 410 600)); concat "B = " (math round [a] 3) " M^" (math round [e] 3) " (Kleiber 3/4), r2 = " (math round (json select "rx_p4d_klb" "/r2") 4) ", dog 25 kg: M^0.75 = " (math round [mb] 2) " kg^0.75, BMR = " (math round [pred] 1) " W, mouse burns " (math round [ratio] 1) " times more per kg than the cow"
B = 3.465 M^0.752 (Kleiber 3/4), r2 = 0.9978, dog 25 kg: M^0.75 = 11.18 kg^0.75, BMR = 39 W, mouse burns 11.8 times more per kg than the cow
- Plot the log-log data with
pa xy_scatterto show the 3/4 slope. - Compare with the 2/3 surface law with
stat fit_modeland a fixed exponent.
Flow cytometry: automatic gating of leukocytes
Forward and side scatter events are grouped with a density-based clustering, which finds the lymphocyte, monocyte and granulocyte populations, leaves the debris out and gives the leukocyte differential.
#1. Flow cytometry: forward and side scatter of 20 leukocytes in channel units / 100, plus 2 debris events; -> "[ev]" "[[2.1, 1.0], [2.3, 1.2], [2.0, 0.9], [2.2, 1.1], [2.4, 1.0], [2.1, 1.3], [2.2, 0.8], [2.3, 0.9], [3.6, 2.2], [3.8, 2.4], [3.5, 2.1], [3.7, 2.5], [4.4, 5.8], [4.6, 6.1], [4.3, 5.9], [4.5, 6.3], [4.7, 6.0], [4.4, 6.2], [4.6, 5.7], [4.5, 6.0], [0.4, 3.9], [6.8, 0.3]]"; #2. Density-based gating: neighbours within 0.45, at least 3 events per population; ml cluster load_from_json "rx_p4d_fcm" 0.45 3 [ev]; -> "[k]" (ml cluster nb "rx_p4d_fcm"); #3. Size of each population and leukocyte differential; -> "[n0]" (ml cluster nb_point "rx_p4d_fcm" 0); -> "[n1]" (ml cluster nb_point "rx_p4d_fcm" 1); -> "[n2]" (ml cluster nb_point "rx_p4d_fcm" 2); -> "[tot]" (+ [n0] (+ [n1] [n2])); -> "[first]" (ml cluster point_get "rx_p4d_fcm" 2 0); ml cluster close "rx_p4d_fcm"; concat [k] " populations, sizes " [n0] ", " [n1] ", " [n2] " = " (math round (* 100 (/ [n0] [tot])) 1) " %, " (math round (* 100 (/ [n1] [tot])) 1) " %, " (math round (* 100 (/ [n2] [tot])) 1) " %, " (- 22 [tot]) " events left as debris, first event of population 3: " (string replace (string replace (string replace [first] [_n_] "") " " "") "," ", ")
3 populations, sizes 8, 4, 8 = 40 %, 20 %, 40 %, 2 events left as debris, first event of population 3: [4.4, 5.8]
- Show the gates with
ml cluster xy_scatterbefore closing the cluster. - Change the radius and the minimum points to see when monocytes merge with lymphocytes.
Photosynthesis-irradiance curve (Jassby-Platt)
Gross oxygen production of a diatom culture is measured at seven irradiances. The script fits the Jassby-Platt tanh model and derives the initial slope alpha, Pmax, the saturation onset Ik and the irradiance for 90 % of Pmax.
#1. Photosynthesis-irradiance curve of a diatom culture, gross O2 production in umol/mg Chl/h; -> "[i]" "[0, 25, 50, 100, 200, 400, 800]"; -> "[p]" "[0, 21.5, 40.2, 66.1, 88.9, 97.8, 99.6]"; #2. Jassby-Platt model P = Pmax.tanh of alpha.I/Pmax; -> "[fit]" (stat fit_model "pm*tanh(al*x/pm)" "x" [i] [p] "{\"pm\": 100, \"al\": 1}"); -> "[pm]" (json load select "rx_p4d_pi" [fit] "/parameters/pm"); -> "[al]" (json select "rx_p4d_pi" "/parameters/al"); #3. Saturation onset Ik = Pmax/alpha and irradiance for 90 % of Pmax: Ik.atanh 0.9; -> "[ik]" (/ [pm] [al]); -> "[i90]" (* [ik] (math atanh 0.9)); #4. Check the model at Ik: tanh 1 = 76 %; concat "Pmax = " (math round [pm] 1) ", alpha = " (math round [al] 3) ", Ik = " (math round [ik] 1) " umol photons/m2/s, I90 = " (math round [i90] 1) ", P at Ik = " (math round (* 100 (math tanh 1)) 1) " % of Pmax, r2 = " (math round (json select "rx_p4d_pi" "/r2") 4)
Pmax = 98, alpha = 0.816, Ik = 120 umol photons/m2/s, I90 = 176.7, P at Ik = 76.2 % of Pmax, r2 = 0.9986
- Add a photoinhibition term (Platt 1980) with
stat fit_modeland a third parameter beta. - Integrate the daily production over a sine light curve with
num integrate.
Resting membrane potential: Nernst and Goldman
For a mammalian neuron at 37 C, the script computes RT/F from the CODATA constants, the Nernst potential of K+ and the Goldman-Hodgkin-Katz resting potential, then the driving force and the direction of the K+ current.
#1. Mammalian neuron at 37 C: concentrations in mM, inside and outside, relative permeabilities K:Na:Cl = 1:0.04:0.45; -> "[ki]" 140; -> "[ko]" 5; -> "[nai]" 15; -> "[nao]" 145; -> "[cli]" 10; -> "[clo]" 110; -> "[t]" (unit convert 37 "degC" "K"); #2. RT/F in mV with the CODATA constants of math calc; -> "[rtf]" (math calc "1000*_R*[t]/_F"); #3. Nernst potential of K+ and Goldman-Hodgkin-Katz resting potential; -> "[ek]" (* [rtf] (math log (/ [ko] [ki]))); -> "[vm]" (* [rtf] (math log (/ (+ [ko] (+ (* 0.04 [nao]) (* 0.45 [cli]))) (+ [ki] (+ (* 0.04 [nai]) (* 0.45 [clo])))))); #4. Driving force on K+; concat "RT/F = " (math round [rtf] 2) " mV (F = " (constant physics_f) "), E_K = " (math round [ek] 1) " mV, GHK Vm = " (math round [vm] 1) " mV, K+ driving force = " (math round (- [vm] [ek]) 1) " mV, sign " (math signum (- [vm] [ek])) " = outward K+ current"
RT/F = 26.73 mV (F = 96485.33212331001 C/mol), E_K = -89.1 mV, GHK Vm = -67.3 mV, K+ driving force = 21.7 mV, sign 1 = outward K+ current
- Change the external K+ (hyperkalemia, 8 mM) and see the depolarisation.
- Solve the K+ permeability ratio that gives -70 mV with
num solve.
