Examples
Example 1: Basic Usage
In the first example we will correct a measured response vector of the M-57 alanine fragment. First the chemical formula of the fragment and the response vector have to be defined, after which the uncorrected mass isotopomer distribution (MID) can be calculated.
The number after "LabC" in the chemical formula represents the number of possibly labeled carbon atoms in the fragment while the number behind "C" is the total number of carbon atoms, both from the alanine and from any derivative groups.
using IsotopeCorrection
ala_m57 = "C11H26N1O2Si2LabC3"
response_vec = [2500000, 2000000, 2500000, 800000]
MID = response_vec ./ sum(response_vec)
4-element Vector{Float64}:
0.32051282051282054
0.2564102564102564
0.32051282051282054
0.10256410256410256
The function isotope_correction()
` can be directly used on a single measurement vector. Here we are assuming that the tracer used for this experiment had an 80% purity.
corr_resp, corr_MID, mean_enrich, residuum = isotope_correction(response_vec,
ala_m57;
tracer_purity = 0.8)
([3.0266026323459675e6, 819243.5134320183, 3.666924789018221e6, 587930.8175325774], [0.37362227679544946, 0.10113241278096713, 0.4526675467300171, 0.07257776369356636], 0.5560501993304251, [-2.022641591536693e-13, -2.999336291582156e-13, 3.788572473403735e-13, 2.28532231771029e-13])
corr_resp
` is the corrected measurement vector,
corr_resp
4-element Vector{Float64}:
3.0266026323459675e6
819243.5134320183
3.666924789018221e6
587930.8175325774
corr_MID
is the MID of the corrected measurement vector,
corr_MID
4-element Vector{Float64}:
0.37362227679544946
0.10113241278096713
0.4526675467300171
0.07257776369356636
mean_enrich
is the mean enrichment of the corrected measurement vector,
mean_enrich
0.5560501993304251
and residuum
is the residals of the optimization.
residuum
4-element Vector{Float64}:
-2.022641591536693e-13
-2.999336291582156e-13
3.788572473403735e-13
2.28532231771029e-13
The optimization can also be turned off, using the optimization = false
keyword argument, though this isn't recommended as the optimization prevents negative values in the corrected response.
To visualize the effects of isotope_correction()
, the MID can be plotted before and after correction.
using ColorSchemes, CairoMakie
colors = colorschemes[:bamako][1:64:end];
group_color = [PolyElement(color = color, strokecolor = :transparent)
for color in colors]
labels = ["m+0", "m+1", "m+2", "m+3"]
Mplus = [0, 1, 2, 3]
fig = Figure();
ax = Axis(fig[1,1],
xticks = (1:2, ["uncorrected", "corrected"]),
title = "Alanine (M-57) MID")
barplot!(ax, repeat([1, 2], inner = length(corr_MID)),
cat(MID, corr_MID, dims = 1),
stack = repeat(Mplus, 2),
colormap = colors,
color = repeat(Mplus .+ 1, 2))
Legend(fig[1,2], group_color, labels, framevisible = false)
fig

Example 2: Usage with a DataFrame
For this example we will make a very simple DataFrame with 2 samples for each of which 2 methionine fragments were measured, specifically M-159 and M-57. We need the chemical formulas of both fragments, as shown in the code below, as well as measured response vectors. For this example the measured response for sample 1 is all possible m+ being recorded with equal frequency while the measured response for sample 2 is simply a random vector.
The number after "LabC" in the chemical formula represents the number of possibly labeled carbon atoms in the fragment while the number behind "C" is the total number of carbon atoms, both from the methionine and from any derivative groups.
using IsotopeCorrection
using DataFrames, DataFramesMeta
df = DataFrame(
Sample = repeat([1, 2], inner = 11),
AminoAcidFragment = repeat(cat(repeat(["Met_(M-159)"], 5), repeat(["Met_(M-57)"], 6), dims = 1), 2),
Molecule = repeat(cat(repeat(["C10H24N1S1Si1LabC4"], 5), repeat(["C13H30N1O2S1Si2LabC5"], 6), dims = 1), 2),
MZ0 = repeat(cat(repeat([218], 5), repeat([320], 6), dims = 1), 2),
Mplus = repeat(cat(repeat(0:4, 1), repeat(0:5, 1), dims = 1), 2),
Response = cat(repeat([3e6/5], 5), repeat([3e6/6], 6), rand(0:3e6, 11), dims = 1))
# Of course normally the first step would be to read in (and prepare) real data,
# using CSV.jl or XLSX.jl, for example.
# using CSV
# df = CSV.read("DATA.csv", DataFrame)
Row | Sample | AminoAcidFragment | Molecule | MZ0 | Mplus | Response |
---|---|---|---|---|---|---|
Int64 | String | String | Int64 | Int64 | Float64 | |
1 | 1 | Met_(M-159) | C10H24N1S1Si1LabC4 | 218 | 0 | 600000.0 |
2 | 1 | Met_(M-159) | C10H24N1S1Si1LabC4 | 218 | 1 | 600000.0 |
3 | 1 | Met_(M-159) | C10H24N1S1Si1LabC4 | 218 | 2 | 600000.0 |
4 | 1 | Met_(M-159) | C10H24N1S1Si1LabC4 | 218 | 3 | 600000.0 |
5 | 1 | Met_(M-159) | C10H24N1S1Si1LabC4 | 218 | 4 | 600000.0 |
6 | 1 | Met_(M-57) | C13H30N1O2S1Si2LabC5 | 320 | 0 | 500000.0 |
7 | 1 | Met_(M-57) | C13H30N1O2S1Si2LabC5 | 320 | 1 | 500000.0 |
8 | 1 | Met_(M-57) | C13H30N1O2S1Si2LabC5 | 320 | 2 | 500000.0 |
9 | 1 | Met_(M-57) | C13H30N1O2S1Si2LabC5 | 320 | 3 | 500000.0 |
10 | 1 | Met_(M-57) | C13H30N1O2S1Si2LabC5 | 320 | 4 | 500000.0 |
11 | 1 | Met_(M-57) | C13H30N1O2S1Si2LabC5 | 320 | 5 | 500000.0 |
12 | 2 | Met_(M-159) | C10H24N1S1Si1LabC4 | 218 | 0 | 818334.0 |
13 | 2 | Met_(M-159) | C10H24N1S1Si1LabC4 | 218 | 1 | 261575.0 |
14 | 2 | Met_(M-159) | C10H24N1S1Si1LabC4 | 218 | 2 | 2.5839e6 |
15 | 2 | Met_(M-159) | C10H24N1S1Si1LabC4 | 218 | 3 | 1.14897e6 |
16 | 2 | Met_(M-159) | C10H24N1S1Si1LabC4 | 218 | 4 | 231407.0 |
17 | 2 | Met_(M-57) | C13H30N1O2S1Si2LabC5 | 320 | 0 | 1.17069e6 |
18 | 2 | Met_(M-57) | C13H30N1O2S1Si2LabC5 | 320 | 1 | 678027.0 |
19 | 2 | Met_(M-57) | C13H30N1O2S1Si2LabC5 | 320 | 2 | 2.97735e6 |
20 | 2 | Met_(M-57) | C13H30N1O2S1Si2LabC5 | 320 | 3 | 541298.0 |
21 | 2 | Met_(M-57) | C13H30N1O2S1Si2LabC5 | 320 | 4 | 1.82826e6 |
22 | 2 | Met_(M-57) | C13H30N1O2S1Si2LabC5 | 320 | 5 | 1.65989e6 |
Using DataFramesMeta the DataFrame can be grouped based on the sample ID and amino acid fragment and each group corrected using the main function of this package: isotope_correction()
Since this function outputs the corrected response, MID, mean enrichment and residuum, we index into element 1 to recieve only the corrected response. Additionally we are assuming that the tracer used for this experiment had a 99% purity.
gdfs = groupby(df, [:Sample, :AminoAcidFragment])
df_corrected = @transform(gdfs,
:CorrectedResponse = isotope_correction(Vector(:Response), :Molecule[1]; tracer_purity = 0.99)[1])
Row | Sample | AminoAcidFragment | Molecule | MZ0 | Mplus | Response | CorrectedResponse |
---|---|---|---|---|---|---|---|
Int64 | String | String | Int64 | Int64 | Float64 | Float64 | |
1 | 1 | Met_(M-159) | C10H24N1S1Si1LabC4 | 218 | 0 | 600000.0 | 7.61252e5 |
2 | 1 | Met_(M-159) | C10H24N1S1Si1LabC4 | 218 | 1 | 600000.0 | 6.22406e5 |
3 | 1 | Met_(M-159) | C10H24N1S1Si1LabC4 | 218 | 2 | 600000.0 | 5.75541e5 |
4 | 1 | Met_(M-159) | C10H24N1S1Si1LabC4 | 218 | 3 | 600000.0 | 5.8521e5 |
5 | 1 | Met_(M-159) | C10H24N1S1Si1LabC4 | 218 | 4 | 600000.0 | 6.18862e5 |
6 | 1 | Met_(M-57) | C13H30N1O2S1Si2LabC5 | 320 | 0 | 500000.0 | 7.15001e5 |
7 | 1 | Met_(M-57) | C13H30N1O2S1Si2LabC5 | 320 | 1 | 500000.0 | 524602.0 |
8 | 1 | Met_(M-57) | C13H30N1O2S1Si2LabC5 | 320 | 2 | 500000.0 | 4.67532e5 |
9 | 1 | Met_(M-57) | C13H30N1O2S1Si2LabC5 | 320 | 3 | 500000.0 | 4.88044e5 |
10 | 1 | Met_(M-57) | C13H30N1O2S1Si2LabC5 | 320 | 4 | 500000.0 | 4.90389e5 |
11 | 1 | Met_(M-57) | C13H30N1O2S1Si2LabC5 | 320 | 5 | 500000.0 | 5.20477e5 |
12 | 2 | Met_(M-159) | C10H24N1S1Si1LabC4 | 218 | 0 | 818334.0 | 1.04608e6 |
13 | 2 | Met_(M-159) | C10H24N1S1Si1LabC4 | 218 | 1 | 261575.0 | 90713.2 |
14 | 2 | Met_(M-159) | C10H24N1S1Si1LabC4 | 218 | 2 | 2.5839e6 | 3.14444e6 |
15 | 2 | Met_(M-159) | C10H24N1S1Si1LabC4 | 218 | 3 | 1.14897e6 | 9.42992e5 |
16 | 2 | Met_(M-159) | C10H24N1S1Si1LabC4 | 218 | 4 | 231407.0 | 0.0 |
17 | 2 | Met_(M-57) | C13H30N1O2S1Si2LabC5 | 320 | 0 | 1.17069e6 | 1.69095e6 |
18 | 2 | Met_(M-57) | C13H30N1O2S1Si2LabC5 | 320 | 1 | 678027.0 | 4.33579e5 |
19 | 2 | Met_(M-57) | C13H30N1O2S1Si2LabC5 | 320 | 2 | 2.97735e6 | 3.83412e6 |
20 | 2 | Met_(M-57) | C13H30N1O2S1Si2LabC5 | 320 | 3 | 541298.0 | 0.0 |
21 | 2 | Met_(M-57) | C13H30N1O2S1Si2LabC5 | 320 | 4 | 1.82826e6 | 1.93887e6 |
22 | 2 | Met_(M-57) | C13H30N1O2S1Si2LabC5 | 320 | 5 | 1.65989e6 | 1.83581e6 |
Now, again using DataFramesMeta, both the corrected and uncorrected MIDs can be calculated.
gdfs_corrected = groupby(df_corrected, [:Sample, :AminoAcidFragment])
df_corrected_MIDs = @transform(gdfs_corrected,
:MID = :Response ./ sum(:Response),
:CorrectedMID = :CorrectedResponse ./ sum(:CorrectedResponse))
select(df_corrected_MIDs, :Sample, :AminoAcidFragment, :Response, :CorrectedResponse, :MID, :CorrectedMID)
# And of course the finished DataFrame can then be saved.
# CSV.write("Corrected_MIDs.csv", df_corrected_MIDs)
Row | Sample | AminoAcidFragment | Response | CorrectedResponse | MID | CorrectedMID |
---|---|---|---|---|---|---|
Int64 | String | Float64 | Float64 | Float64 | Float64 | |
1 | 1 | Met_(M-159) | 600000.0 | 7.61252e5 | 0.2 | 0.240653 |
2 | 1 | Met_(M-159) | 600000.0 | 6.22406e5 | 0.2 | 0.19676 |
3 | 1 | Met_(M-159) | 600000.0 | 5.75541e5 | 0.2 | 0.181945 |
4 | 1 | Met_(M-159) | 600000.0 | 5.8521e5 | 0.2 | 0.185002 |
5 | 1 | Met_(M-159) | 600000.0 | 6.18862e5 | 0.2 | 0.19564 |
6 | 1 | Met_(M-57) | 500000.0 | 7.15001e5 | 0.166667 | 0.223017 |
7 | 1 | Met_(M-57) | 500000.0 | 524602.0 | 0.166667 | 0.163629 |
8 | 1 | Met_(M-57) | 500000.0 | 4.67532e5 | 0.166667 | 0.145828 |
9 | 1 | Met_(M-57) | 500000.0 | 4.88044e5 | 0.166667 | 0.152226 |
10 | 1 | Met_(M-57) | 500000.0 | 4.90389e5 | 0.166667 | 0.152958 |
11 | 1 | Met_(M-57) | 500000.0 | 5.20477e5 | 0.166667 | 0.162342 |
12 | 2 | Met_(M-159) | 818334.0 | 1.04608e6 | 0.162233 | 0.200237 |
13 | 2 | Met_(M-159) | 261575.0 | 90713.2 | 0.0518567 | 0.017364 |
14 | 2 | Met_(M-159) | 2.5839e6 | 3.14444e6 | 0.512254 | 0.601896 |
15 | 2 | Met_(M-159) | 1.14897e6 | 9.42992e5 | 0.227781 | 0.180504 |
16 | 2 | Met_(M-159) | 231407.0 | 0.0 | 0.045876 | 0.0 |
17 | 2 | Met_(M-57) | 1.17069e6 | 1.69095e6 | 0.132199 | 0.173728 |
18 | 2 | Met_(M-57) | 678027.0 | 4.33579e5 | 0.0765655 | 0.0445459 |
19 | 2 | Met_(M-57) | 2.97735e6 | 3.83412e6 | 0.336214 | 0.393917 |
20 | 2 | Met_(M-57) | 541298.0 | 0.0 | 0.0611255 | 0.0 |
21 | 2 | Met_(M-57) | 1.82826e6 | 1.93887e6 | 0.206454 | 0.199199 |
22 | 2 | Met_(M-57) | 1.65989e6 | 1.83581e6 | 0.187441 | 0.188611 |
To visualize what isotope_correction()
does we can plot the MIDs before and after correction.
using ColorSchemes, CairoMakie
gdfs = @groupby(df_corrected_MIDs, :Sample, :AminoAcidFragment)
colors = colorschemes[:bamako][1:43:256];
group_color = [PolyElement(color = color, strokecolor = :transparent)
for color in colors]
labels = ["m+0", "m+1", "m+2", "m+3", "m+4", "m+5"]
fig = Figure();
function myplot(group, fig, colors)
name = group.AminoAcidFragment[1]
sample = group.Sample[1]
ax = Axis(fig,
xticks = (1:2, ["uncorrected", "corrected"]),
title = "Sample $sample $name MID")
barplot!(ax, repeat([1, 2], inner = length(group.MID)),
cat(group.MID, group.CorrectedMID, dims = 1),
stack = repeat(group.Mplus, 2),
colormap = colors,
color = repeat(group.Mplus .+ 1, 2))
end
myplot(gdfs[1], fig[1,1], colors[1:5])
myplot(gdfs[2], fig[1,2], colors)
myplot(gdfs[3], fig[2,1], colors[1:5])
myplot(gdfs[4], fig[2,2], colors)
Legend(fig[1:2,3], group_color, labels, framevisible = false)
fig
# save("Methionine_MIDs.png", fig)

This page was generated using Literate.jl.