@@ -13,7 +12,7 @@
## HaDeX: Analysis and Visualisation of Hydrogen/Deuterium Exchange Mass Spectrometry Data
-Hydrogen/Deuterium eXchange Mass Spectrometry (HDX-MS) is a staple technology in structural proteomics. HaDeX provides a analytic workflow for HDX-MS data available as a standalone GUI (https://sourceforge.net/projects/HaDeX/), web server (http://mslab-ibb.pl/shiny/HaDeX/) and the **R** package available on CRAN (https://cran.r-project.org/web/packages/HaDeX/index.html).
+Hydrogen/Deuterium eXchange Mass Spectrometry (HDX-MS) is a staple technology in structural proteomics. HaDeX provides a analytic workflow for HDX-MS data available as a standalone GUI (https://sourceforge.net/projects/HaDeX/), web server (https://hadex.mslab-ibb.pl/) and the **R** package available on CRAN (https://cran.r-project.org/web/packages/HaDeX/index.html).
### Local instance of HaDeX GUI
@@ -24,7 +23,7 @@ To run HaDeX GUI locally on Windows, install it using the following binary file:
You can install the latest development version of the package:
```R
-source("https://install-github.me/hadexversum/HaDeX")
+devtools::install_github("hadexversum/HaDeX")
```
or the latest version available on CRAN:
@@ -45,8 +44,8 @@ The HaDeX documentation is available [online](https://HaDeXversum.github.io/HaDe
### Citation
-Puchala W, Burdukiewicz M, Kistowski M, Dabrowska KA, Badaczewska-Dawid AE, Cysewski D and Dadlez M (2019). HaDeX: Analysis and Visualisation of Hydrogen/Deuterium Exchange Mass Spectrometry Data. R package version 1.2.
+Puchala W, Burdukiewicz M, Kistowski M, Dabrowska KA, Badaczewska-Dawid AE, Cysewski D and Dadlez M (2020). HaDeX: Analysis and Visualisation of Hydrogen/Deuterium Exchange Mass Spectrometry Data. Bioinformatics, 10.1093/bioinformatics/btaa587.
### Funding
-This work is supported by Foundation of Polish Science (TEAM TECH CORE FACILITY/2016-2/2 *Mass Spectrometry of Biopharmaceuticals - improved methodologies for qualitative, quantitative and structural characterization of drugs, proteinaceous drug targets and diagnostic molecules)*.
+This work is supported by Foundation of Polish Science (TEAM TECH CORE FACILITY/2016-2/2 *Mass Spectrometry of Biopharmaceuticals - improved methodologies for qualitative, quantitative and structural characterization of drugs, proteinaceous drug targets and diagnostic molecules)* and Narodowe Centrum Nauki (Preludium Bis 1 2019/35/O/NZ2/03745 *Wysokorozdzielcza analiza danych z eksperymentów wymiany proton-deuter monitorowanych spektrometrią mas)*.
diff --git a/appveyor.yml b/appveyor.yml
deleted file mode 100644
index 3a75e16a..00000000
--- a/appveyor.yml
+++ /dev/null
@@ -1,52 +0,0 @@
-# DO NOT CHANGE the "init" and "install" sections below
-
-# Download script file from GitHub
-init:
- ps: |
- $ErrorActionPreference = "Stop"
- Invoke-WebRequest http://raw.github.com/krlmlr/r-appveyor/master/scripts/appveyor-tool.ps1 -OutFile "..\appveyor-tool.ps1"
- Import-Module '..\appveyor-tool.ps1'
-
-install:
- ps: Bootstrap
-
-cache:
- - C:\RLibrary
-
-environment:
- NOT_CRAN: true
- # env vars that may need to be set, at least temporarily, from time to time
- # see https://github.com/krlmlr/r-appveyor#readme for details
- # USE_RTOOLS: true
- # R_REMOTES_STANDALONE: true
-
-# Adapt as necessary starting from here
-
-build_script:
- - travis-tool.sh install_deps
-
-test_script:
- - travis-tool.sh run_tests
-
-on_failure:
- - 7z a failure.zip *.Rcheck\*
- - appveyor PushArtifact failure.zip
-
-artifacts:
- - path: '*.Rcheck\**\*.log'
- name: Logs
-
- - path: '*.Rcheck\**\*.out'
- name: Logs
-
- - path: '*.Rcheck\**\*.fail'
- name: Logs
-
- - path: '*.Rcheck\**\*.Rout'
- name: Logs
-
- - path: '\*_*.tar.gz'
- name: Bits
-
- - path: '\*_*.zip'
- name: Bits
diff --git a/docs/404.html b/docs/404.html
index 5d15c6e5..54c8081a 100644
--- a/docs/404.html
+++ b/docs/404.html
@@ -17,23 +17,27 @@
-
+
-
+
-
+
+
+
+
+
-
-
+
+
-
+
-
-
+
+
@@ -60,7 +64,7 @@
-
Supplement to: “HaDeX: Analysis and Visualisation of Hydrogen/Deuterium Exchange Mass Spectrometry Data”
+
Weronika Puchała, Michał Burdukiewicz, Michał Kistowski, Katarzyna A. Dąbrowska, Aleksandra E. Badaczewska-Dawid, Dominik Cysewski, Michał Dadlez
+
+
20.06.2019
+
+
+
HaDeX.Rmd
+
+
+
+
+
+
+
+About HaDeX
+
HaDeX is a novel tool for processing, analysis, and visualization of HDX-MS experiments. HaDeX covers the final parts of the analytic process, including a comparison of experiments, quality control and generation of publication-quality figures. To make the HaDeX R package available to the less R-fluent users, we enhanced it with a comprehensive Graphical User Interface available as a HaDeX GUI. The reproducibility of the whole procedure is ensured with advanced reporting functions.
This document covers the main functionalities of both the R package and the GUI.
+
+
+Comparison of the existing HDX-MS software
+
To show the novelty of HaDeX, we compare its functionalities with other relatively new software for analysis of HDX-MS data: MEMHDX (Hourdel et al. 2016) and Deuteros (Lau et al. 2019).
+
+
We have not considered HDX Workbench (Pascal et al. 2012) as it deals with the preliminary steps of the analysis. This comparison also does not cover a versatile structural visualisation tool for HDX-MS results, HDX-Viewer (Bouyssié et al. 2019) as its scope is different from the tools mentioned above.
+
Web server: a software is available as a web server.
+
Programmatic access: analytic functionalities are documented and available from a command line.
+
Desktop software: a software can be installed locally.
+
Multi-state analysis: a software supports comparisons of more than two states.
+
ISO-based uncertainty: analytic functions produce ISO-compatible uncertainty intervals.
+
Coverage and peptide overlap: overview of experimental sequence coverage is available in a user-friendly way.
+
Quality control: additional information about course of the experiment.
+
N- and C-terminal length corrections: manual correction of sequence length.
+
Global visualization of deuterium uptake: deuterium uptake for different states is shown together for comparison.
+
Woods plot: deuteration difference between chosen states shown in the format of Woods plot.
+
Zooming of the Woods plot: Woods plot can be zoomed in.
+
Customizable label names and colors: Labels and colors on the plot can be changed by the user.
+
Peptide kinetics chart: Kinetics plot (deuteration change in time) are available for each peptide.
+
3D structure visualization: structure of the protein is visualized in 3D.
+
Downloadable charts: charts are downloadable, preferably in a vector format (.eps, .svg or .pdf).
+
Deuterium uptake download: data shown on Woods plot is downloadable (e.q. as CSV file).
+
Downloadable results of intermediate computations: results of intermediate computations (e.q. pure deuteration data) are downloadable.
+
Report generation: generates a report (e.q. in Html format) with results of the analysis with parametrization.
HDX Data Summary: summary of the experimental data (Masson et al. 2019).
+
+
+
+
+HaDeX functionalities
+
+
+Data import
+
The HaDeX web server works only on data in the DynamX datafile format (Waters Corp.). The data from other sources may be also adjusted to the format accepted by HaDeX provided it has following columns:
+
+
Although data can be imported into R using other tools, we strongly advise to rely on the read_hdx() function:
Currently, read_hdx() supports .csv, .tsv and .xls files fulfilling the data structure described above. Files with data from multiple proteins are supported. The user need to indicate which protein is of interest for calculations.
+
+
+
+Computation of deuteration levels
+
The computation of the level of deuteration involves several pre-processing steps, all of which are described in this section. These steps are performed automatically in the GUI or by the prepare_dataset() function in the console.
+
+
+Measured data into overall peptide mass
+
The results of HDX-MS measurements as given in the DynamX data files are represented as the measured mass of peptides plus proton mass to charge ratio (\(Center\)). For later use, this value has to be transformed into an overall mass of a peptide measured after specific time point from a protein in a specific state, as shown in equation 1:
+
\[pepMass = z \times (Center-protonMass)\tag{1}\] where:
+
+
\(pepMass\) - expected mass of the peptide after incubation (Da),
+
\(protonMass\) - the mass of the proton (Da),
+
\(z\) - charge of the peptide,
+
\(Center\) - experimentally measured peptide mass plus proton mass to charge ratio \(\left(\frac{m}{z}\right)\).
+
+
HDX-MS experiments are often repeated (by the rule of thumb at least three times). Thus, we aggregate the results of replicates as a weighted mean mass into a single result per peptide using equation 2:
\(aggMass\) - weighted mean mass of the peptide (Da),
+
\(k\) - replicate index,
+
\(Inten\) - intensity,
+
\(N\) - number of replicates.
+
+
This data manipulation results from an original data structure. Each repetition of the measurement gives the data for given peptide in a given time per possible value of \(z\) as shown in the example below. We need to use the value of \(pepMass\) as shown in equation 1 but still keep the information about original measurement - that’s why we use the weighted mass.
The uncertainty of a measurement is variability associated with the precision of measuring instrumentation. We present here a novel derivation of uncertainty formulas for HDX-MS data according to the ISO guidelines (Joint Committee for Guides in Metrology 2008). Input files always encompass results of more than one measurement. We assume uncorrelatedness of replicates as they come from different samples. Therefore, we average measurements of replicates for each time point and for all protein states. Thus, we compute peptide mass uncertainty \(u\) as uncertainty for aggregate estimate using the formula for standard deviation of the mean:
After obtaining the mass of the peptide, we can compute the deuteration level depending on the chosen maximum deuteration level. The maximum deuteration can also be computed in two different ways: either as theoretical (where the maximum deuteration depends on the theoretical deuteration levels) and experimental (where the maximum deuteration is assumed to be equal to the deuteration measured at the last time point).
+
+
+
+Experimental deuteration level
+
The experimental deuteration level is computed as the deuteration level of the peptide from a protein in a specific state and after incubation time \(t\) compared to the deuteration level measured at the start of the incubation (\(t_0\)). It yields a value for the chosen state and chosen time \(t\).
+
\[D = D_{t} - D_{t_0}\tag{4}\]
+
where:
+
+
\(D\) - deuteration level (Da),
+
\(D_{t_0}\) - experimentally measured deuteration at the beginning of the incubation (0 or close to 0),
+
+
The equation 4 produces only absolute deuteration levels. The computations of relative deuteration levels follows a similar logic and is normalized by the difference of deuteration between the start (\(t_0\)) and the end of the experiment (\(t_out\)) as shown in the equation 4a:
All functions in the HaDeX package contain the logical parameter \(relative\) to determine if they should return absolute or relative deuteration levels.
+
+
+Uncertainty calculations
+
We describe the methodology of the uncertainty calculations for relative deuteration levels. The uncertainty for absolute deuteration levels is computed similarly, but without scaling.
+
To calculate uncertainty related to functions of more than one variables (e. g., equation 4) the Law of propagation of uncertainty is defined by equation 5:
\(u(D_{k})\) - an uncertainty associated with \(D_{k}\) as standard deviation of the mean value,
+
+
Then, expanding the equation 6:
+
\[u_{c}(D) = \sqrt{ \left[
+\frac{1}{D_{t_{out}}-D_{t_0}} u(D_{t}) \right]^2 +
+\left[ \frac{D_{t} - D_{t_{out}}}{(D_{t_{out}}-D_{t_0})^2} u(D_{t_0}) \right]^2 +
+\left[ \frac{D_{t_0} - D_{t}}{(D_{t_{out}}-D_{t_0})^2} u (D_{t_{out}}) \right]^2}\tag{7}\] As expected, the uncertainty associated with \(D_{t}\) has the biggest impact on \(u_{c}(D)\).
+
+
+
+
+Theoretical deuteration level
+
As opposed to the experimental deuteration levels, theoretical deuteration level only partially depends on the experimental data. Here, the maximum deuteration level is based on a hypothetical peptide where all hydrogens were replaced by deuterons, as it is shown in equation 8:
For the absolute values, \(u(D)\) is identical with \(u(D_{t})\), based on equations 8a and 9.
+
+
+
+
+
+Difference of deuteration levels between two states
+
The differences of deuteration levels between two states are associated with a different level of protection of hydrogens. Therefore, we are especially interested in the differential analysis of the deuteration levels. Thus, the deuteration level in one state \((D_{2})\) is subtracted from deuteration level in the other state \((D_{1})\):
+
\[diff = D_{1} - D_{2}\tag{11}\]
+
and the uncertainty is a function of two variables (based on equation 11 and 5):
Comparison plots show the deuteration level of all peptides in selected states in a given time. The x-axis represents positions of amino acids in the sequence. The y-axis shows the deuteration level, expressed either as a relative or absolute deuteration. The chart below shows peptide deuteration after 25 minutes of the incubation along with the confidence intervals.
+
– theoretical:
+
+
relative values:
+
+
+comparison_plot(calc_dat =calc_dat,
+ theoretical =TRUE,
+ relative =TRUE,
+ state_first ="Nucb2 Factor 1",
+ state_second ="Nucb2 Factor 2")+
+ labs(title ="Theoretical fraction exchanged in state comparison in 25 min time")
+
+
+
absolute values:
+
+
+comparison_plot(calc_dat =calc_dat,
+ theoretical =TRUE,
+ relative =FALSE,
+ state_first ="Nucb2 Factor 1",
+ state_second ="Nucb2 Factor 2")+
+ labs(title ="Theoretical fraction exchanged in state comparison in 25 min time")
+
+
– experimental:
+
+
relative values:
+
+
+comparison_plot(calc_dat =calc_dat,
+ theoretical =FALSE,
+ relative =TRUE,
+ state_first ="Nucb2 Factor 1",
+ state_second ="Nucb2 Factor 2")+
+ labs(title ="Fraction exchanged in state comparison in 25 min time")
+
+
+
absolute values:
+
+
+comparison_plot(calc_dat =calc_dat,
+ theoretical =FALSE,
+ relative =FALSE,
+ state_first ="Nucb2 Factor 1",
+ state_second ="Nucb2 Factor 2")+
+ labs(title ="Fraction exchanged in state comparison in 25 min time")
+
+
+
+
+
+Woods plot
+
Woods plots show the difference between the deuteration of all peptides in two different states in a specific time point as described by equation 11. Similarly to the comparison plot, HaDeX provides both experimental and theoretical deuteration levels using either relative or absolute values:
+
– theoretical:
+
+
relative values:
+
+
+woods_plot(calc_dat =calc_dat,
+ theoretical =TRUE,
+ relative =TRUE)+
+ labs(title ="Theoretical fraction exchanged between states in 25 min time")
+
+
+
absolute values:
+
+
+woods_plot(calc_dat =calc_dat,
+ theoretical =TRUE,
+ relative =FALSE)+
+ labs(title ="Theoretical fraction exchanged between states in 25 min time")
+
+
– experimental:
+
+
relative values:
+
+
+woods_plot(calc_dat =calc_dat,
+ theoretical =FALSE,
+ relative =TRUE)+
+ labs(title ="Theoretical fraction exchanged between states in 25 min time")
+
+
+
absolute values:
+
+
+woods_plot(calc_dat =calc_dat,
+ theoretical =FALSE,
+ relative =FALSE)+
+ labs(title ="Theoretical fraction exchanged between states in 25 min time")
+
+
+
+Confidence limit in Woods plot
+
The function calculate_confidence_limit_values() calculates confidence limit values as it is described elsewhere (Houde, Berkowitz, and Engen 2011).
By the term kinetics we understand deuteration change in time. To calculate deuteration values per peptide for different time points is used function calculate_kinetics(). This function uses the calculate_state_deuteration() function.
+
+(kin_YYDEYL_gg_Nucb2_CaCl2<-calculate_kinetics(dat =dat,
+ protein ="db_Nucb2",
+ sequence ="YYDEYL",
+ state ="gg_Nucb2_CaCl2",
+ start =45,
+ end =50,
+ time_in =0.001,
+ time_out =1440))
HaDeX provides additional tools for assessment of experiments.
+
+
+Peptide coverage
+
The sequence of the protein(s) is reconstructed from the peptides from the input file. Thus, amino acids not covered by peptides are marked as X according to the IUPAC convention. The sequence is reconstructed using the reconstruct_sequence() function.
The user can choose which state (or states) should be included in these plots. If this parameter is not provided, the first possible state is chosen. If a given peptide is available in more than one state, it is shown only once.
+
+
+
+Quality control
+
The function quality_control() plots the change in the uncertainty of deuteration levels as a function of incubation time. The uncertainty is averaged over all peptides available at a given time point in a selected state. This chart has a double function: firstly, it allows checking if the measurement uncertainty is decreasing over time (which is the expected behavior) and the second one helps to plan the appropriate incubation length for the tested protein (whether we obtain the desired data reliability values).
+
In HDX-MS experiments, the average uncertainty of measurements decreases over time as the sample is more and more deuterated (even accounting for the back-propagation). Therefore, if the level of uncertainty is stable, the exchange is still ongoing and it would be advisable to prolong the reaction.
+
Moreover, the user can detect a time point after which the decrease of the deuteration uncertainty becomes too marginal to prolong the measurements. This function is most useful in case of multiple measurements of the same or very similar proteins because it helps to optimize the duration of the incubation. The result of this function can be easily visualized.
+ggplot(result)+
+ geom_line(aes(x =out_time, y =avg_err_state_first, color ="Average error (first state)"))+
+ geom_line(aes(x =out_time, y =avg_err_state_second, color ="Average error (second state)"))+
+ scale_x_log10()+
+ labs(x ="log(time) [min]", y ="Average uncertainty", title ="Uncertainty change")+
+ theme_bw(base_size =11)+
+ theme(legend.position ="bottom",
+ legend.title =element_blank())
+
+
The chart below shows how we interpret the three most common results of quality control.
+
+
+
+
+
+
+HaDeX Graphical User Interface
+
The HaDeX Shiny app is launched by the HaDeX_gui() function or available at MS Lab website: http://mslab-ibb.pl/shiny/HaDeX/. In the Input Data tab the user can adjust parameters to be propagated for the whole analysis.
+
+
+
+Examples
+
+
+Example 1: CD160-HVEM
+
The interaction between HVEM and the CD160 receptor was measured with HDX-MS.
+
Firstly, we read the input data, exactly as provided by the DynamX 3.0 (Waters Corp.)
Then, we reconstruct the protein sequence from the peptides measured during the experiment. We observe the region from amino acid 107 till amino acid 124 is not covered by any peptide.
The theoretical plot allows finding regions, which exchange quickly (N-terminus, regions between 30-70 amino acid) and regions, which exchange slowly (peptides 15-24, 95-110 amino acid). We can also see the differences in the exchange between two states, indicating regions which changed upon binding with other protein.
On the experimental plot, there are visible regions, which exchange quickly (N terminal part, regions between 30-70 amino acid) and regions, which exchange slowly (peptides 15-24, 30-35, 95-110 amino acid).
The plot below shows peptides for which levels of deuteration were significantly lower upon binding with other protein (red) and peptides for which levels of exchange were significantly higher upon binding with other protein (blue). The plot also shows peptides in which no significant changes in deuteration between states are visible (grey). The biggest changes on the theoretical plot can be observed in 3 peptides (15-24, 30-35, 75-90).
+# example quality control visualisation - relative values
+library(ggplot2)
+ggplot(result[result["out_time"]>=1,])+
+ geom_line(aes(x =out_time, y =avg_err_state_first, color ="Average error (first state)"))+
+ geom_line(aes(x =out_time, y =avg_err_state_second, color ="Average error (second state)"))+
+ scale_x_log10()+
+ labs(x ="log(time) [min]", y ="Average uncertainty", title ="Uncertainty change")+
+ theme(legend.position ="bottom",
+ legend.title =element_blank())
+
+
+
+
+
+References
+
+
+
Bouyssié, David, Jean Lesne, Marie Locard-Paulet, Renaud Albigot, Odile Burlet-Schiltz, and Julien Marcoux. 2019. “HDX-Viewer: Interactive 3D Visualization of Hydrogen-Deuterium Exchange Data.” Bioinformatics (Oxford, England), July. https://doi.org/10.1093/bioinformatics/btz550.
+
+
+
Houde, Damian, Steven A. Berkowitz, and John R. Engen. 2011. “The Utility of Hydrogen/Deuterium Exchange Mass Spectrometry in Biopharmaceutical Comparability Studies.” Journal of Pharmaceutical Sciences 100 (6): 2071–86. https://doi.org/10.1002/jps.22432.
+
+
+
Hourdel, Véronique, Stevenn Volant, Darragh P. O’Brien, Alexandre Chenal, Julia Chamot-Rooke, Marie-Agnès Dillies, and Sébastien Brier. 2016. “MEMHDX: An Interactive Tool to Expedite the Statistical Validation and Visualization of Large HDX-MS Datasets.” Bioinformatics 32 (22): 3413–9. https://doi.org/10.1093/bioinformatics/btw420.
+
+
+
Joint Committee for Guides in Metrology. 2008. “JCGM 100: Evaluation of Measurement Data - Guide to the Expression of Uncertainty in Measurement.” JCGM.
+
+
+
Lau, Andy M. C., Zainab Ahdash, Chloe Martens, and Argyris Politis. 2019. “Deuteros: Software for Rapid Analysis and Visualization of Data from Differential Hydrogen Deuterium Exchange-Mass Spectrometry.” Bioinformatics (Oxford, England), January. https://doi.org/10.1093/bioinformatics/btz022.
+
+
+
Masson, Glenn R., John E. Burke, Natalie G. Ahn, Ganesh S. Anand, Christoph Borchers, Sébastien Brier, George M. Bou-Assaf, et al. 2019. “Recommendations for Performing, Interpreting and Reporting Hydrogen Deuterium Exchange Mass Spectrometry (HDX-MS) Experiments.” Nature Methods 16 (7): 595–602. https://doi.org/10.1038/s41592-019-0459-y.
+
+
+
Pascal, Bruce D., Scooter Willis, Janelle L. Lauer, Rachelle R. Landgraf, Graham M. West, David Marciano, Scott Novick, Devrishi Goswami, Michael J. Chalmers, and Patrick R. Griffin. 2012. “HDX Workbench: Software for the Analysis of H/D Exchange MS Data.” Journal of the American Society for Mass Spectrometry 23 (9): 1512–21. https://doi.org/10.1007/s13361-012-0419-6.
/g,">").replace(/"/g,"""):a};q.render={number:function(a,b,c,d,e){return{display:function(f){if("number"!==typeof f&&"string"!==typeof f)return f;var g=0>f?"-":"",h=parseFloat(f);if(isNaN(h))return ib(f);h=h.toFixed(c);f=Math.abs(h);h=parseInt(f,10);f=c?b+(f-h).toFixed(c).substring(2):"";return g+(d||"")+h.toString().replace(/\B(?=(\d{3})+(?!\d))/g,
+a)+f+(e||"")}}},text:function(){return{display:ib,filter:ib}}};f.extend(q.ext.internal,{_fnExternApiFunc:Qb,_fnBuildAjax:va,_fnAjaxUpdate:qb,_fnAjaxParameters:zb,_fnAjaxUpdateDraw:Ab,_fnAjaxDataSrc:wa,_fnAddColumn:Ia,_fnColumnOptions:ma,_fnAdjustColumnSizing:aa,_fnVisibleToColumnIndex:ba,_fnColumnIndexToVisible:ca,_fnVisbleColumns:W,_fnGetColumns:oa,_fnColumnTypes:Ka,_fnApplyColumnDefs:nb,_fnHungarianMap:H,_fnCamelToHungarian:L,_fnLanguageCompat:Ga,_fnBrowserDetect:lb,_fnAddData:R,_fnAddTr:pa,_fnNodeToDataIndex:function(a,
+b){return b._DT_RowIndex!==p?b._DT_RowIndex:null},_fnNodeToColumnIndex:function(a,b,c){return f.inArray(c,a.aoData[b].anCells)},_fnGetCellData:I,_fnSetCellData:ob,_fnSplitObjNotation:Na,_fnGetObjectDataFn:U,_fnSetObjectDataFn:Q,_fnGetDataMaster:Oa,_fnClearTable:qa,_fnDeleteIndex:ra,_fnInvalidate:ea,_fnGetRowElements:Ma,_fnCreateTr:La,_fnBuildHead:pb,_fnDrawHead:ha,_fnDraw:S,_fnReDraw:V,_fnAddOptionsHtml:sb,_fnDetectHeader:fa,_fnGetUniqueThs:ua,_fnFeatureHtmlFilter:ub,_fnFilterComplete:ia,_fnFilterCustom:Db,
+_fnFilterColumn:Cb,_fnFilter:Bb,_fnFilterCreateSearch:Ta,_fnEscapeRegex:Ua,_fnFilterData:Eb,_fnFeatureHtmlInfo:xb,_fnUpdateInfo:Hb,_fnInfoMacros:Ib,_fnInitialise:ja,_fnInitComplete:xa,_fnLengthChange:Va,_fnFeatureHtmlLength:tb,_fnFeatureHtmlPaginate:yb,_fnPageChange:Xa,_fnFeatureHtmlProcessing:vb,_fnProcessingDisplay:K,_fnFeatureHtmlTable:wb,_fnScrollDraw:na,_fnApplyToChildren:N,_fnCalculateColumnWidths:Ja,_fnThrottle:Sa,_fnConvertToWidth:Jb,_fnGetWidestNode:Kb,_fnGetMaxLenString:Lb,_fnStringToCss:B,
+_fnSortFlatten:Y,_fnSort:rb,_fnSortAria:Nb,_fnSortListener:Za,_fnSortAttachListener:Qa,_fnSortingClasses:Aa,_fnSortData:Mb,_fnSaveState:Ba,_fnLoadState:Ob,_fnSettingsFromNode:Ca,_fnLog:O,_fnMap:M,_fnBindAction:$a,_fnCallbackReg:E,_fnCallbackFire:A,_fnLengthOverflow:Wa,_fnRenderer:Ra,_fnDataSource:D,_fnRowAttributes:Pa,_fnExtend:ab,_fnCalculateEnd:function(){}});f.fn.dataTable=q;q.$=f;f.fn.dataTableSettings=q.settings;f.fn.dataTableExt=q.ext;f.fn.DataTable=function(a){return f(this).dataTable(a).api()};
+f.each(q,function(a,b){f.fn.DataTable[a]=b});return f.fn.dataTable});
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-10-1.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-10-1.png
new file mode 100644
index 00000000..37ecf056
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-10-1.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-11-1.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-11-1.png
new file mode 100644
index 00000000..a486a32d
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-11-1.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-12-1.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-12-1.png
new file mode 100644
index 00000000..b7f6cc9d
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-12-1.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-13-1.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-13-1.png
new file mode 100644
index 00000000..016a4d8e
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-13-1.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-14-1.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-14-1.png
new file mode 100644
index 00000000..d184bd45
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-14-1.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-19-1.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-19-1.png
new file mode 100644
index 00000000..bd2abed2
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-19-1.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-20-1.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-20-1.png
new file mode 100644
index 00000000..af3dfae5
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-20-1.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-21-1.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-21-1.png
new file mode 100644
index 00000000..d0311845
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-21-1.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-22-1.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-22-1.png
new file mode 100644
index 00000000..848c35da
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-22-1.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-24-1.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-24-1.png
new file mode 100644
index 00000000..6850caad
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-24-1.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-24-2.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-24-2.png
new file mode 100644
index 00000000..79ca4279
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-24-2.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-26-1.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-26-1.png
new file mode 100644
index 00000000..af200b5b
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-26-1.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-27-1.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-27-1.png
new file mode 100644
index 00000000..c3006fb4
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-27-1.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-29-1.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-29-1.png
new file mode 100644
index 00000000..c4664596
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-29-1.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-30-1.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-30-1.png
new file mode 100644
index 00000000..ab15744c
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-30-1.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-31-1.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-31-1.png
new file mode 100644
index 00000000..e571442f
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-31-1.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-32-1.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-32-1.png
new file mode 100644
index 00000000..4766417c
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-32-1.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-32-2.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-32-2.png
new file mode 100644
index 00000000..3342318a
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-32-2.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-33-1.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-33-1.png
new file mode 100644
index 00000000..dfb4b563
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-33-1.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-34-1.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-34-1.png
new file mode 100644
index 00000000..d26402e6
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-34-1.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-35-1.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-35-1.png
new file mode 100644
index 00000000..0eec8da8
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-35-1.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-35-2.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-35-2.png
new file mode 100644
index 00000000..949c9cd3
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-35-2.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-35-3.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-35-3.png
new file mode 100644
index 00000000..03cd6139
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-35-3.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-36-1.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-36-1.png
new file mode 100644
index 00000000..40fa1486
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-36-1.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-36-2.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-36-2.png
new file mode 100644
index 00000000..fec71b40
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-36-2.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-36-3.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-36-3.png
new file mode 100644
index 00000000..c5b149ec
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-36-3.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-36-4.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-36-4.png
new file mode 100644
index 00000000..0f61733c
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-36-4.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-36-5.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-36-5.png
new file mode 100644
index 00000000..d7a9558b
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-36-5.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-36-6.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-36-6.png
new file mode 100644
index 00000000..7ffc4e87
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-36-6.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-36-7.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-36-7.png
new file mode 100644
index 00000000..b7f6cc9d
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-36-7.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-36-8.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-36-8.png
new file mode 100644
index 00000000..f3814409
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-36-8.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-36-9.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-36-9.png
new file mode 100644
index 00000000..5c818428
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-36-9.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-7-1.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-7-1.png
new file mode 100644
index 00000000..f308a118
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-7-1.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-8-1.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-8-1.png
new file mode 100644
index 00000000..bf226615
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-8-1.png differ
diff --git a/docs/articles/HaDeX_files/figure-html/unnamed-chunk-9-1.png b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-9-1.png
new file mode 100644
index 00000000..040e14d9
Binary files /dev/null and b/docs/articles/HaDeX_files/figure-html/unnamed-chunk-9-1.png differ
diff --git a/docs/articles/HaDeX_files/htmlwidgets-1.5.2/htmlwidgets.js b/docs/articles/HaDeX_files/htmlwidgets-1.5.2/htmlwidgets.js
new file mode 100644
index 00000000..6f3d672d
--- /dev/null
+++ b/docs/articles/HaDeX_files/htmlwidgets-1.5.2/htmlwidgets.js
@@ -0,0 +1,903 @@
+(function() {
+ // If window.HTMLWidgets is already defined, then use it; otherwise create a
+ // new object. This allows preceding code to set options that affect the
+ // initialization process (though none currently exist).
+ window.HTMLWidgets = window.HTMLWidgets || {};
+
+ // See if we're running in a viewer pane. If not, we're in a web browser.
+ var viewerMode = window.HTMLWidgets.viewerMode =
+ /\bviewer_pane=1\b/.test(window.location);
+
+ // See if we're running in Shiny mode. If not, it's a static document.
+ // Note that static widgets can appear in both Shiny and static modes, but
+ // obviously, Shiny widgets can only appear in Shiny apps/documents.
+ var shinyMode = window.HTMLWidgets.shinyMode =
+ typeof(window.Shiny) !== "undefined" && !!window.Shiny.outputBindings;
+
+ // We can't count on jQuery being available, so we implement our own
+ // version if necessary.
+ function querySelectorAll(scope, selector) {
+ if (typeof(jQuery) !== "undefined" && scope instanceof jQuery) {
+ return scope.find(selector);
+ }
+ if (scope.querySelectorAll) {
+ return scope.querySelectorAll(selector);
+ }
+ }
+
+ function asArray(value) {
+ if (value === null)
+ return [];
+ if ($.isArray(value))
+ return value;
+ return [value];
+ }
+
+ // Implement jQuery's extend
+ function extend(target /*, ... */) {
+ if (arguments.length == 1) {
+ return target;
+ }
+ for (var i = 1; i < arguments.length; i++) {
+ var source = arguments[i];
+ for (var prop in source) {
+ if (source.hasOwnProperty(prop)) {
+ target[prop] = source[prop];
+ }
+ }
+ }
+ return target;
+ }
+
+ // IE8 doesn't support Array.forEach.
+ function forEach(values, callback, thisArg) {
+ if (values.forEach) {
+ values.forEach(callback, thisArg);
+ } else {
+ for (var i = 0; i < values.length; i++) {
+ callback.call(thisArg, values[i], i, values);
+ }
+ }
+ }
+
+ // Replaces the specified method with the return value of funcSource.
+ //
+ // Note that funcSource should not BE the new method, it should be a function
+ // that RETURNS the new method. funcSource receives a single argument that is
+ // the overridden method, it can be called from the new method. The overridden
+ // method can be called like a regular function, it has the target permanently
+ // bound to it so "this" will work correctly.
+ function overrideMethod(target, methodName, funcSource) {
+ var superFunc = target[methodName] || function() {};
+ var superFuncBound = function() {
+ return superFunc.apply(target, arguments);
+ };
+ target[methodName] = funcSource(superFuncBound);
+ }
+
+ // Add a method to delegator that, when invoked, calls
+ // delegatee.methodName. If there is no such method on
+ // the delegatee, but there was one on delegator before
+ // delegateMethod was called, then the original version
+ // is invoked instead.
+ // For example:
+ //
+ // var a = {
+ // method1: function() { console.log('a1'); }
+ // method2: function() { console.log('a2'); }
+ // };
+ // var b = {
+ // method1: function() { console.log('b1'); }
+ // };
+ // delegateMethod(a, b, "method1");
+ // delegateMethod(a, b, "method2");
+ // a.method1();
+ // a.method2();
+ //
+ // The output would be "b1", "a2".
+ function delegateMethod(delegator, delegatee, methodName) {
+ var inherited = delegator[methodName];
+ delegator[methodName] = function() {
+ var target = delegatee;
+ var method = delegatee[methodName];
+
+ // The method doesn't exist on the delegatee. Instead,
+ // call the method on the delegator, if it exists.
+ if (!method) {
+ target = delegator;
+ method = inherited;
+ }
+
+ if (method) {
+ return method.apply(target, arguments);
+ }
+ };
+ }
+
+ // Implement a vague facsimilie of jQuery's data method
+ function elementData(el, name, value) {
+ if (arguments.length == 2) {
+ return el["htmlwidget_data_" + name];
+ } else if (arguments.length == 3) {
+ el["htmlwidget_data_" + name] = value;
+ return el;
+ } else {
+ throw new Error("Wrong number of arguments for elementData: " +
+ arguments.length);
+ }
+ }
+
+ // http://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
+ function escapeRegExp(str) {
+ return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
+ }
+
+ function hasClass(el, className) {
+ var re = new RegExp("\\b" + escapeRegExp(className) + "\\b");
+ return re.test(el.className);
+ }
+
+ // elements - array (or array-like object) of HTML elements
+ // className - class name to test for
+ // include - if true, only return elements with given className;
+ // if false, only return elements *without* given className
+ function filterByClass(elements, className, include) {
+ var results = [];
+ for (var i = 0; i < elements.length; i++) {
+ if (hasClass(elements[i], className) == include)
+ results.push(elements[i]);
+ }
+ return results;
+ }
+
+ function on(obj, eventName, func) {
+ if (obj.addEventListener) {
+ obj.addEventListener(eventName, func, false);
+ } else if (obj.attachEvent) {
+ obj.attachEvent(eventName, func);
+ }
+ }
+
+ function off(obj, eventName, func) {
+ if (obj.removeEventListener)
+ obj.removeEventListener(eventName, func, false);
+ else if (obj.detachEvent) {
+ obj.detachEvent(eventName, func);
+ }
+ }
+
+ // Translate array of values to top/right/bottom/left, as usual with
+ // the "padding" CSS property
+ // https://developer.mozilla.org/en-US/docs/Web/CSS/padding
+ function unpackPadding(value) {
+ if (typeof(value) === "number")
+ value = [value];
+ if (value.length === 1) {
+ return {top: value[0], right: value[0], bottom: value[0], left: value[0]};
+ }
+ if (value.length === 2) {
+ return {top: value[0], right: value[1], bottom: value[0], left: value[1]};
+ }
+ if (value.length === 3) {
+ return {top: value[0], right: value[1], bottom: value[2], left: value[1]};
+ }
+ if (value.length === 4) {
+ return {top: value[0], right: value[1], bottom: value[2], left: value[3]};
+ }
+ }
+
+ // Convert an unpacked padding object to a CSS value
+ function paddingToCss(paddingObj) {
+ return paddingObj.top + "px " + paddingObj.right + "px " + paddingObj.bottom + "px " + paddingObj.left + "px";
+ }
+
+ // Makes a number suitable for CSS
+ function px(x) {
+ if (typeof(x) === "number")
+ return x + "px";
+ else
+ return x;
+ }
+
+ // Retrieves runtime widget sizing information for an element.
+ // The return value is either null, or an object with fill, padding,
+ // defaultWidth, defaultHeight fields.
+ function sizingPolicy(el) {
+ var sizingEl = document.querySelector("script[data-for='" + el.id + "'][type='application/htmlwidget-sizing']");
+ if (!sizingEl)
+ return null;
+ var sp = JSON.parse(sizingEl.textContent || sizingEl.text || "{}");
+ if (viewerMode) {
+ return sp.viewer;
+ } else {
+ return sp.browser;
+ }
+ }
+
+ // @param tasks Array of strings (or falsy value, in which case no-op).
+ // Each element must be a valid JavaScript expression that yields a
+ // function. Or, can be an array of objects with "code" and "data"
+ // properties; in this case, the "code" property should be a string
+ // of JS that's an expr that yields a function, and "data" should be
+ // an object that will be added as an additional argument when that
+ // function is called.
+ // @param target The object that will be "this" for each function
+ // execution.
+ // @param args Array of arguments to be passed to the functions. (The
+ // same arguments will be passed to all functions.)
+ function evalAndRun(tasks, target, args) {
+ if (tasks) {
+ forEach(tasks, function(task) {
+ var theseArgs = args;
+ if (typeof(task) === "object") {
+ theseArgs = theseArgs.concat([task.data]);
+ task = task.code;
+ }
+ var taskFunc = tryEval(task);
+ if (typeof(taskFunc) !== "function") {
+ throw new Error("Task must be a function! Source:\n" + task);
+ }
+ taskFunc.apply(target, theseArgs);
+ });
+ }
+ }
+
+ // Attempt eval() both with and without enclosing in parentheses.
+ // Note that enclosing coerces a function declaration into
+ // an expression that eval() can parse
+ // (otherwise, a SyntaxError is thrown)
+ function tryEval(code) {
+ var result = null;
+ try {
+ result = eval(code);
+ } catch(error) {
+ if (!error instanceof SyntaxError) {
+ throw error;
+ }
+ try {
+ result = eval("(" + code + ")");
+ } catch(e) {
+ if (e instanceof SyntaxError) {
+ throw error;
+ } else {
+ throw e;
+ }
+ }
+ }
+ return result;
+ }
+
+ function initSizing(el) {
+ var sizing = sizingPolicy(el);
+ if (!sizing)
+ return;
+
+ var cel = document.getElementById("htmlwidget_container");
+ if (!cel)
+ return;
+
+ if (typeof(sizing.padding) !== "undefined") {
+ document.body.style.margin = "0";
+ document.body.style.padding = paddingToCss(unpackPadding(sizing.padding));
+ }
+
+ if (sizing.fill) {
+ document.body.style.overflow = "hidden";
+ document.body.style.width = "100%";
+ document.body.style.height = "100%";
+ document.documentElement.style.width = "100%";
+ document.documentElement.style.height = "100%";
+ if (cel) {
+ cel.style.position = "absolute";
+ var pad = unpackPadding(sizing.padding);
+ cel.style.top = pad.top + "px";
+ cel.style.right = pad.right + "px";
+ cel.style.bottom = pad.bottom + "px";
+ cel.style.left = pad.left + "px";
+ el.style.width = "100%";
+ el.style.height = "100%";
+ }
+
+ return {
+ getWidth: function() { return cel.offsetWidth; },
+ getHeight: function() { return cel.offsetHeight; }
+ };
+
+ } else {
+ el.style.width = px(sizing.width);
+ el.style.height = px(sizing.height);
+
+ return {
+ getWidth: function() { return el.offsetWidth; },
+ getHeight: function() { return el.offsetHeight; }
+ };
+ }
+ }
+
+ // Default implementations for methods
+ var defaults = {
+ find: function(scope) {
+ return querySelectorAll(scope, "." + this.name);
+ },
+ renderError: function(el, err) {
+ var $el = $(el);
+
+ this.clearError(el);
+
+ // Add all these error classes, as Shiny does
+ var errClass = "shiny-output-error";
+ if (err.type !== null) {
+ // use the classes of the error condition as CSS class names
+ errClass = errClass + " " + $.map(asArray(err.type), function(type) {
+ return errClass + "-" + type;
+ }).join(" ");
+ }
+ errClass = errClass + " htmlwidgets-error";
+
+ // Is el inline or block? If inline or inline-block, just display:none it
+ // and add an inline error.
+ var display = $el.css("display");
+ $el.data("restore-display-mode", display);
+
+ if (display === "inline" || display === "inline-block") {
+ $el.hide();
+ if (err.message !== "") {
+ var errorSpan = $("").addClass(errClass);
+ errorSpan.text(err.message);
+ $el.after(errorSpan);
+ }
+ } else if (display === "block") {
+ // If block, add an error just after the el, set visibility:none on the
+ // el, and position the error to be on top of the el.
+ // Mark it with a unique ID and CSS class so we can remove it later.
+ $el.css("visibility", "hidden");
+ if (err.message !== "") {
+ var errorDiv = $("
").addClass(errClass).css("position", "absolute")
+ .css("top", el.offsetTop)
+ .css("left", el.offsetLeft)
+ // setting width can push out the page size, forcing otherwise
+ // unnecessary scrollbars to appear and making it impossible for
+ // the element to shrink; so use max-width instead
+ .css("maxWidth", el.offsetWidth)
+ .css("height", el.offsetHeight);
+ errorDiv.text(err.message);
+ $el.after(errorDiv);
+
+ // Really dumb way to keep the size/position of the error in sync with
+ // the parent element as the window is resized or whatever.
+ var intId = setInterval(function() {
+ if (!errorDiv[0].parentElement) {
+ clearInterval(intId);
+ return;
+ }
+ errorDiv
+ .css("top", el.offsetTop)
+ .css("left", el.offsetLeft)
+ .css("maxWidth", el.offsetWidth)
+ .css("height", el.offsetHeight);
+ }, 500);
+ }
+ }
+ },
+ clearError: function(el) {
+ var $el = $(el);
+ var display = $el.data("restore-display-mode");
+ $el.data("restore-display-mode", null);
+
+ if (display === "inline" || display === "inline-block") {
+ if (display)
+ $el.css("display", display);
+ $(el.nextSibling).filter(".htmlwidgets-error").remove();
+ } else if (display === "block"){
+ $el.css("visibility", "inherit");
+ $(el.nextSibling).filter(".htmlwidgets-error").remove();
+ }
+ },
+ sizing: {}
+ };
+
+ // Called by widget bindings to register a new type of widget. The definition
+ // object can contain the following properties:
+ // - name (required) - A string indicating the binding name, which will be
+ // used by default as the CSS classname to look for.
+ // - initialize (optional) - A function(el) that will be called once per
+ // widget element; if a value is returned, it will be passed as the third
+ // value to renderValue.
+ // - renderValue (required) - A function(el, data, initValue) that will be
+ // called with data. Static contexts will cause this to be called once per
+ // element; Shiny apps will cause this to be called multiple times per
+ // element, as the data changes.
+ window.HTMLWidgets.widget = function(definition) {
+ if (!definition.name) {
+ throw new Error("Widget must have a name");
+ }
+ if (!definition.type) {
+ throw new Error("Widget must have a type");
+ }
+ // Currently we only support output widgets
+ if (definition.type !== "output") {
+ throw new Error("Unrecognized widget type '" + definition.type + "'");
+ }
+ // TODO: Verify that .name is a valid CSS classname
+
+ // Support new-style instance-bound definitions. Old-style class-bound
+ // definitions have one widget "object" per widget per type/class of
+ // widget; the renderValue and resize methods on such widget objects
+ // take el and instance arguments, because the widget object can't
+ // store them. New-style instance-bound definitions have one widget
+ // object per widget instance; the definition that's passed in doesn't
+ // provide renderValue or resize methods at all, just the single method
+ // factory(el, width, height)
+ // which returns an object that has renderValue(x) and resize(w, h).
+ // This enables a far more natural programming style for the widget
+ // author, who can store per-instance state using either OO-style
+ // instance fields or functional-style closure variables (I guess this
+ // is in contrast to what can only be called C-style pseudo-OO which is
+ // what we required before).
+ if (definition.factory) {
+ definition = createLegacyDefinitionAdapter(definition);
+ }
+
+ if (!definition.renderValue) {
+ throw new Error("Widget must have a renderValue function");
+ }
+
+ // For static rendering (non-Shiny), use a simple widget registration
+ // scheme. We also use this scheme for Shiny apps/documents that also
+ // contain static widgets.
+ window.HTMLWidgets.widgets = window.HTMLWidgets.widgets || [];
+ // Merge defaults into the definition; don't mutate the original definition.
+ var staticBinding = extend({}, defaults, definition);
+ overrideMethod(staticBinding, "find", function(superfunc) {
+ return function(scope) {
+ var results = superfunc(scope);
+ // Filter out Shiny outputs, we only want the static kind
+ return filterByClass(results, "html-widget-output", false);
+ };
+ });
+ window.HTMLWidgets.widgets.push(staticBinding);
+
+ if (shinyMode) {
+ // Shiny is running. Register the definition with an output binding.
+ // The definition itself will not be the output binding, instead
+ // we will make an output binding object that delegates to the
+ // definition. This is because we foolishly used the same method
+ // name (renderValue) for htmlwidgets definition and Shiny bindings
+ // but they actually have quite different semantics (the Shiny
+ // bindings receive data that includes lots of metadata that it
+ // strips off before calling htmlwidgets renderValue). We can't
+ // just ignore the difference because in some widgets it's helpful
+ // to call this.renderValue() from inside of resize(), and if
+ // we're not delegating, then that call will go to the Shiny
+ // version instead of the htmlwidgets version.
+
+ // Merge defaults with definition, without mutating either.
+ var bindingDef = extend({}, defaults, definition);
+
+ // This object will be our actual Shiny binding.
+ var shinyBinding = new Shiny.OutputBinding();
+
+ // With a few exceptions, we'll want to simply use the bindingDef's
+ // version of methods if they are available, otherwise fall back to
+ // Shiny's defaults. NOTE: If Shiny's output bindings gain additional
+ // methods in the future, and we want them to be overrideable by
+ // HTMLWidget binding definitions, then we'll need to add them to this
+ // list.
+ delegateMethod(shinyBinding, bindingDef, "getId");
+ delegateMethod(shinyBinding, bindingDef, "onValueChange");
+ delegateMethod(shinyBinding, bindingDef, "onValueError");
+ delegateMethod(shinyBinding, bindingDef, "renderError");
+ delegateMethod(shinyBinding, bindingDef, "clearError");
+ delegateMethod(shinyBinding, bindingDef, "showProgress");
+
+ // The find, renderValue, and resize are handled differently, because we
+ // want to actually decorate the behavior of the bindingDef methods.
+
+ shinyBinding.find = function(scope) {
+ var results = bindingDef.find(scope);
+
+ // Only return elements that are Shiny outputs, not static ones
+ var dynamicResults = results.filter(".html-widget-output");
+
+ // It's possible that whatever caused Shiny to think there might be
+ // new dynamic outputs, also caused there to be new static outputs.
+ // Since there might be lots of different htmlwidgets bindings, we
+ // schedule execution for later--no need to staticRender multiple
+ // times.
+ if (results.length !== dynamicResults.length)
+ scheduleStaticRender();
+
+ return dynamicResults;
+ };
+
+ // Wrap renderValue to handle initialization, which unfortunately isn't
+ // supported natively by Shiny at the time of this writing.
+
+ shinyBinding.renderValue = function(el, data) {
+ Shiny.renderDependencies(data.deps);
+ // Resolve strings marked as javascript literals to objects
+ if (!(data.evals instanceof Array)) data.evals = [data.evals];
+ for (var i = 0; data.evals && i < data.evals.length; i++) {
+ window.HTMLWidgets.evaluateStringMember(data.x, data.evals[i]);
+ }
+ if (!bindingDef.renderOnNullValue) {
+ if (data.x === null) {
+ el.style.visibility = "hidden";
+ return;
+ } else {
+ el.style.visibility = "inherit";
+ }
+ }
+ if (!elementData(el, "initialized")) {
+ initSizing(el);
+
+ elementData(el, "initialized", true);
+ if (bindingDef.initialize) {
+ var result = bindingDef.initialize(el, el.offsetWidth,
+ el.offsetHeight);
+ elementData(el, "init_result", result);
+ }
+ }
+ bindingDef.renderValue(el, data.x, elementData(el, "init_result"));
+ evalAndRun(data.jsHooks.render, elementData(el, "init_result"), [el, data.x]);
+ };
+
+ // Only override resize if bindingDef implements it
+ if (bindingDef.resize) {
+ shinyBinding.resize = function(el, width, height) {
+ // Shiny can call resize before initialize/renderValue have been
+ // called, which doesn't make sense for widgets.
+ if (elementData(el, "initialized")) {
+ bindingDef.resize(el, width, height, elementData(el, "init_result"));
+ }
+ };
+ }
+
+ Shiny.outputBindings.register(shinyBinding, bindingDef.name);
+ }
+ };
+
+ var scheduleStaticRenderTimerId = null;
+ function scheduleStaticRender() {
+ if (!scheduleStaticRenderTimerId) {
+ scheduleStaticRenderTimerId = setTimeout(function() {
+ scheduleStaticRenderTimerId = null;
+ window.HTMLWidgets.staticRender();
+ }, 1);
+ }
+ }
+
+ // Render static widgets after the document finishes loading
+ // Statically render all elements that are of this widget's class
+ window.HTMLWidgets.staticRender = function() {
+ var bindings = window.HTMLWidgets.widgets || [];
+ forEach(bindings, function(binding) {
+ var matches = binding.find(document.documentElement);
+ forEach(matches, function(el) {
+ var sizeObj = initSizing(el, binding);
+
+ if (hasClass(el, "html-widget-static-bound"))
+ return;
+ el.className = el.className + " html-widget-static-bound";
+
+ var initResult;
+ if (binding.initialize) {
+ initResult = binding.initialize(el,
+ sizeObj ? sizeObj.getWidth() : el.offsetWidth,
+ sizeObj ? sizeObj.getHeight() : el.offsetHeight
+ );
+ elementData(el, "init_result", initResult);
+ }
+
+ if (binding.resize) {
+ var lastSize = {
+ w: sizeObj ? sizeObj.getWidth() : el.offsetWidth,
+ h: sizeObj ? sizeObj.getHeight() : el.offsetHeight
+ };
+ var resizeHandler = function(e) {
+ var size = {
+ w: sizeObj ? sizeObj.getWidth() : el.offsetWidth,
+ h: sizeObj ? sizeObj.getHeight() : el.offsetHeight
+ };
+ if (size.w === 0 && size.h === 0)
+ return;
+ if (size.w === lastSize.w && size.h === lastSize.h)
+ return;
+ lastSize = size;
+ binding.resize(el, size.w, size.h, initResult);
+ };
+
+ on(window, "resize", resizeHandler);
+
+ // This is needed for cases where we're running in a Shiny
+ // app, but the widget itself is not a Shiny output, but
+ // rather a simple static widget. One example of this is
+ // an rmarkdown document that has runtime:shiny and widget
+ // that isn't in a render function. Shiny only knows to
+ // call resize handlers for Shiny outputs, not for static
+ // widgets, so we do it ourselves.
+ if (window.jQuery) {
+ window.jQuery(document).on(
+ "shown.htmlwidgets shown.bs.tab.htmlwidgets shown.bs.collapse.htmlwidgets",
+ resizeHandler
+ );
+ window.jQuery(document).on(
+ "hidden.htmlwidgets hidden.bs.tab.htmlwidgets hidden.bs.collapse.htmlwidgets",
+ resizeHandler
+ );
+ }
+
+ // This is needed for the specific case of ioslides, which
+ // flips slides between display:none and display:block.
+ // Ideally we would not have to have ioslide-specific code
+ // here, but rather have ioslides raise a generic event,
+ // but the rmarkdown package just went to CRAN so the
+ // window to getting that fixed may be long.
+ if (window.addEventListener) {
+ // It's OK to limit this to window.addEventListener
+ // browsers because ioslides itself only supports
+ // such browsers.
+ on(document, "slideenter", resizeHandler);
+ on(document, "slideleave", resizeHandler);
+ }
+ }
+
+ var scriptData = document.querySelector("script[data-for='" + el.id + "'][type='application/json']");
+ if (scriptData) {
+ var data = JSON.parse(scriptData.textContent || scriptData.text);
+ // Resolve strings marked as javascript literals to objects
+ if (!(data.evals instanceof Array)) data.evals = [data.evals];
+ for (var k = 0; data.evals && k < data.evals.length; k++) {
+ window.HTMLWidgets.evaluateStringMember(data.x, data.evals[k]);
+ }
+ binding.renderValue(el, data.x, initResult);
+ evalAndRun(data.jsHooks.render, initResult, [el, data.x]);
+ }
+ });
+ });
+
+ invokePostRenderHandlers();
+ }
+
+
+ function has_jQuery3() {
+ if (!window.jQuery) {
+ return false;
+ }
+ var $version = window.jQuery.fn.jquery;
+ var $major_version = parseInt($version.split(".")[0]);
+ return $major_version >= 3;
+ }
+
+ /*
+ / Shiny 1.4 bumped jQuery from 1.x to 3.x which means jQuery's
+ / on-ready handler (i.e., $(fn)) is now asyncronous (i.e., it now
+ / really means $(setTimeout(fn)).
+ / https://jquery.com/upgrade-guide/3.0/#breaking-change-document-ready-handlers-are-now-asynchronous
+ /
+ / Since Shiny uses $() to schedule initShiny, shiny>=1.4 calls initShiny
+ / one tick later than it did before, which means staticRender() is
+ / called renderValue() earlier than (advanced) widget authors might be expecting.
+ / https://github.com/rstudio/shiny/issues/2630
+ /
+ / For a concrete example, leaflet has some methods (e.g., updateBounds)
+ / which reference Shiny methods registered in initShiny (e.g., setInputValue).
+ / Since leaflet is privy to this life-cycle, it knows to use setTimeout() to
+ / delay execution of those methods (until Shiny methods are ready)
+ / https://github.com/rstudio/leaflet/blob/18ec981/javascript/src/index.js#L266-L268
+ /
+ / Ideally widget authors wouldn't need to use this setTimeout() hack that
+ / leaflet uses to call Shiny methods on a staticRender(). In the long run,
+ / the logic initShiny should be broken up so that method registration happens
+ / right away, but binding happens later.
+ */
+ function maybeStaticRenderLater() {
+ if (shinyMode && has_jQuery3()) {
+ window.jQuery(window.HTMLWidgets.staticRender);
+ } else {
+ window.HTMLWidgets.staticRender();
+ }
+ }
+
+ if (document.addEventListener) {
+ document.addEventListener("DOMContentLoaded", function() {
+ document.removeEventListener("DOMContentLoaded", arguments.callee, false);
+ maybeStaticRenderLater();
+ }, false);
+ } else if (document.attachEvent) {
+ document.attachEvent("onreadystatechange", function() {
+ if (document.readyState === "complete") {
+ document.detachEvent("onreadystatechange", arguments.callee);
+ maybeStaticRenderLater();
+ }
+ });
+ }
+
+
+ window.HTMLWidgets.getAttachmentUrl = function(depname, key) {
+ // If no key, default to the first item
+ if (typeof(key) === "undefined")
+ key = 1;
+
+ var link = document.getElementById(depname + "-" + key + "-attachment");
+ if (!link) {
+ throw new Error("Attachment " + depname + "/" + key + " not found in document");
+ }
+ return link.getAttribute("href");
+ };
+
+ window.HTMLWidgets.dataframeToD3 = function(df) {
+ var names = [];
+ var length;
+ for (var name in df) {
+ if (df.hasOwnProperty(name))
+ names.push(name);
+ if (typeof(df[name]) !== "object" || typeof(df[name].length) === "undefined") {
+ throw new Error("All fields must be arrays");
+ } else if (typeof(length) !== "undefined" && length !== df[name].length) {
+ throw new Error("All fields must be arrays of the same length");
+ }
+ length = df[name].length;
+ }
+ var results = [];
+ var item;
+ for (var row = 0; row < length; row++) {
+ item = {};
+ for (var col = 0; col < names.length; col++) {
+ item[names[col]] = df[names[col]][row];
+ }
+ results.push(item);
+ }
+ return results;
+ };
+
+ window.HTMLWidgets.transposeArray2D = function(array) {
+ if (array.length === 0) return array;
+ var newArray = array[0].map(function(col, i) {
+ return array.map(function(row) {
+ return row[i]
+ })
+ });
+ return newArray;
+ };
+ // Split value at splitChar, but allow splitChar to be escaped
+ // using escapeChar. Any other characters escaped by escapeChar
+ // will be included as usual (including escapeChar itself).
+ function splitWithEscape(value, splitChar, escapeChar) {
+ var results = [];
+ var escapeMode = false;
+ var currentResult = "";
+ for (var pos = 0; pos < value.length; pos++) {
+ if (!escapeMode) {
+ if (value[pos] === splitChar) {
+ results.push(currentResult);
+ currentResult = "";
+ } else if (value[pos] === escapeChar) {
+ escapeMode = true;
+ } else {
+ currentResult += value[pos];
+ }
+ } else {
+ currentResult += value[pos];
+ escapeMode = false;
+ }
+ }
+ if (currentResult !== "") {
+ results.push(currentResult);
+ }
+ return results;
+ }
+ // Function authored by Yihui/JJ Allaire
+ window.HTMLWidgets.evaluateStringMember = function(o, member) {
+ var parts = splitWithEscape(member, '.', '\\');
+ for (var i = 0, l = parts.length; i < l; i++) {
+ var part = parts[i];
+ // part may be a character or 'numeric' member name
+ if (o !== null && typeof o === "object" && part in o) {
+ if (i == (l - 1)) { // if we are at the end of the line then evalulate
+ if (typeof o[part] === "string")
+ o[part] = tryEval(o[part]);
+ } else { // otherwise continue to next embedded object
+ o = o[part];
+ }
+ }
+ }
+ };
+
+ // Retrieve the HTMLWidget instance (i.e. the return value of an
+ // HTMLWidget binding's initialize() or factory() function)
+ // associated with an element, or null if none.
+ window.HTMLWidgets.getInstance = function(el) {
+ return elementData(el, "init_result");
+ };
+
+ // Finds the first element in the scope that matches the selector,
+ // and returns the HTMLWidget instance (i.e. the return value of
+ // an HTMLWidget binding's initialize() or factory() function)
+ // associated with that element, if any. If no element matches the
+ // selector, or the first matching element has no HTMLWidget
+ // instance associated with it, then null is returned.
+ //
+ // The scope argument is optional, and defaults to window.document.
+ window.HTMLWidgets.find = function(scope, selector) {
+ if (arguments.length == 1) {
+ selector = scope;
+ scope = document;
+ }
+
+ var el = scope.querySelector(selector);
+ if (el === null) {
+ return null;
+ } else {
+ return window.HTMLWidgets.getInstance(el);
+ }
+ };
+
+ // Finds all elements in the scope that match the selector, and
+ // returns the HTMLWidget instances (i.e. the return values of
+ // an HTMLWidget binding's initialize() or factory() function)
+ // associated with the elements, in an array. If elements that
+ // match the selector don't have an associated HTMLWidget
+ // instance, the returned array will contain nulls.
+ //
+ // The scope argument is optional, and defaults to window.document.
+ window.HTMLWidgets.findAll = function(scope, selector) {
+ if (arguments.length == 1) {
+ selector = scope;
+ scope = document;
+ }
+
+ var nodes = scope.querySelectorAll(selector);
+ var results = [];
+ for (var i = 0; i < nodes.length; i++) {
+ results.push(window.HTMLWidgets.getInstance(nodes[i]));
+ }
+ return results;
+ };
+
+ var postRenderHandlers = [];
+ function invokePostRenderHandlers() {
+ while (postRenderHandlers.length) {
+ var handler = postRenderHandlers.shift();
+ if (handler) {
+ handler();
+ }
+ }
+ }
+
+ // Register the given callback function to be invoked after the
+ // next time static widgets are rendered.
+ window.HTMLWidgets.addPostRenderHandler = function(callback) {
+ postRenderHandlers.push(callback);
+ };
+
+ // Takes a new-style instance-bound definition, and returns an
+ // old-style class-bound definition. This saves us from having
+ // to rewrite all the logic in this file to accomodate both
+ // types of definitions.
+ function createLegacyDefinitionAdapter(defn) {
+ var result = {
+ name: defn.name,
+ type: defn.type,
+ initialize: function(el, width, height) {
+ return defn.factory(el, width, height);
+ },
+ renderValue: function(el, x, instance) {
+ return instance.renderValue(x);
+ },
+ resize: function(el, width, height, instance) {
+ return instance.resize(width, height);
+ }
+ };
+
+ if (defn.find)
+ result.find = defn.find;
+ if (defn.renderError)
+ result.renderError = defn.renderError;
+ if (defn.clearError)
+ result.clearError = defn.clearError;
+
+ return result;
+ }
+})();
+
diff --git a/docs/articles/HaDeX_files/jquery-1.12.4/LICENSE.txt b/docs/articles/HaDeX_files/jquery-1.12.4/LICENSE.txt
new file mode 100644
index 00000000..5bf4f5e6
--- /dev/null
+++ b/docs/articles/HaDeX_files/jquery-1.12.4/LICENSE.txt
@@ -0,0 +1,37 @@
+Copyright 2005, 2014 jQuery Foundation and other contributors,
+https://jquery.org/
+
+This software consists of voluntary contributions made by many
+individuals. For exact contribution history, see the revision history
+available at https://github.com/jquery/jquery
+
+The following license applies to all parts of this software except as
+documented below:
+
+====
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+====
+
+All files located in the node_modules and external directories are
+externally maintained libraries used by this software which have their
+own licenses; we recommend you read them, as their terms may differ from
+the terms above.
diff --git a/docs/articles/HaDeX_files/jquery-1.12.4/jquery.min.js b/docs/articles/HaDeX_files/jquery-1.12.4/jquery.min.js
new file mode 100644
index 00000000..e8364758
--- /dev/null
+++ b/docs/articles/HaDeX_files/jquery-1.12.4/jquery.min.js
@@ -0,0 +1,5 @@
+/*! jQuery v1.12.4 | (c) jQuery Foundation | jquery.org/license */
+!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=a.document,e=c.slice,f=c.concat,g=c.push,h=c.indexOf,i={},j=i.toString,k=i.hasOwnProperty,l={},m="1.12.4",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return e.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:e.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a){return n.each(this,a)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(e.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:g,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(n.isPlainObject(c)||(b=n.isArray(c)))?(b?(b=!1,f=a&&n.isArray(a)?a:[]):f=a&&n.isPlainObject(a)?a:{},g[d]=n.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray||function(a){return"array"===n.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){var b=a&&a.toString();return!n.isArray(a)&&b-parseFloat(b)+1>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==n.type(a)||a.nodeType||n.isWindow(a))return!1;try{if(a.constructor&&!k.call(a,"constructor")&&!k.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(!l.ownFirst)for(b in a)return k.call(a,b);for(b in a);return void 0===b||k.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?i[j.call(a)]||"object":typeof a},globalEval:function(b){b&&n.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b){var c,d=0;if(s(a)){for(c=a.length;c>d;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):g.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(h)return h.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,g=0,h=[];if(s(a))for(d=a.length;d>g;g++)e=b(a[g],g,c),null!=e&&h.push(e);else for(g in a)e=b(a[g],g,c),null!=e&&h.push(e);return f.apply([],h)},guid:1,proxy:function(a,b){var c,d,f;return"string"==typeof b&&(f=a[b],b=a,a=f),n.isFunction(a)?(c=e.call(arguments,2),d=function(){return a.apply(b||this,c.concat(e.call(arguments)))},d.guid=a.guid=a.guid||n.guid++,d):void 0},now:function(){return+new Date},support:l}),"function"==typeof Symbol&&(n.fn[Symbol.iterator]=c[Symbol.iterator]),n.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(a,b){i["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=!!a&&"length"in a&&a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ga(),z=ga(),A=ga(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+M+"))|)"+L+"*\\]",O=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+N+")*)|.*)\\)|)",P=new RegExp(L+"+","g"),Q=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),R=new RegExp("^"+L+"*,"+L+"*"),S=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),T=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),U=new RegExp(O),V=new RegExp("^"+M+"$"),W={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M+"|[*])"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},X=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Z=/^[^{]+\{\s*\[native \w/,$=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,_=/[+~]/,aa=/'|\\/g,ba=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),ca=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},da=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(ea){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fa(a,b,d,e){var f,h,j,k,l,o,r,s,w=b&&b.ownerDocument,x=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==x&&9!==x&&11!==x)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==x&&(o=$.exec(a)))if(f=o[1]){if(9===x){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(w&&(j=w.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(o[2])return H.apply(d,b.getElementsByTagName(a)),d;if((f=o[3])&&c.getElementsByClassName&&b.getElementsByClassName)return H.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==x)w=b,s=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(aa,"\\$&"):b.setAttribute("id",k=u),r=g(a),h=r.length,l=V.test(k)?"#"+k:"[id='"+k+"']";while(h--)r[h]=l+" "+qa(r[h]);s=r.join(","),w=_.test(a)&&oa(b.parentNode)||b}if(s)try{return H.apply(d,w.querySelectorAll(s)),d}catch(y){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(Q,"$1"),b,d,e)}function ga(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ha(a){return a[u]=!0,a}function ia(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ja(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function ka(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function la(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function na(a){return ha(function(b){return b=+b,ha(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function oa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=fa.support={},f=fa.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fa.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ia(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ia(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Z.test(n.getElementsByClassName),c.getById=ia(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return"undefined"!=typeof b.getElementsByClassName&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=Z.test(n.querySelectorAll))&&(ia(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ia(function(a){var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Z.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ia(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",O)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Z.test(o.compareDocumentPosition),t=b||Z.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return ka(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?ka(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},fa.matches=function(a,b){return fa(a,null,null,b)},fa.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(T,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fa(b,n,null,[a]).length>0},fa.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fa.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fa.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fa.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fa.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fa.selectors={cacheLength:50,createPseudo:ha,match:W,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ba,ca),a[3]=(a[3]||a[4]||a[5]||"").replace(ba,ca),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fa.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fa.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return W.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&U.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ba,ca).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fa.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(P," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fa.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ha(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ha(function(a){var b=[],c=[],d=h(a.replace(Q,"$1"));return d[u]?ha(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ha(function(a){return function(b){return fa(a,b).length>0}}),contains:ha(function(a){return a=a.replace(ba,ca),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ha(function(a){return V.test(a||"")||fa.error("unsupported lang: "+a),a=a.replace(ba,ca).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Y.test(a.nodeName)},input:function(a){return X.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:na(function(){return[0]}),last:na(function(a,b){return[b-1]}),eq:na(function(a,b,c){return[0>c?c+b:c]}),even:na(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:na(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:na(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:na(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function ra(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j,k=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(j=b[u]||(b[u]={}),i=j[b.uniqueID]||(j[b.uniqueID]={}),(h=i[d])&&h[0]===w&&h[1]===f)return k[2]=h[2];if(i[d]=k,k[2]=a(b,c,g))return!0}}}function sa(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ta(a,b,c){for(var d=0,e=b.length;e>d;d++)fa(a,b[d],c);return c}function ua(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(c&&!c(f,d,e)||(g.push(f),j&&b.push(h)));return g}function va(a,b,c,d,e,f){return d&&!d[u]&&(d=va(d)),e&&!e[u]&&(e=va(e,f)),ha(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ta(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ua(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ua(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ua(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function wa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ra(function(a){return a===b},h,!0),l=ra(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[ra(sa(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return va(i>1&&sa(m),i>1&&qa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(Q,"$1"),c,e>i&&wa(a.slice(i,e)),f>e&&wa(a=a.slice(e)),f>e&&qa(a))}m.push(c)}return sa(m)}function xa(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=F.call(i));u=ua(u)}H.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&fa.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ha(f):f}return h=fa.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xa(e,d)),f.selector=a}return f},i=fa.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ba,ca),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=W.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ba,ca),_.test(j[0].type)&&oa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qa(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,!b||_.test(a)&&oa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ia(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ia(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ja("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ia(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ja("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ia(function(a){return null==a.getAttribute("disabled")})||ja(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fa}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.uniqueSort=n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},v=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},w=n.expr.match.needsContext,x=/^<([\w-]+)\s*\/?>(?:<\/\1>|)$/,y=/^.[^:#\[\.,]*$/;function z(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(y.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return n.inArray(a,b)>-1!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;e>b;b++)if(n.contains(d[b],this))return!0}));for(b=0;e>b;b++)n.find(a,d[b],c);return c=this.pushStack(e>1?n.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(z(this,a||[],!1))},not:function(a){return this.pushStack(z(this,a||[],!0))},is:function(a){return!!z(this,"string"==typeof a&&w.test(a)?n(a):a||[],!1).length}});var A,B=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=n.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||A,"string"==typeof a){if(e="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:B.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),x.test(e[1])&&n.isPlainObject(b))for(e in b)n.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}if(f=d.getElementById(e[2]),f&&f.parentNode){if(f.id!==e[2])return A.find(a);this.length=1,this[0]=f}return this.context=d,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof c.ready?c.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};C.prototype=n.fn,A=n(d);var D=/^(?:parents|prev(?:Until|All))/,E={children:!0,contents:!0,next:!0,prev:!0};n.fn.extend({has:function(a){var b,c=n(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(n.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=w.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?n.inArray(this[0],n(a)):n.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.uniqueSort(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function F(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return u(a,"parentNode")},parentsUntil:function(a,b,c){return u(a,"parentNode",c)},next:function(a){return F(a,"nextSibling")},prev:function(a){return F(a,"previousSibling")},nextAll:function(a){return u(a,"nextSibling")},prevAll:function(a){return u(a,"previousSibling")},nextUntil:function(a,b,c){return u(a,"nextSibling",c)},prevUntil:function(a,b,c){return u(a,"previousSibling",c)},siblings:function(a){return v((a.parentNode||{}).firstChild,a)},children:function(a){return v(a.firstChild)},contents:function(a){return n.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(E[a]||(e=n.uniqueSort(e)),D.test(a)&&(e=e.reverse())),this.pushStack(e)}});var G=/\S+/g;function H(a){var b={};return n.each(a.match(G)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?H(a):n.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h-1)f.splice(c,1),h>=c&&h--}),this},has:function(a){return a?n.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=!0,c||j.disable(),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().progress(c.notify).done(c.resolve).fail(c.reject):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=e.call(arguments),d=c.length,f=1!==d||a&&n.isFunction(a.promise)?d:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?e.call(arguments):d,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(d>1)for(i=new Array(d),j=new Array(d),k=new Array(d);d>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().progress(h(b,j,i)).done(h(b,k,c)).fail(g.reject):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(d,[n]),n.fn.triggerHandler&&(n(d).triggerHandler("ready"),n(d).off("ready"))))}});function J(){d.addEventListener?(d.removeEventListener("DOMContentLoaded",K),a.removeEventListener("load",K)):(d.detachEvent("onreadystatechange",K),a.detachEvent("onload",K))}function K(){(d.addEventListener||"load"===a.event.type||"complete"===d.readyState)&&(J(),n.ready())}n.ready.promise=function(b){if(!I)if(I=n.Deferred(),"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll)a.setTimeout(n.ready);else if(d.addEventListener)d.addEventListener("DOMContentLoaded",K),a.addEventListener("load",K);else{d.attachEvent("onreadystatechange",K),a.attachEvent("onload",K);var c=!1;try{c=null==a.frameElement&&d.documentElement}catch(e){}c&&c.doScroll&&!function f(){if(!n.isReady){try{c.doScroll("left")}catch(b){return a.setTimeout(f,50)}J(),n.ready()}}()}return I.promise(b)},n.ready.promise();var L;for(L in n(l))break;l.ownFirst="0"===L,l.inlineBlockNeedsLayout=!1,n(function(){var a,b,c,e;c=d.getElementsByTagName("body")[0],c&&c.style&&(b=d.createElement("div"),e=d.createElement("div"),e.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(e).appendChild(b),"undefined"!=typeof b.style.zoom&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",l.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(e))}),function(){var a=d.createElement("div");l.deleteExpando=!0;try{delete a.test}catch(b){l.deleteExpando=!1}a=null}();var M=function(a){var b=n.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b},N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(O,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}n.data(a,b,c)}else c=void 0;
+}return c}function Q(a){var b;for(b in a)if(("data"!==b||!n.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function R(a,b,d,e){if(M(a)){var f,g,h=n.expando,i=a.nodeType,j=i?n.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||n.guid++:h),j[k]||(j[k]=i?{}:{toJSON:n.noop}),"object"!=typeof b&&"function"!=typeof b||(e?j[k]=n.extend(j[k],b):j[k].data=n.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[n.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[n.camelCase(b)])):f=g,f}}function S(a,b,c){if(M(a)){var d,e,f=a.nodeType,g=f?n.cache:a,h=f?a[n.expando]:n.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){n.isArray(b)?b=b.concat(n.map(b,n.camelCase)):b in d?b=[b]:(b=n.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!Q(d):!n.isEmptyObject(d))return}(c||(delete g[h].data,Q(g[h])))&&(f?n.cleanData([a],!0):l.deleteExpando||g!=g.window?delete g[h]:g[h]=void 0)}}}n.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?n.cache[a[n.expando]]:a[n.expando],!!a&&!Q(a)},data:function(a,b,c){return R(a,b,c)},removeData:function(a,b){return S(a,b)},_data:function(a,b,c){return R(a,b,c,!0)},_removeData:function(a,b){return S(a,b,!0)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=n.data(f),1===f.nodeType&&!n._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));n._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){n.data(this,a)}):arguments.length>1?this.each(function(){n.data(this,a,b)}):f?P(f,a,n.data(f,a)):void 0},removeData:function(a){return this.each(function(){n.removeData(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=n._data(a,b),c&&(!d||n.isArray(c)?d=n._data(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return n._data(a,c)||n._data(a,c,{empty:n.Callbacks("once memory").add(function(){n._removeData(a,b+"queue"),n._removeData(a,c)})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},Z=/^(?:checkbox|radio)$/i,$=/<([\w:-]+)/,_=/^$|\/(?:java|ecma)script/i,aa=/^\s+/,ba="abbr|article|aside|audio|bdi|canvas|data|datalist|details|dialog|figcaption|figure|footer|header|hgroup|main|mark|meter|nav|output|picture|progress|section|summary|template|time|video";function ca(a){var b=ba.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}!function(){var a=d.createElement("div"),b=d.createDocumentFragment(),c=d.createElement("input");a.innerHTML="
Currently, HaDeX is limited to the cluster file from DynamX 3.0 or 2.0. Below we explain how the data file is processed.
+
+
+Processing data from DynamX
+
Let’s investigate how the data processing of the cluster file from DynamX is conducted on the example file from the package.
+
+
+Differences between files
+
What is the difference between cluster files from DynamX 3.0 and 2.0? The datafiles from DynamX 2.0 don’t include Modification and Fragment columns. The variations of the experiment were limited, while the DynamX 2.0 was the latest version.
## Protein Start End Sequence Modification Fragment MaxUptake MHP
+## 1: db_CD160 1 15 INITSSASQEGTRLN NA NA 14 1590.808
+## 2: db_CD160 1 15 INITSSASQEGTRLN NA NA 14 1590.808
+## 3: db_CD160 1 15 INITSSASQEGTRLN NA NA 14 1590.808
+## 4: db_CD160 1 15 INITSSASQEGTRLN NA NA 14 1590.808
+## 5: db_CD160 1 15 INITSSASQEGTRLN NA NA 14 1590.808
+## 6: db_CD160 1 15 INITSSASQEGTRLN NA NA 14 1590.808
+## 7: db_CD160 1 15 INITSSASQEGTRLN NA NA 14 1590.808
+## 8: db_CD160 1 15 INITSSASQEGTRLN NA NA 14 1590.808
+## 9: db_CD160 1 15 INITSSASQEGTRLN NA NA 14 1590.808
+## 10: db_CD160 1 15 INITSSASQEGTRLN NA NA 14 1590.808
+## State Exposure File z RT Inten Center
+## 1: CD160 0.000 KD_160527_CD160_sekw_05 1 3.232479 6592 1591.2584
+## 2: CD160 0.000 KD_160527_CD160_sekw_05 2 3.238079 394066 796.3552
+## 3: CD160 0.000 KD_160527_CD160_sekw_05 3 3.238759 173526 531.2633
+## 4: CD160 0.001 KD_160527_CD160_IN_01 2 3.258598 232221 796.3634
+## 5: CD160 0.001 KD_160527_CD160_IN_01 3 3.256844 110675 531.2849
+## 6: CD160 0.167 KD_160530_CD160_10s_01 2 3.262774 99894 800.3610
+## 7: CD160 0.167 KD_160530_CD160_10s_02 2 3.264558 117541 800.3852
+## 8: CD160 0.167 KD_160530_CD160_10s_03 2 3.263795 90562 800.3682
+## 9: CD160 0.167 KD_160530_CD160_10s_04 2 3.273656 66131 800.4242
+## 10: CD160 1.000 KD_160530_CD160_1min_01 2 3.262300 109301 800.7878
+
As you can see, the data file has a very specific structure and is not informative yet. In the file, we have m/z values for each z value (charge) for each time point for each state of each peptide, repeated as many times as measurement was repeated (each measurement should be repeated at least three times).
+
+
Our aim is to have one result with an uncertainty of the measurement per each peptide in each biological state in each measured time point - data in this format allows further calculations, e.q. calculating deuterium uptake values.
+
For a better understanding of the process of aggregating the data, see the Data aggregation article.
+
Within each replicate of the measurement (we recognize each replicate by the File value), the m/z values are provided for each possible z value. The m/z values are in the Center column, as it is a geometrical centroid calculated from the isotopic envelope. Firstly, we have to calculate the mass value, measured experimentally:
+
\[expMass = z \times (Center-protonMass)\tag{1}\]
+
To aggregate data from different z values, we have to calculate the mean mass weighted by intensity. Additional information about this step and how the weighted mean impacts the results can be found in Mass calculation article.
+\(aggMass\) - mass of the peptide [Da], average from replicates,
+
+\(Inten_k\) - intensity of the measurement,
+
+\(pepMass\) - mass of the peptide, calculated using Equation 1.
+
+
As we use the aggregated result from the replicates, we need to calculate an uncertainty associated with the measurement. We use the mean value as the final result, so we need to calculate error as a standard deviation of the mean, according to the Equation 3:
+\(\overline{x}\) - mean value from all of the replicates,
+
+\(n\) - number of replicates.
+
+
Now we have the format we want for further calculations.
+
+
+
+Calculation of the deuterium uptake
+
HaDeX package provides the calculated values in different forms. All of them are provided with associated uncertainty of the measurement. All of the uncertainties are derived from the formula - the Law of propagation of uncertainty:
Deuterium uptake is the increase of the mass of the peptide in time \(t\). The minimal exchange control \(m_{t_0}\) is mass measured directly after adding the buffer (before the start of the exchange), and \(m_t\) is the mass measured in chosen time point \(t\). The value is in Daltons [Da].
+
\[D = m_{t} - m_{t_0}\] The uncertainty associated with deuterium uptake [Da] (based on equation 3):
+
\[u_c(D) = \sqrt{u(m_t)^2 + u(m_{t_0})^2}\]
+
+
+
+Fractional deuterium uptake
+
Fractional deuterium uptake is the ratio of the increase of the mass in time \(t\) to the maximal exchange control. The maximal exchange control \(m_{t_{100}}\) is measured after a long time (chosen by the experimenter, usually 1440 min = 24 h). It is assumed that after this long time, the exchange is finished. The minimal exchange control \(m_{t_0}\) is mass measured directly after adding the buffer (before the start of the exchange), and \(m_t\) is the mass measured in chosen time point \(t\). This value is a percentage value [%].
Theoretical deuterium uptake is the increase of mass in time \(t\) compared with the theoretical value of the peptide mass without any exchange (\(MHP\) - a mass of the singly charged monoisotopic molecular ion), and \(m_t\) is the mass measured in chosen time point \(t\). This value is in daltons [Da]:
+
\[D_{theo} = m_{t} - MHP\]
+
The uncertainty associated with theoretical deuterium uptake [Da] (the \(MHP\) value is a constant without measurement uncertainty - based on the equation 3):
+
\[u(D_{theo}) = u(m_t)\]
+
+
+
+Theoretical fractional deuterium uptake
+
Theoretical fractional deuterium uptake is the ratio of the increase of mass in time \(t\) compared with a theoretical value of the mass of the peptide without any exchange to the possible theoretical increase of the mass, based on the maximal potential uptake of the peptide (based on the peptide sequence). This value is a percentage value [%].
Differential value is the way to see how the deuterium uptake differs between two biological states. It allows seeing if the possible difference is statistically important (more information below). This value is calculated as the difference between the previously described (in a chosen form) deuterium uptake of the first and second states.
+
\[diff = D_{1} - D_{2}\] The uncertainty associated with the difference of deuterium uptake (based on the equation 3):
+
\[u_{c}(diff) = \sqrt{u(D_{1})^2 + u(D_{2})^2}\]
+
The convenient way to present results calculated as described is the comparison plot and differential plot (Woods’ plot).
+
+
+
+
+Additional information
+
If the file contains modified peptides - the value from column Modification is added to the value from column State and is treated as a new biological state. The further aspects of the analysis are the same as for non-modified peptides.
+Comparison of results with weighted mean and without
+
As it is described in Data processing article, the data within each replicate of the experiment is aggregated using weighted mean. Below we present the effect it has on the results.
+
The whole workflow is described in the mentioned article. Here the focus is on the first aspect of the processing.
+
For the analysis, we use the example file from HaDeX.
As described, the first step is to transform the Center value (geometric centroid of the isotopic envelope for given peptide in a given state in given time point) and then to aggregate the values measured for different charge values. This is all done within each replicate.
+
The aggregation in our workflow is a weighted mean, with Inten (intensity) values as weights, as shown below.
Supplement to: “HaDeX: Analysis and Visualisation of Hydrogen/Deuterium Exchange Mass Spectrometry Data”
+
Supplement to: “HaDeX: Analysis and Visualisation of Hydrogen/Deuterium Exchange Mass Spectrometry Data”
Weronika Puchała, Michał Burdukiewicz, Michał Kistowski, Katarzyna A. Dąbrowska, Aleksandra E. Badaczewska-Dawid, Dominik Cysewski, Michał Dadlez
20.06.2019
@@ -92,6 +103,10 @@
20.06.2019
+
## Warning: replacing previous import 'vctrs::data_frame' by 'tibble::data_frame'
+## when loading 'dplyr'
+
## Warning: pakiet 'ggplot2' został zbudowany w wersji R 4.0.3
+
## Warning: pakiet 'DT' został zbudowany w wersji R 4.0.3
About HaDeX
@@ -102,8 +117,8 @@
Comparison of the existing HDX-MS software
To show the novelty of HaDeX, we compare its functionalities with other relatively new software for analysis of HDX-MS data: MEMHDX (Hourdel et al. 2016) and Deuteros (Lau et al. 2019).
-
-
We have not considered HDX Workbench (Pascal et al. 2012) as it deals with the preliminary steps of the analysis. This comparison also does not cover a versatile structural visualisation tool for HDX-MS results, HDX-Viewer (Bouyssié et al. 2019) as its scope is different from the tools mentioned above.
+
+
We have not considered HDX Workbench (Pascal et al. 2012) as it deals with the preliminary steps of the analysis. This comparison also does not cover a versatile structural visualisation tool for HDX-MS results, HDX-Viewer (Bouyssié et al. 2019) as its scope is different from the tools mentioned above.
Web server: a software is available as a web server.
Programmatic access: analytic functionalities are documented and available from a command line.
Desktop software: a software can be installed locally.
@@ -133,10 +148,11 @@
Data import
The HaDeX web server works only on data in the DynamX datafile format (Waters Corp.). The data from other sources may be also adjusted to the format accepted by HaDeX provided it has following columns:
-
-
Although data can be imported into R using other tools, we strongly advise to rely on the read_hdx() function:
Currently, read_hdx() supports .csv, .tsv and .xls files fulfilling the data structure described above. Files with data from multiple proteins are supported. The user need to indicate which protein is of interest for calculations.
@@ -215,7 +231,7 @@
Theoretical deuteration level
-
As opposed to the experimental deuteration levels, theoretical deuteration level only partially depends on the experimental data. Here, the maximum deuteration level is based on a hypothetical peptide where all hydrogens were replaced by deuters, as it is shown in equation 8:
+
As opposed to the experimental deuteration levels, theoretical deuteration level only partially depends on the experimental data. Here, the maximum deuteration level is based on a hypothetical peptide where all hydrogens were replaced by deuterons, as it is shown in equation 8:
+woods_plot(calc_dat =calc_dat,
+ theoretical =FALSE,
+ relative =FALSE)+
+ labs(title ="Theoretical fraction exchanged between states in 25 min time")
Confidence limit in Woods plot
The function calculate_confidence_limit_values() calculates confidence limit values as it is described elsewhere (Houde, Berkowitz, and Engen 2011).
By the term kinetics we understand deuteration change in time. To calculate deuteration values per peptide for different time points is used function calculate_kinetics(). This function uses the calculate_state_deuteration() function.
The sequence of the protein(s) is reconstructed from the peptides from the input file. Thus, amino acids not covered by peptides are marked as X according to the IUPAC convention. The sequence is reconstructed using the reconstruct_sequence() function.
The user can choose which state (or states) should be included in these plots. If this parameter is not provided, the first possible state is chosen. If a given peptide is available in more than one state, it is shown only once.
@@ -484,19 +520,21 @@
In HDX-MS experiments, the average uncertainty of measurements decreases over time as the sample is more and more deuterated (even accounting for the back-propagation). Therefore, if the level of uncertainty is stable, the exchange is still ongoing and it would be advisable to prolong the reaction.
Moreover, the user can detect a time point after which the decrease of the deuteration uncertainty becomes too marginal to prolong the measurements. This function is most useful in case of multiple measurements of the same or very similar proteins because it helps to optimize the duration of the incubation. The result of this function can be easily visualized.
Then, we reconstruct the protein sequence from the peptides measured during the experiment. We observe the region from amino acid 107 till amino acid 124 is not covered by any peptide.
The theoretical plot allows finding regions, which exchange quickly (N-terminus, regions between 30-70 amino acid) and regions, which exchange slowly (peptides 15-24, 95-110 amino acid). We can also see the differences in the exchange between two states, indicating regions which changed upon binding with other protein.
On the experimental plot, there are visible regions, which exchange quickly (N terminal part, regions between 30-70 amino acid) and regions, which exchange slowly (peptides 15-24, 30-35, 95-110 amino acid).
The plot below shows peptides for which levels of deuteration were significantly lower upon binding with other protein (red) and peptides for which levels of exchange were significantly higher upon binding with other protein (blue). The plot also shows peptides in which no significant changes in deuteration between states are visible (grey). The biggest changes on the theoretical plot can be observed in 3 peptides (15-24, 30-35, 75-90).
/g,">").replace(/"/g,"""):a};q.render={number:function(a,b,c,d,e){return{display:function(f){if("number"!==typeof f&&"string"!==typeof f)return f;var g=0>f?"-":"",h=parseFloat(f);if(isNaN(h))return ib(f);h=h.toFixed(c);f=Math.abs(h);h=parseInt(f,10);f=c?b+(f-h).toFixed(c).substring(2):"";return g+(d||"")+h.toString().replace(/\B(?=(\d{3})+(?!\d))/g,
+a)+f+(e||"")}}},text:function(){return{display:ib,filter:ib}}};f.extend(q.ext.internal,{_fnExternApiFunc:Qb,_fnBuildAjax:va,_fnAjaxUpdate:qb,_fnAjaxParameters:zb,_fnAjaxUpdateDraw:Ab,_fnAjaxDataSrc:wa,_fnAddColumn:Ia,_fnColumnOptions:ma,_fnAdjustColumnSizing:aa,_fnVisibleToColumnIndex:ba,_fnColumnIndexToVisible:ca,_fnVisbleColumns:W,_fnGetColumns:oa,_fnColumnTypes:Ka,_fnApplyColumnDefs:nb,_fnHungarianMap:H,_fnCamelToHungarian:L,_fnLanguageCompat:Ga,_fnBrowserDetect:lb,_fnAddData:R,_fnAddTr:pa,_fnNodeToDataIndex:function(a,
+b){return b._DT_RowIndex!==p?b._DT_RowIndex:null},_fnNodeToColumnIndex:function(a,b,c){return f.inArray(c,a.aoData[b].anCells)},_fnGetCellData:I,_fnSetCellData:ob,_fnSplitObjNotation:Na,_fnGetObjectDataFn:U,_fnSetObjectDataFn:Q,_fnGetDataMaster:Oa,_fnClearTable:qa,_fnDeleteIndex:ra,_fnInvalidate:ea,_fnGetRowElements:Ma,_fnCreateTr:La,_fnBuildHead:pb,_fnDrawHead:ha,_fnDraw:S,_fnReDraw:V,_fnAddOptionsHtml:sb,_fnDetectHeader:fa,_fnGetUniqueThs:ua,_fnFeatureHtmlFilter:ub,_fnFilterComplete:ia,_fnFilterCustom:Db,
+_fnFilterColumn:Cb,_fnFilter:Bb,_fnFilterCreateSearch:Ta,_fnEscapeRegex:Ua,_fnFilterData:Eb,_fnFeatureHtmlInfo:xb,_fnUpdateInfo:Hb,_fnInfoMacros:Ib,_fnInitialise:ja,_fnInitComplete:xa,_fnLengthChange:Va,_fnFeatureHtmlLength:tb,_fnFeatureHtmlPaginate:yb,_fnPageChange:Xa,_fnFeatureHtmlProcessing:vb,_fnProcessingDisplay:K,_fnFeatureHtmlTable:wb,_fnScrollDraw:na,_fnApplyToChildren:N,_fnCalculateColumnWidths:Ja,_fnThrottle:Sa,_fnConvertToWidth:Jb,_fnGetWidestNode:Kb,_fnGetMaxLenString:Lb,_fnStringToCss:B,
+_fnSortFlatten:Y,_fnSort:rb,_fnSortAria:Nb,_fnSortListener:Za,_fnSortAttachListener:Qa,_fnSortingClasses:Aa,_fnSortData:Mb,_fnSaveState:Ba,_fnLoadState:Ob,_fnSettingsFromNode:Ca,_fnLog:O,_fnMap:M,_fnBindAction:$a,_fnCallbackReg:E,_fnCallbackFire:A,_fnLengthOverflow:Wa,_fnRenderer:Ra,_fnDataSource:D,_fnRowAttributes:Pa,_fnExtend:ab,_fnCalculateEnd:function(){}});f.fn.dataTable=q;q.$=f;f.fn.dataTableSettings=q.settings;f.fn.dataTableExt=q.ext;f.fn.DataTable=function(a){return f(this).dataTable(a).api()};
+f.each(q,function(a,b){f.fn.DataTable[a]=b});return f.fn.dataTable});
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-10-1.png b/docs/articles/overview_files/figure-html/unnamed-chunk-10-1.png
index bd23ec52..37ecf056 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-10-1.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-10-1.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-11-1.png b/docs/articles/overview_files/figure-html/unnamed-chunk-11-1.png
index 580e7082..a486a32d 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-11-1.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-11-1.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-12-1.png b/docs/articles/overview_files/figure-html/unnamed-chunk-12-1.png
index b7e7bb0b..b7f6cc9d 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-12-1.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-12-1.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-13-1.png b/docs/articles/overview_files/figure-html/unnamed-chunk-13-1.png
index aa8c6544..016a4d8e 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-13-1.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-13-1.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-14-1.png b/docs/articles/overview_files/figure-html/unnamed-chunk-14-1.png
index f78173b9..d184bd45 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-14-1.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-14-1.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-16-1.png b/docs/articles/overview_files/figure-html/unnamed-chunk-16-1.png
index de6798c0..6850caad 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-16-1.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-16-1.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-16-2.png b/docs/articles/overview_files/figure-html/unnamed-chunk-16-2.png
new file mode 100644
index 00000000..79ca4279
Binary files /dev/null and b/docs/articles/overview_files/figure-html/unnamed-chunk-16-2.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-18-1.png b/docs/articles/overview_files/figure-html/unnamed-chunk-18-1.png
index 4fd1ca36..af200b5b 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-18-1.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-18-1.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-19-1.png b/docs/articles/overview_files/figure-html/unnamed-chunk-19-1.png
index 497ac20e..bd2abed2 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-19-1.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-19-1.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-20-1.png b/docs/articles/overview_files/figure-html/unnamed-chunk-20-1.png
index ec3eb1ef..af3dfae5 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-20-1.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-20-1.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-21-1.png b/docs/articles/overview_files/figure-html/unnamed-chunk-21-1.png
index f6eb0ad3..d0311845 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-21-1.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-21-1.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-22-1.png b/docs/articles/overview_files/figure-html/unnamed-chunk-22-1.png
index 1f2473ed..848c35da 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-22-1.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-22-1.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-23-1.png b/docs/articles/overview_files/figure-html/unnamed-chunk-23-1.png
index e29bbe2c..e571442f 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-23-1.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-23-1.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-24-1.png b/docs/articles/overview_files/figure-html/unnamed-chunk-24-1.png
index 4fd1ca36..6850caad 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-24-1.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-24-1.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-24-2.png b/docs/articles/overview_files/figure-html/unnamed-chunk-24-2.png
index a6a790dc..79ca4279 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-24-2.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-24-2.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-25-1.png b/docs/articles/overview_files/figure-html/unnamed-chunk-25-1.png
index 140fee3f..dfb4b563 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-25-1.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-25-1.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-26-1.png b/docs/articles/overview_files/figure-html/unnamed-chunk-26-1.png
index 020147b1..af200b5b 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-26-1.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-26-1.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-27-1.png b/docs/articles/overview_files/figure-html/unnamed-chunk-27-1.png
index c120175d..c3006fb4 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-27-1.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-27-1.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-27-2.png b/docs/articles/overview_files/figure-html/unnamed-chunk-27-2.png
index 06c4a840..949c9cd3 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-27-2.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-27-2.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-27-3.png b/docs/articles/overview_files/figure-html/unnamed-chunk-27-3.png
index b765c47b..03cd6139 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-27-3.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-27-3.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-28-1.png b/docs/articles/overview_files/figure-html/unnamed-chunk-28-1.png
index 5bb76898..40fa1486 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-28-1.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-28-1.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-28-2.png b/docs/articles/overview_files/figure-html/unnamed-chunk-28-2.png
index 250ac413..fec71b40 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-28-2.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-28-2.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-28-3.png b/docs/articles/overview_files/figure-html/unnamed-chunk-28-3.png
index 871b2a3f..c5b149ec 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-28-3.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-28-3.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-28-4.png b/docs/articles/overview_files/figure-html/unnamed-chunk-28-4.png
index 910e221e..0f61733c 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-28-4.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-28-4.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-28-5.png b/docs/articles/overview_files/figure-html/unnamed-chunk-28-5.png
index 3e293db9..d7a9558b 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-28-5.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-28-5.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-28-6.png b/docs/articles/overview_files/figure-html/unnamed-chunk-28-6.png
index 2a14cef0..7ffc4e87 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-28-6.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-28-6.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-28-7.png b/docs/articles/overview_files/figure-html/unnamed-chunk-28-7.png
index e0a5dbc6..b7f6cc9d 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-28-7.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-28-7.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-28-8.png b/docs/articles/overview_files/figure-html/unnamed-chunk-28-8.png
index 20b30193..f3814409 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-28-8.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-28-8.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-28-9.png b/docs/articles/overview_files/figure-html/unnamed-chunk-28-9.png
index 67290b19..5c818428 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-28-9.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-28-9.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-29-1.png b/docs/articles/overview_files/figure-html/unnamed-chunk-29-1.png
index 140fee3f..c4664596 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-29-1.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-29-1.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-30-1.png b/docs/articles/overview_files/figure-html/unnamed-chunk-30-1.png
index cfb87fc0..ab15744c 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-30-1.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-30-1.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-31-1.png b/docs/articles/overview_files/figure-html/unnamed-chunk-31-1.png
index f41b9b3f..e571442f 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-31-1.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-31-1.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-32-1.png b/docs/articles/overview_files/figure-html/unnamed-chunk-32-1.png
index d5fb2a29..4766417c 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-32-1.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-32-1.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-32-2.png b/docs/articles/overview_files/figure-html/unnamed-chunk-32-2.png
index 250ac413..3342318a 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-32-2.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-32-2.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-33-1.png b/docs/articles/overview_files/figure-html/unnamed-chunk-33-1.png
index 567bb092..dfb4b563 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-33-1.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-33-1.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-34-1.png b/docs/articles/overview_files/figure-html/unnamed-chunk-34-1.png
index 254f0151..d26402e6 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-34-1.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-34-1.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-35-1.png b/docs/articles/overview_files/figure-html/unnamed-chunk-35-1.png
index 33dd1666..0eec8da8 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-35-1.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-35-1.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-35-2.png b/docs/articles/overview_files/figure-html/unnamed-chunk-35-2.png
index 667d7418..949c9cd3 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-35-2.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-35-2.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-35-3.png b/docs/articles/overview_files/figure-html/unnamed-chunk-35-3.png
index 0b0c456a..03cd6139 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-35-3.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-35-3.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-36-1.png b/docs/articles/overview_files/figure-html/unnamed-chunk-36-1.png
index cd7bfc05..40fa1486 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-36-1.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-36-1.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-36-2.png b/docs/articles/overview_files/figure-html/unnamed-chunk-36-2.png
index 8d2e92ca..fec71b40 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-36-2.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-36-2.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-36-3.png b/docs/articles/overview_files/figure-html/unnamed-chunk-36-3.png
index c1d1825a..c5b149ec 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-36-3.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-36-3.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-36-4.png b/docs/articles/overview_files/figure-html/unnamed-chunk-36-4.png
index dec092d2..0f61733c 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-36-4.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-36-4.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-36-5.png b/docs/articles/overview_files/figure-html/unnamed-chunk-36-5.png
index 3ffb78cc..d7a9558b 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-36-5.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-36-5.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-36-6.png b/docs/articles/overview_files/figure-html/unnamed-chunk-36-6.png
index df7725fd..7ffc4e87 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-36-6.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-36-6.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-36-7.png b/docs/articles/overview_files/figure-html/unnamed-chunk-36-7.png
index b7e7bb0b..b7f6cc9d 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-36-7.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-36-7.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-36-8.png b/docs/articles/overview_files/figure-html/unnamed-chunk-36-8.png
index 994cec18..f3814409 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-36-8.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-36-8.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-36-9.png b/docs/articles/overview_files/figure-html/unnamed-chunk-36-9.png
index 0a1f4799..5c818428 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-36-9.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-36-9.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-7-1.png b/docs/articles/overview_files/figure-html/unnamed-chunk-7-1.png
index e859d5d2..f308a118 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-7-1.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-7-1.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-8-1.png b/docs/articles/overview_files/figure-html/unnamed-chunk-8-1.png
index 87f4e6d1..bf226615 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-8-1.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-8-1.png differ
diff --git a/docs/articles/overview_files/figure-html/unnamed-chunk-9-1.png b/docs/articles/overview_files/figure-html/unnamed-chunk-9-1.png
index c19181a2..040e14d9 100644
Binary files a/docs/articles/overview_files/figure-html/unnamed-chunk-9-1.png and b/docs/articles/overview_files/figure-html/unnamed-chunk-9-1.png differ
diff --git a/docs/articles/overview_files/htmlwidgets-1.5.2/htmlwidgets.js b/docs/articles/overview_files/htmlwidgets-1.5.2/htmlwidgets.js
new file mode 100644
index 00000000..6f3d672d
--- /dev/null
+++ b/docs/articles/overview_files/htmlwidgets-1.5.2/htmlwidgets.js
@@ -0,0 +1,903 @@
+(function() {
+ // If window.HTMLWidgets is already defined, then use it; otherwise create a
+ // new object. This allows preceding code to set options that affect the
+ // initialization process (though none currently exist).
+ window.HTMLWidgets = window.HTMLWidgets || {};
+
+ // See if we're running in a viewer pane. If not, we're in a web browser.
+ var viewerMode = window.HTMLWidgets.viewerMode =
+ /\bviewer_pane=1\b/.test(window.location);
+
+ // See if we're running in Shiny mode. If not, it's a static document.
+ // Note that static widgets can appear in both Shiny and static modes, but
+ // obviously, Shiny widgets can only appear in Shiny apps/documents.
+ var shinyMode = window.HTMLWidgets.shinyMode =
+ typeof(window.Shiny) !== "undefined" && !!window.Shiny.outputBindings;
+
+ // We can't count on jQuery being available, so we implement our own
+ // version if necessary.
+ function querySelectorAll(scope, selector) {
+ if (typeof(jQuery) !== "undefined" && scope instanceof jQuery) {
+ return scope.find(selector);
+ }
+ if (scope.querySelectorAll) {
+ return scope.querySelectorAll(selector);
+ }
+ }
+
+ function asArray(value) {
+ if (value === null)
+ return [];
+ if ($.isArray(value))
+ return value;
+ return [value];
+ }
+
+ // Implement jQuery's extend
+ function extend(target /*, ... */) {
+ if (arguments.length == 1) {
+ return target;
+ }
+ for (var i = 1; i < arguments.length; i++) {
+ var source = arguments[i];
+ for (var prop in source) {
+ if (source.hasOwnProperty(prop)) {
+ target[prop] = source[prop];
+ }
+ }
+ }
+ return target;
+ }
+
+ // IE8 doesn't support Array.forEach.
+ function forEach(values, callback, thisArg) {
+ if (values.forEach) {
+ values.forEach(callback, thisArg);
+ } else {
+ for (var i = 0; i < values.length; i++) {
+ callback.call(thisArg, values[i], i, values);
+ }
+ }
+ }
+
+ // Replaces the specified method with the return value of funcSource.
+ //
+ // Note that funcSource should not BE the new method, it should be a function
+ // that RETURNS the new method. funcSource receives a single argument that is
+ // the overridden method, it can be called from the new method. The overridden
+ // method can be called like a regular function, it has the target permanently
+ // bound to it so "this" will work correctly.
+ function overrideMethod(target, methodName, funcSource) {
+ var superFunc = target[methodName] || function() {};
+ var superFuncBound = function() {
+ return superFunc.apply(target, arguments);
+ };
+ target[methodName] = funcSource(superFuncBound);
+ }
+
+ // Add a method to delegator that, when invoked, calls
+ // delegatee.methodName. If there is no such method on
+ // the delegatee, but there was one on delegator before
+ // delegateMethod was called, then the original version
+ // is invoked instead.
+ // For example:
+ //
+ // var a = {
+ // method1: function() { console.log('a1'); }
+ // method2: function() { console.log('a2'); }
+ // };
+ // var b = {
+ // method1: function() { console.log('b1'); }
+ // };
+ // delegateMethod(a, b, "method1");
+ // delegateMethod(a, b, "method2");
+ // a.method1();
+ // a.method2();
+ //
+ // The output would be "b1", "a2".
+ function delegateMethod(delegator, delegatee, methodName) {
+ var inherited = delegator[methodName];
+ delegator[methodName] = function() {
+ var target = delegatee;
+ var method = delegatee[methodName];
+
+ // The method doesn't exist on the delegatee. Instead,
+ // call the method on the delegator, if it exists.
+ if (!method) {
+ target = delegator;
+ method = inherited;
+ }
+
+ if (method) {
+ return method.apply(target, arguments);
+ }
+ };
+ }
+
+ // Implement a vague facsimilie of jQuery's data method
+ function elementData(el, name, value) {
+ if (arguments.length == 2) {
+ return el["htmlwidget_data_" + name];
+ } else if (arguments.length == 3) {
+ el["htmlwidget_data_" + name] = value;
+ return el;
+ } else {
+ throw new Error("Wrong number of arguments for elementData: " +
+ arguments.length);
+ }
+ }
+
+ // http://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
+ function escapeRegExp(str) {
+ return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
+ }
+
+ function hasClass(el, className) {
+ var re = new RegExp("\\b" + escapeRegExp(className) + "\\b");
+ return re.test(el.className);
+ }
+
+ // elements - array (or array-like object) of HTML elements
+ // className - class name to test for
+ // include - if true, only return elements with given className;
+ // if false, only return elements *without* given className
+ function filterByClass(elements, className, include) {
+ var results = [];
+ for (var i = 0; i < elements.length; i++) {
+ if (hasClass(elements[i], className) == include)
+ results.push(elements[i]);
+ }
+ return results;
+ }
+
+ function on(obj, eventName, func) {
+ if (obj.addEventListener) {
+ obj.addEventListener(eventName, func, false);
+ } else if (obj.attachEvent) {
+ obj.attachEvent(eventName, func);
+ }
+ }
+
+ function off(obj, eventName, func) {
+ if (obj.removeEventListener)
+ obj.removeEventListener(eventName, func, false);
+ else if (obj.detachEvent) {
+ obj.detachEvent(eventName, func);
+ }
+ }
+
+ // Translate array of values to top/right/bottom/left, as usual with
+ // the "padding" CSS property
+ // https://developer.mozilla.org/en-US/docs/Web/CSS/padding
+ function unpackPadding(value) {
+ if (typeof(value) === "number")
+ value = [value];
+ if (value.length === 1) {
+ return {top: value[0], right: value[0], bottom: value[0], left: value[0]};
+ }
+ if (value.length === 2) {
+ return {top: value[0], right: value[1], bottom: value[0], left: value[1]};
+ }
+ if (value.length === 3) {
+ return {top: value[0], right: value[1], bottom: value[2], left: value[1]};
+ }
+ if (value.length === 4) {
+ return {top: value[0], right: value[1], bottom: value[2], left: value[3]};
+ }
+ }
+
+ // Convert an unpacked padding object to a CSS value
+ function paddingToCss(paddingObj) {
+ return paddingObj.top + "px " + paddingObj.right + "px " + paddingObj.bottom + "px " + paddingObj.left + "px";
+ }
+
+ // Makes a number suitable for CSS
+ function px(x) {
+ if (typeof(x) === "number")
+ return x + "px";
+ else
+ return x;
+ }
+
+ // Retrieves runtime widget sizing information for an element.
+ // The return value is either null, or an object with fill, padding,
+ // defaultWidth, defaultHeight fields.
+ function sizingPolicy(el) {
+ var sizingEl = document.querySelector("script[data-for='" + el.id + "'][type='application/htmlwidget-sizing']");
+ if (!sizingEl)
+ return null;
+ var sp = JSON.parse(sizingEl.textContent || sizingEl.text || "{}");
+ if (viewerMode) {
+ return sp.viewer;
+ } else {
+ return sp.browser;
+ }
+ }
+
+ // @param tasks Array of strings (or falsy value, in which case no-op).
+ // Each element must be a valid JavaScript expression that yields a
+ // function. Or, can be an array of objects with "code" and "data"
+ // properties; in this case, the "code" property should be a string
+ // of JS that's an expr that yields a function, and "data" should be
+ // an object that will be added as an additional argument when that
+ // function is called.
+ // @param target The object that will be "this" for each function
+ // execution.
+ // @param args Array of arguments to be passed to the functions. (The
+ // same arguments will be passed to all functions.)
+ function evalAndRun(tasks, target, args) {
+ if (tasks) {
+ forEach(tasks, function(task) {
+ var theseArgs = args;
+ if (typeof(task) === "object") {
+ theseArgs = theseArgs.concat([task.data]);
+ task = task.code;
+ }
+ var taskFunc = tryEval(task);
+ if (typeof(taskFunc) !== "function") {
+ throw new Error("Task must be a function! Source:\n" + task);
+ }
+ taskFunc.apply(target, theseArgs);
+ });
+ }
+ }
+
+ // Attempt eval() both with and without enclosing in parentheses.
+ // Note that enclosing coerces a function declaration into
+ // an expression that eval() can parse
+ // (otherwise, a SyntaxError is thrown)
+ function tryEval(code) {
+ var result = null;
+ try {
+ result = eval(code);
+ } catch(error) {
+ if (!error instanceof SyntaxError) {
+ throw error;
+ }
+ try {
+ result = eval("(" + code + ")");
+ } catch(e) {
+ if (e instanceof SyntaxError) {
+ throw error;
+ } else {
+ throw e;
+ }
+ }
+ }
+ return result;
+ }
+
+ function initSizing(el) {
+ var sizing = sizingPolicy(el);
+ if (!sizing)
+ return;
+
+ var cel = document.getElementById("htmlwidget_container");
+ if (!cel)
+ return;
+
+ if (typeof(sizing.padding) !== "undefined") {
+ document.body.style.margin = "0";
+ document.body.style.padding = paddingToCss(unpackPadding(sizing.padding));
+ }
+
+ if (sizing.fill) {
+ document.body.style.overflow = "hidden";
+ document.body.style.width = "100%";
+ document.body.style.height = "100%";
+ document.documentElement.style.width = "100%";
+ document.documentElement.style.height = "100%";
+ if (cel) {
+ cel.style.position = "absolute";
+ var pad = unpackPadding(sizing.padding);
+ cel.style.top = pad.top + "px";
+ cel.style.right = pad.right + "px";
+ cel.style.bottom = pad.bottom + "px";
+ cel.style.left = pad.left + "px";
+ el.style.width = "100%";
+ el.style.height = "100%";
+ }
+
+ return {
+ getWidth: function() { return cel.offsetWidth; },
+ getHeight: function() { return cel.offsetHeight; }
+ };
+
+ } else {
+ el.style.width = px(sizing.width);
+ el.style.height = px(sizing.height);
+
+ return {
+ getWidth: function() { return el.offsetWidth; },
+ getHeight: function() { return el.offsetHeight; }
+ };
+ }
+ }
+
+ // Default implementations for methods
+ var defaults = {
+ find: function(scope) {
+ return querySelectorAll(scope, "." + this.name);
+ },
+ renderError: function(el, err) {
+ var $el = $(el);
+
+ this.clearError(el);
+
+ // Add all these error classes, as Shiny does
+ var errClass = "shiny-output-error";
+ if (err.type !== null) {
+ // use the classes of the error condition as CSS class names
+ errClass = errClass + " " + $.map(asArray(err.type), function(type) {
+ return errClass + "-" + type;
+ }).join(" ");
+ }
+ errClass = errClass + " htmlwidgets-error";
+
+ // Is el inline or block? If inline or inline-block, just display:none it
+ // and add an inline error.
+ var display = $el.css("display");
+ $el.data("restore-display-mode", display);
+
+ if (display === "inline" || display === "inline-block") {
+ $el.hide();
+ if (err.message !== "") {
+ var errorSpan = $("").addClass(errClass);
+ errorSpan.text(err.message);
+ $el.after(errorSpan);
+ }
+ } else if (display === "block") {
+ // If block, add an error just after the el, set visibility:none on the
+ // el, and position the error to be on top of the el.
+ // Mark it with a unique ID and CSS class so we can remove it later.
+ $el.css("visibility", "hidden");
+ if (err.message !== "") {
+ var errorDiv = $("
").addClass(errClass).css("position", "absolute")
+ .css("top", el.offsetTop)
+ .css("left", el.offsetLeft)
+ // setting width can push out the page size, forcing otherwise
+ // unnecessary scrollbars to appear and making it impossible for
+ // the element to shrink; so use max-width instead
+ .css("maxWidth", el.offsetWidth)
+ .css("height", el.offsetHeight);
+ errorDiv.text(err.message);
+ $el.after(errorDiv);
+
+ // Really dumb way to keep the size/position of the error in sync with
+ // the parent element as the window is resized or whatever.
+ var intId = setInterval(function() {
+ if (!errorDiv[0].parentElement) {
+ clearInterval(intId);
+ return;
+ }
+ errorDiv
+ .css("top", el.offsetTop)
+ .css("left", el.offsetLeft)
+ .css("maxWidth", el.offsetWidth)
+ .css("height", el.offsetHeight);
+ }, 500);
+ }
+ }
+ },
+ clearError: function(el) {
+ var $el = $(el);
+ var display = $el.data("restore-display-mode");
+ $el.data("restore-display-mode", null);
+
+ if (display === "inline" || display === "inline-block") {
+ if (display)
+ $el.css("display", display);
+ $(el.nextSibling).filter(".htmlwidgets-error").remove();
+ } else if (display === "block"){
+ $el.css("visibility", "inherit");
+ $(el.nextSibling).filter(".htmlwidgets-error").remove();
+ }
+ },
+ sizing: {}
+ };
+
+ // Called by widget bindings to register a new type of widget. The definition
+ // object can contain the following properties:
+ // - name (required) - A string indicating the binding name, which will be
+ // used by default as the CSS classname to look for.
+ // - initialize (optional) - A function(el) that will be called once per
+ // widget element; if a value is returned, it will be passed as the third
+ // value to renderValue.
+ // - renderValue (required) - A function(el, data, initValue) that will be
+ // called with data. Static contexts will cause this to be called once per
+ // element; Shiny apps will cause this to be called multiple times per
+ // element, as the data changes.
+ window.HTMLWidgets.widget = function(definition) {
+ if (!definition.name) {
+ throw new Error("Widget must have a name");
+ }
+ if (!definition.type) {
+ throw new Error("Widget must have a type");
+ }
+ // Currently we only support output widgets
+ if (definition.type !== "output") {
+ throw new Error("Unrecognized widget type '" + definition.type + "'");
+ }
+ // TODO: Verify that .name is a valid CSS classname
+
+ // Support new-style instance-bound definitions. Old-style class-bound
+ // definitions have one widget "object" per widget per type/class of
+ // widget; the renderValue and resize methods on such widget objects
+ // take el and instance arguments, because the widget object can't
+ // store them. New-style instance-bound definitions have one widget
+ // object per widget instance; the definition that's passed in doesn't
+ // provide renderValue or resize methods at all, just the single method
+ // factory(el, width, height)
+ // which returns an object that has renderValue(x) and resize(w, h).
+ // This enables a far more natural programming style for the widget
+ // author, who can store per-instance state using either OO-style
+ // instance fields or functional-style closure variables (I guess this
+ // is in contrast to what can only be called C-style pseudo-OO which is
+ // what we required before).
+ if (definition.factory) {
+ definition = createLegacyDefinitionAdapter(definition);
+ }
+
+ if (!definition.renderValue) {
+ throw new Error("Widget must have a renderValue function");
+ }
+
+ // For static rendering (non-Shiny), use a simple widget registration
+ // scheme. We also use this scheme for Shiny apps/documents that also
+ // contain static widgets.
+ window.HTMLWidgets.widgets = window.HTMLWidgets.widgets || [];
+ // Merge defaults into the definition; don't mutate the original definition.
+ var staticBinding = extend({}, defaults, definition);
+ overrideMethod(staticBinding, "find", function(superfunc) {
+ return function(scope) {
+ var results = superfunc(scope);
+ // Filter out Shiny outputs, we only want the static kind
+ return filterByClass(results, "html-widget-output", false);
+ };
+ });
+ window.HTMLWidgets.widgets.push(staticBinding);
+
+ if (shinyMode) {
+ // Shiny is running. Register the definition with an output binding.
+ // The definition itself will not be the output binding, instead
+ // we will make an output binding object that delegates to the
+ // definition. This is because we foolishly used the same method
+ // name (renderValue) for htmlwidgets definition and Shiny bindings
+ // but they actually have quite different semantics (the Shiny
+ // bindings receive data that includes lots of metadata that it
+ // strips off before calling htmlwidgets renderValue). We can't
+ // just ignore the difference because in some widgets it's helpful
+ // to call this.renderValue() from inside of resize(), and if
+ // we're not delegating, then that call will go to the Shiny
+ // version instead of the htmlwidgets version.
+
+ // Merge defaults with definition, without mutating either.
+ var bindingDef = extend({}, defaults, definition);
+
+ // This object will be our actual Shiny binding.
+ var shinyBinding = new Shiny.OutputBinding();
+
+ // With a few exceptions, we'll want to simply use the bindingDef's
+ // version of methods if they are available, otherwise fall back to
+ // Shiny's defaults. NOTE: If Shiny's output bindings gain additional
+ // methods in the future, and we want them to be overrideable by
+ // HTMLWidget binding definitions, then we'll need to add them to this
+ // list.
+ delegateMethod(shinyBinding, bindingDef, "getId");
+ delegateMethod(shinyBinding, bindingDef, "onValueChange");
+ delegateMethod(shinyBinding, bindingDef, "onValueError");
+ delegateMethod(shinyBinding, bindingDef, "renderError");
+ delegateMethod(shinyBinding, bindingDef, "clearError");
+ delegateMethod(shinyBinding, bindingDef, "showProgress");
+
+ // The find, renderValue, and resize are handled differently, because we
+ // want to actually decorate the behavior of the bindingDef methods.
+
+ shinyBinding.find = function(scope) {
+ var results = bindingDef.find(scope);
+
+ // Only return elements that are Shiny outputs, not static ones
+ var dynamicResults = results.filter(".html-widget-output");
+
+ // It's possible that whatever caused Shiny to think there might be
+ // new dynamic outputs, also caused there to be new static outputs.
+ // Since there might be lots of different htmlwidgets bindings, we
+ // schedule execution for later--no need to staticRender multiple
+ // times.
+ if (results.length !== dynamicResults.length)
+ scheduleStaticRender();
+
+ return dynamicResults;
+ };
+
+ // Wrap renderValue to handle initialization, which unfortunately isn't
+ // supported natively by Shiny at the time of this writing.
+
+ shinyBinding.renderValue = function(el, data) {
+ Shiny.renderDependencies(data.deps);
+ // Resolve strings marked as javascript literals to objects
+ if (!(data.evals instanceof Array)) data.evals = [data.evals];
+ for (var i = 0; data.evals && i < data.evals.length; i++) {
+ window.HTMLWidgets.evaluateStringMember(data.x, data.evals[i]);
+ }
+ if (!bindingDef.renderOnNullValue) {
+ if (data.x === null) {
+ el.style.visibility = "hidden";
+ return;
+ } else {
+ el.style.visibility = "inherit";
+ }
+ }
+ if (!elementData(el, "initialized")) {
+ initSizing(el);
+
+ elementData(el, "initialized", true);
+ if (bindingDef.initialize) {
+ var result = bindingDef.initialize(el, el.offsetWidth,
+ el.offsetHeight);
+ elementData(el, "init_result", result);
+ }
+ }
+ bindingDef.renderValue(el, data.x, elementData(el, "init_result"));
+ evalAndRun(data.jsHooks.render, elementData(el, "init_result"), [el, data.x]);
+ };
+
+ // Only override resize if bindingDef implements it
+ if (bindingDef.resize) {
+ shinyBinding.resize = function(el, width, height) {
+ // Shiny can call resize before initialize/renderValue have been
+ // called, which doesn't make sense for widgets.
+ if (elementData(el, "initialized")) {
+ bindingDef.resize(el, width, height, elementData(el, "init_result"));
+ }
+ };
+ }
+
+ Shiny.outputBindings.register(shinyBinding, bindingDef.name);
+ }
+ };
+
+ var scheduleStaticRenderTimerId = null;
+ function scheduleStaticRender() {
+ if (!scheduleStaticRenderTimerId) {
+ scheduleStaticRenderTimerId = setTimeout(function() {
+ scheduleStaticRenderTimerId = null;
+ window.HTMLWidgets.staticRender();
+ }, 1);
+ }
+ }
+
+ // Render static widgets after the document finishes loading
+ // Statically render all elements that are of this widget's class
+ window.HTMLWidgets.staticRender = function() {
+ var bindings = window.HTMLWidgets.widgets || [];
+ forEach(bindings, function(binding) {
+ var matches = binding.find(document.documentElement);
+ forEach(matches, function(el) {
+ var sizeObj = initSizing(el, binding);
+
+ if (hasClass(el, "html-widget-static-bound"))
+ return;
+ el.className = el.className + " html-widget-static-bound";
+
+ var initResult;
+ if (binding.initialize) {
+ initResult = binding.initialize(el,
+ sizeObj ? sizeObj.getWidth() : el.offsetWidth,
+ sizeObj ? sizeObj.getHeight() : el.offsetHeight
+ );
+ elementData(el, "init_result", initResult);
+ }
+
+ if (binding.resize) {
+ var lastSize = {
+ w: sizeObj ? sizeObj.getWidth() : el.offsetWidth,
+ h: sizeObj ? sizeObj.getHeight() : el.offsetHeight
+ };
+ var resizeHandler = function(e) {
+ var size = {
+ w: sizeObj ? sizeObj.getWidth() : el.offsetWidth,
+ h: sizeObj ? sizeObj.getHeight() : el.offsetHeight
+ };
+ if (size.w === 0 && size.h === 0)
+ return;
+ if (size.w === lastSize.w && size.h === lastSize.h)
+ return;
+ lastSize = size;
+ binding.resize(el, size.w, size.h, initResult);
+ };
+
+ on(window, "resize", resizeHandler);
+
+ // This is needed for cases where we're running in a Shiny
+ // app, but the widget itself is not a Shiny output, but
+ // rather a simple static widget. One example of this is
+ // an rmarkdown document that has runtime:shiny and widget
+ // that isn't in a render function. Shiny only knows to
+ // call resize handlers for Shiny outputs, not for static
+ // widgets, so we do it ourselves.
+ if (window.jQuery) {
+ window.jQuery(document).on(
+ "shown.htmlwidgets shown.bs.tab.htmlwidgets shown.bs.collapse.htmlwidgets",
+ resizeHandler
+ );
+ window.jQuery(document).on(
+ "hidden.htmlwidgets hidden.bs.tab.htmlwidgets hidden.bs.collapse.htmlwidgets",
+ resizeHandler
+ );
+ }
+
+ // This is needed for the specific case of ioslides, which
+ // flips slides between display:none and display:block.
+ // Ideally we would not have to have ioslide-specific code
+ // here, but rather have ioslides raise a generic event,
+ // but the rmarkdown package just went to CRAN so the
+ // window to getting that fixed may be long.
+ if (window.addEventListener) {
+ // It's OK to limit this to window.addEventListener
+ // browsers because ioslides itself only supports
+ // such browsers.
+ on(document, "slideenter", resizeHandler);
+ on(document, "slideleave", resizeHandler);
+ }
+ }
+
+ var scriptData = document.querySelector("script[data-for='" + el.id + "'][type='application/json']");
+ if (scriptData) {
+ var data = JSON.parse(scriptData.textContent || scriptData.text);
+ // Resolve strings marked as javascript literals to objects
+ if (!(data.evals instanceof Array)) data.evals = [data.evals];
+ for (var k = 0; data.evals && k < data.evals.length; k++) {
+ window.HTMLWidgets.evaluateStringMember(data.x, data.evals[k]);
+ }
+ binding.renderValue(el, data.x, initResult);
+ evalAndRun(data.jsHooks.render, initResult, [el, data.x]);
+ }
+ });
+ });
+
+ invokePostRenderHandlers();
+ }
+
+
+ function has_jQuery3() {
+ if (!window.jQuery) {
+ return false;
+ }
+ var $version = window.jQuery.fn.jquery;
+ var $major_version = parseInt($version.split(".")[0]);
+ return $major_version >= 3;
+ }
+
+ /*
+ / Shiny 1.4 bumped jQuery from 1.x to 3.x which means jQuery's
+ / on-ready handler (i.e., $(fn)) is now asyncronous (i.e., it now
+ / really means $(setTimeout(fn)).
+ / https://jquery.com/upgrade-guide/3.0/#breaking-change-document-ready-handlers-are-now-asynchronous
+ /
+ / Since Shiny uses $() to schedule initShiny, shiny>=1.4 calls initShiny
+ / one tick later than it did before, which means staticRender() is
+ / called renderValue() earlier than (advanced) widget authors might be expecting.
+ / https://github.com/rstudio/shiny/issues/2630
+ /
+ / For a concrete example, leaflet has some methods (e.g., updateBounds)
+ / which reference Shiny methods registered in initShiny (e.g., setInputValue).
+ / Since leaflet is privy to this life-cycle, it knows to use setTimeout() to
+ / delay execution of those methods (until Shiny methods are ready)
+ / https://github.com/rstudio/leaflet/blob/18ec981/javascript/src/index.js#L266-L268
+ /
+ / Ideally widget authors wouldn't need to use this setTimeout() hack that
+ / leaflet uses to call Shiny methods on a staticRender(). In the long run,
+ / the logic initShiny should be broken up so that method registration happens
+ / right away, but binding happens later.
+ */
+ function maybeStaticRenderLater() {
+ if (shinyMode && has_jQuery3()) {
+ window.jQuery(window.HTMLWidgets.staticRender);
+ } else {
+ window.HTMLWidgets.staticRender();
+ }
+ }
+
+ if (document.addEventListener) {
+ document.addEventListener("DOMContentLoaded", function() {
+ document.removeEventListener("DOMContentLoaded", arguments.callee, false);
+ maybeStaticRenderLater();
+ }, false);
+ } else if (document.attachEvent) {
+ document.attachEvent("onreadystatechange", function() {
+ if (document.readyState === "complete") {
+ document.detachEvent("onreadystatechange", arguments.callee);
+ maybeStaticRenderLater();
+ }
+ });
+ }
+
+
+ window.HTMLWidgets.getAttachmentUrl = function(depname, key) {
+ // If no key, default to the first item
+ if (typeof(key) === "undefined")
+ key = 1;
+
+ var link = document.getElementById(depname + "-" + key + "-attachment");
+ if (!link) {
+ throw new Error("Attachment " + depname + "/" + key + " not found in document");
+ }
+ return link.getAttribute("href");
+ };
+
+ window.HTMLWidgets.dataframeToD3 = function(df) {
+ var names = [];
+ var length;
+ for (var name in df) {
+ if (df.hasOwnProperty(name))
+ names.push(name);
+ if (typeof(df[name]) !== "object" || typeof(df[name].length) === "undefined") {
+ throw new Error("All fields must be arrays");
+ } else if (typeof(length) !== "undefined" && length !== df[name].length) {
+ throw new Error("All fields must be arrays of the same length");
+ }
+ length = df[name].length;
+ }
+ var results = [];
+ var item;
+ for (var row = 0; row < length; row++) {
+ item = {};
+ for (var col = 0; col < names.length; col++) {
+ item[names[col]] = df[names[col]][row];
+ }
+ results.push(item);
+ }
+ return results;
+ };
+
+ window.HTMLWidgets.transposeArray2D = function(array) {
+ if (array.length === 0) return array;
+ var newArray = array[0].map(function(col, i) {
+ return array.map(function(row) {
+ return row[i]
+ })
+ });
+ return newArray;
+ };
+ // Split value at splitChar, but allow splitChar to be escaped
+ // using escapeChar. Any other characters escaped by escapeChar
+ // will be included as usual (including escapeChar itself).
+ function splitWithEscape(value, splitChar, escapeChar) {
+ var results = [];
+ var escapeMode = false;
+ var currentResult = "";
+ for (var pos = 0; pos < value.length; pos++) {
+ if (!escapeMode) {
+ if (value[pos] === splitChar) {
+ results.push(currentResult);
+ currentResult = "";
+ } else if (value[pos] === escapeChar) {
+ escapeMode = true;
+ } else {
+ currentResult += value[pos];
+ }
+ } else {
+ currentResult += value[pos];
+ escapeMode = false;
+ }
+ }
+ if (currentResult !== "") {
+ results.push(currentResult);
+ }
+ return results;
+ }
+ // Function authored by Yihui/JJ Allaire
+ window.HTMLWidgets.evaluateStringMember = function(o, member) {
+ var parts = splitWithEscape(member, '.', '\\');
+ for (var i = 0, l = parts.length; i < l; i++) {
+ var part = parts[i];
+ // part may be a character or 'numeric' member name
+ if (o !== null && typeof o === "object" && part in o) {
+ if (i == (l - 1)) { // if we are at the end of the line then evalulate
+ if (typeof o[part] === "string")
+ o[part] = tryEval(o[part]);
+ } else { // otherwise continue to next embedded object
+ o = o[part];
+ }
+ }
+ }
+ };
+
+ // Retrieve the HTMLWidget instance (i.e. the return value of an
+ // HTMLWidget binding's initialize() or factory() function)
+ // associated with an element, or null if none.
+ window.HTMLWidgets.getInstance = function(el) {
+ return elementData(el, "init_result");
+ };
+
+ // Finds the first element in the scope that matches the selector,
+ // and returns the HTMLWidget instance (i.e. the return value of
+ // an HTMLWidget binding's initialize() or factory() function)
+ // associated with that element, if any. If no element matches the
+ // selector, or the first matching element has no HTMLWidget
+ // instance associated with it, then null is returned.
+ //
+ // The scope argument is optional, and defaults to window.document.
+ window.HTMLWidgets.find = function(scope, selector) {
+ if (arguments.length == 1) {
+ selector = scope;
+ scope = document;
+ }
+
+ var el = scope.querySelector(selector);
+ if (el === null) {
+ return null;
+ } else {
+ return window.HTMLWidgets.getInstance(el);
+ }
+ };
+
+ // Finds all elements in the scope that match the selector, and
+ // returns the HTMLWidget instances (i.e. the return values of
+ // an HTMLWidget binding's initialize() or factory() function)
+ // associated with the elements, in an array. If elements that
+ // match the selector don't have an associated HTMLWidget
+ // instance, the returned array will contain nulls.
+ //
+ // The scope argument is optional, and defaults to window.document.
+ window.HTMLWidgets.findAll = function(scope, selector) {
+ if (arguments.length == 1) {
+ selector = scope;
+ scope = document;
+ }
+
+ var nodes = scope.querySelectorAll(selector);
+ var results = [];
+ for (var i = 0; i < nodes.length; i++) {
+ results.push(window.HTMLWidgets.getInstance(nodes[i]));
+ }
+ return results;
+ };
+
+ var postRenderHandlers = [];
+ function invokePostRenderHandlers() {
+ while (postRenderHandlers.length) {
+ var handler = postRenderHandlers.shift();
+ if (handler) {
+ handler();
+ }
+ }
+ }
+
+ // Register the given callback function to be invoked after the
+ // next time static widgets are rendered.
+ window.HTMLWidgets.addPostRenderHandler = function(callback) {
+ postRenderHandlers.push(callback);
+ };
+
+ // Takes a new-style instance-bound definition, and returns an
+ // old-style class-bound definition. This saves us from having
+ // to rewrite all the logic in this file to accomodate both
+ // types of definitions.
+ function createLegacyDefinitionAdapter(defn) {
+ var result = {
+ name: defn.name,
+ type: defn.type,
+ initialize: function(el, width, height) {
+ return defn.factory(el, width, height);
+ },
+ renderValue: function(el, x, instance) {
+ return instance.renderValue(x);
+ },
+ resize: function(el, width, height, instance) {
+ return instance.resize(width, height);
+ }
+ };
+
+ if (defn.find)
+ result.find = defn.find;
+ if (defn.renderError)
+ result.renderError = defn.renderError;
+ if (defn.clearError)
+ result.clearError = defn.clearError;
+
+ return result;
+ }
+})();
+
diff --git a/docs/articles/result_comparison.html b/docs/articles/result_comparison.html
new file mode 100644
index 00000000..a8ff133f
--- /dev/null
+++ b/docs/articles/result_comparison.html
@@ -0,0 +1,136 @@
+
+
+
+
+
+
+
+Comparison of outputs • HaDeX
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
The aggregation of the data is complex. This article describes the process step by step for a better understanding of the data transformation.
+
+
+Aggregation of the data - visualization
+
Let’s see how the data is transformed. We will use the example file “KD_180110_CD160_HVEM.csv” from the HaDeX package and focus on just one peptide - “LCKDRSGDCSPETSLKQLRLKRDPGIDGVGEISSQL” in the state “CD160”. The measurement was made for timepoint 1 min.
+
Below is shown the original and unaggregated data for chosen peptide.
+
## Protein Start End Sequence Modification
+## 1: db_CD160 34 69 LCKDRSGDCSPETSLKQLRLKRDPGIDGVGEISSQL NA
+## 2: db_CD160 34 69 LCKDRSGDCSPETSLKQLRLKRDPGIDGVGEISSQL NA
+## 3: db_CD160 34 69 LCKDRSGDCSPETSLKQLRLKRDPGIDGVGEISSQL NA
+## 4: db_CD160 34 69 LCKDRSGDCSPETSLKQLRLKRDPGIDGVGEISSQL NA
+## 5: db_CD160 34 69 LCKDRSGDCSPETSLKQLRLKRDPGIDGVGEISSQL NA
+## 6: db_CD160 34 69 LCKDRSGDCSPETSLKQLRLKRDPGIDGVGEISSQL NA
+## 7: db_CD160 34 69 LCKDRSGDCSPETSLKQLRLKRDPGIDGVGEISSQL NA
+## 8: db_CD160 34 69 LCKDRSGDCSPETSLKQLRLKRDPGIDGVGEISSQL NA
+## 9: db_CD160 34 69 LCKDRSGDCSPETSLKQLRLKRDPGIDGVGEISSQL NA
+## 10: db_CD160 34 69 LCKDRSGDCSPETSLKQLRLKRDPGIDGVGEISSQL NA
+## 11: db_CD160 34 69 LCKDRSGDCSPETSLKQLRLKRDPGIDGVGEISSQL NA
+## 12: db_CD160 34 69 LCKDRSGDCSPETSLKQLRLKRDPGIDGVGEISSQL NA
+## 13: db_CD160 34 69 LCKDRSGDCSPETSLKQLRLKRDPGIDGVGEISSQL NA
+## 14: db_CD160 34 69 LCKDRSGDCSPETSLKQLRLKRDPGIDGVGEISSQL NA
+## 15: db_CD160 34 69 LCKDRSGDCSPETSLKQLRLKRDPGIDGVGEISSQL NA
+## 16: db_CD160 34 69 LCKDRSGDCSPETSLKQLRLKRDPGIDGVGEISSQL NA
+## 17: db_CD160 34 69 LCKDRSGDCSPETSLKQLRLKRDPGIDGVGEISSQL NA
+## 18: db_CD160 34 69 LCKDRSGDCSPETSLKQLRLKRDPGIDGVGEISSQL NA
+## 19: db_CD160 34 69 LCKDRSGDCSPETSLKQLRLKRDPGIDGVGEISSQL NA
+## 20: db_CD160 34 69 LCKDRSGDCSPETSLKQLRLKRDPGIDGVGEISSQL NA
+## Fragment MaxUptake MHP State Exposure File z
+## 1: NA 33 3900.991 CD160 1 KD_160530_CD160_1min_01 3
+## 2: NA 33 3900.991 CD160 1 KD_160530_CD160_1min_01 4
+## 3: NA 33 3900.991 CD160 1 KD_160530_CD160_1min_01 5
+## 4: NA 33 3900.991 CD160 1 KD_160530_CD160_1min_01 6
+## 5: NA 33 3900.991 CD160 1 KD_160530_CD160_1min_01 7
+## 6: NA 33 3900.991 CD160 1 KD_160530_CD160_1min_02 3
+## 7: NA 33 3900.991 CD160 1 KD_160530_CD160_1min_02 4
+## 8: NA 33 3900.991 CD160 1 KD_160530_CD160_1min_02 5
+## 9: NA 33 3900.991 CD160 1 KD_160530_CD160_1min_02 6
+## 10: NA 33 3900.991 CD160 1 KD_160530_CD160_1min_02 7
+## 11: NA 33 3900.991 CD160 1 KD_160530_CD160_1min_03 3
+## 12: NA 33 3900.991 CD160 1 KD_160530_CD160_1min_03 4
+## 13: NA 33 3900.991 CD160 1 KD_160530_CD160_1min_03 5
+## 14: NA 33 3900.991 CD160 1 KD_160530_CD160_1min_03 6
+## 15: NA 33 3900.991 CD160 1 KD_160530_CD160_1min_03 7
+## 16: NA 33 3900.991 CD160 1 KD_160530_CD160_1min_04 3
+## 17: NA 33 3900.991 CD160 1 KD_160530_CD160_1min_04 4
+## 18: NA 33 3900.991 CD160 1 KD_160530_CD160_1min_04 5
+## 19: NA 33 3900.991 CD160 1 KD_160530_CD160_1min_04 6
+## 20: NA 33 3900.991 CD160 1 KD_160530_CD160_1min_04 7
+## RT Inten Center
+## 1: 4.524763 325032 1307.8329
+## 2: 4.524404 753259 981.0960
+## 3: 4.523707 1340447 785.0905
+## 4: 4.524032 2076956 654.3858
+## 5: 4.525778 759271 561.0548
+## 6: 4.522330 239810 1307.7777
+## 7: 4.521255 583325 981.0817
+## 8: 4.521919 1011160 785.0811
+## 9: 4.521726 1584254 654.4194
+## 10: 4.522196 600218 561.0268
+## 11: 4.523605 176788 1307.8942
+## 12: 4.524804 402630 981.1597
+## 13: 4.521938 746309 785.0906
+## 14: 4.522238 1117344 654.4344
+## 15: 4.524647 397718 561.0833
+## 16: 4.531138 189258 1307.8739
+## 17: 4.530608 441817 981.1656
+## 18: 4.528928 796722 785.1220
+## 19: 4.530066 1186263 654.4411
+## 20: 4.531333 451071 561.0588
+
As we can see from the File column, there are four replicates of the experiment. Each measurement of a replicate provide values for different possible charge values for each peptide. The result of a measurement is in column Center - this is a geometrical centroid of an isotopic envelope - the product of the measurement from a mass spectrometer.
+
Let’s take a look for values for each replicate.
+
+
The centroid values for different charge values are not useful. We have to transform it to the mass values, according to an equation:
+
\[ aggMass = z*(Center - protonMass)\] The results are shown below.
+
+
This results are just for one repetition. We have four of them:
+
+
Values from each replicate are aggregated into one value, using weighted mean (with intencity value as weight):
+
+
The results from replicates are aggregated into the final result (mean), and the uncertainty (standard deviation of the mean) is calculated.
+
+
Now we have the mass value for chosen peptide in the chosen state, measured in the chosen time point. This calculation is done for every other peptide, and these values of mass and uncertainty are used in the calculation of deuterium uptake, as described in the Data processing article.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/articles/transformation_files/figure-html/unnamed-chunk-3-1.png b/docs/articles/transformation_files/figure-html/unnamed-chunk-3-1.png
new file mode 100644
index 00000000..e10b1f51
Binary files /dev/null and b/docs/articles/transformation_files/figure-html/unnamed-chunk-3-1.png differ
diff --git a/docs/articles/transformation_files/figure-html/unnamed-chunk-4-1.png b/docs/articles/transformation_files/figure-html/unnamed-chunk-4-1.png
new file mode 100644
index 00000000..2da1046f
Binary files /dev/null and b/docs/articles/transformation_files/figure-html/unnamed-chunk-4-1.png differ
diff --git a/docs/articles/transformation_files/figure-html/unnamed-chunk-5-1.png b/docs/articles/transformation_files/figure-html/unnamed-chunk-5-1.png
new file mode 100644
index 00000000..e9bb02d7
Binary files /dev/null and b/docs/articles/transformation_files/figure-html/unnamed-chunk-5-1.png differ
diff --git a/docs/articles/transformation_files/figure-html/unnamed-chunk-6-1.png b/docs/articles/transformation_files/figure-html/unnamed-chunk-6-1.png
new file mode 100644
index 00000000..fefe4261
Binary files /dev/null and b/docs/articles/transformation_files/figure-html/unnamed-chunk-6-1.png differ
diff --git a/docs/articles/transformation_files/figure-html/unnamed-chunk-7-1.png b/docs/articles/transformation_files/figure-html/unnamed-chunk-7-1.png
new file mode 100644
index 00000000..6847d8c7
Binary files /dev/null and b/docs/articles/transformation_files/figure-html/unnamed-chunk-7-1.png differ
diff --git a/docs/authors.html b/docs/authors.html
index daa6acb2..277eda33 100644
--- a/docs/authors.html
+++ b/docs/authors.html
@@ -15,21 +15,29 @@
+
-
+
-
-
+
+
+
+
+
+
+
-
+
+
-
+
-
-
+
+
+
@@ -37,10 +45,12 @@
+
+
@@ -51,9 +61,10 @@
+
-
+
Puchala W, Burdukiewicz M, Kistowski M, Dabrowska KA, Badaczewska-Dawid AE, Cysewski D and Dadlez M (2019). HaDeX: Analysis and Visualisation of Hydrogen/Deuterium Exchange Mass Spectrometry Data. R package version 1.0.
+
Puchala W, Burdukiewicz M, Kistowski M, Dabrowska KA, Badaczewska-Dawid AE, Cysewski D and Dadlez M (2020). HaDeX: Analysis and Visualisation of Hydrogen/Deuterium Exchange Mass Spectrometry Data. Bioinformatics, 10.1093/bioinformatics/btaa587.
logical value to determine if values are relative or absolute.
-
+
Value
calc_dat extended by column specifying if given peptide is relevant in given confidence limit.
The value of the confidence limit is added as an attribute - as well as parameters used to calculate (theoretical/relative)
assert_start_end
+This function asserts values of parameters. Start (of the sequence) should be
+bigger than 0 and smaller than end of the sequence. The end of the sequence
+should be bigger than start.
Calculate the mass of the singly charged monoisotopic (or not)
+molecular ion of for given peptide.
+
+
+
calculate_MHP(Sequence, mono =FALSE)
+
+
Arguments
+
+
+
+
Sequence
+
sequence of the peptide (string) or vector of sequences. Each letter
+of the sequence of the peptide represents different amino acid (three letter
+representation not allowed)
+
+
+
mono
+
logical value to determine if the mass should be monoisotopic or not.
+FALSE by default
+
+
+
+
Value
+
+
vector of numeric MHP values of provided Sequences
+
Details
+
+
This function calculates the mass of the singly charged monoisotopic (or not)
+molecular ion for given peptide. It is the sum of the residue masses plus the masses
+of the terminationg group (H and OH). The source of the masses can be found here:
+http://www.matrixscience.com/help/aa_help.html.
logical value to determine if values are relative or absolute.
-
+
Value
range of confidence limit interval
-
Details
...
-
References
Houde, D., Berkowitz, S.A., and Engen, J.R. (2011).
The Utility of Hydrogen/Deuterium Exchange Mass Spectrometry in
Biopharmaceutical Comparability Studies. J Pharm Sci 100, 2071–2086.
percentage of deuterium the protein was exposed to, value in range [0, 1]
-
+
Value
data frame with deuteration calculated for all the data points
@@ -178,7 +203,6 @@
Value
is available in column `time_chosen`. The rest of
the returned structure is equivalent to structure returned by
calculate_state_deuteration.
-
Details
The function calculates deuteration data for all available data points
@@ -188,112 +212,107 @@
Details
to during the exchange in theoretical calculations is provided.
To visualize obtained data we recommend using plot_kinetics function.
The first version doesn't support filled Modification and Fragment columns.
-
The function calculate_state_deuteration calculates deuteration for peptides in given protein in given state based
@@ -171,67 +193,60 @@
Details
supplied (mean values and uncertainty). Manual correction of percentage of deuterium the protein was exposed to during the exchange
in theoretical calculations is provided.
Methods of calculation and uncertainty are profoundly discussed in the vignette.
# load example data
-dat<-read_hdx(system.file(package="HaDeX", "HaDeX/data/KD_180110_CD160_HVEM.csv"))
+dat<-read_hdx(system.file(package ="HaDeX", "HaDeX/data/KD_180110_CD160_HVEM.csv"))# calculate deuteration for state "CD160"
-calculate_state_deuteration(dat, protein="db_CD160", state="CD160",
- time_in=0, time_chosen=5.000, time_out=1440.000)
#> # A tibble: 41 x 14
-#> Protein Sequence Start End State frac_exch_state err_frac_exch_s…
+calculate_state_deuteration(dat, protein ="db_CD160", state ="CD160",
+ time_in =0, time_chosen =5.000, time_out =1440.000)
+
Generate the data frame with differential data from two
+provided states - experimental/fractional calculations with the
+uncertainty, based on supplied parameters.
vector of two states to calculate difference between them,
+the order is important (state first - state second)
+
+
+
protein
+
...
+
+
+
time_0
+
...
+
+
+
time_t
+
...
+
+
+
time_100
+
...
+
+
+
deut_part
+
...
+
+
+
+
Value
+
+
...
+
Details
+
+
The names of the parameters and variables will be changed
+later after the glossary project.
+
See also
+
+
...
+
+
Examples
+
# load example data
+dat<-read_hdx(system.file(package ="HaDeX", "HaDeX/data/KD_180110_CD160_HVEM.csv"))
+
+# calculate differential values between states "CD160" and "CD160_HVEM" for protein "db_CD160"
+generate_differential_data_set(dat =dat, states =c("CD160", "CD160_HVEM"), protein ="db_CD160",
+ time_0 =0.001, time_t =5.000, time_100 =1440.000)
+
This is a wrapper for calculate_kinetics, but for
+the peptide list instead of one peptide. The names of the parameters and
+variables will be changed later after the glossary project.
The format in the table is suggested in Masson, G.R., Burke, J.E.,
+Ahn, N.G., Anand, G.S., Borchers, C., Brier, S., Bou-Assaf, G.M., Engen, J.R.,
+Englander, S.W., Faber, J., et al. (2019). Recommendations for performing,
+interpreting and reporting hydrogen deuterium exchange mass spectrometry
+(HDX-MS) experiments. Nat Methods 16, 595–602
The function plot_coverage plots sequence coverage based on experimental data for chosen protein in chosen state.
Only non-duplicated peptides are shown on the plot, next to each other.
The aim of this plot is to see the dependence between positions of the peptides on the protein sequence. Their position in y-axis
does not contain any information.
This function visualises the output of the
@@ -158,101 +173,97 @@
Details
If you want to plot data for more then one peptide in one state, join
calculated data by using bind_rows from dplyr package and
pass the result as kin_dat.
# load example data
-dat<-read_hdx(system.file(package="HaDeX", "HaDeX/data/KD_180110_CD160_HVEM.csv"))
+dat<-read_hdx(system.file(package ="HaDeX", "HaDeX/data/KD_180110_CD160_HVEM.csv"))# calculate data for the sequence INITSSASQEGTRLN in the CD160 state
-(kin1<-calculate_kinetics(dat,
- protein="db_CD160",
- sequence="INITSSASQEGTRLN",
- state="CD160",
- start=1,
- end=15,
- time_in=0.001,
- time_out=1440))
#> # A tibble: 5 x 15
+(kin1<-calculate_kinetics(dat,
+ protein ="db_CD160",
+ sequence ="INITSSASQEGTRLN",
+ state ="CD160",
+ start =1,
+ end =15,
+ time_in =0.001,
+ time_out =1440))
+
# calculate data for the sequence INITSSASQEGTRLN in the CD160_HVEM state
-(kin2<-calculate_kinetics(dat,
- protein="db_CD160",
- sequence="INITSSASQEGTRLN",
- state="CD160_HVEM",
- start=1,
- end=15,
- time_in=0.001,
- time_out=1440))
#> # A tibble: 5 x 15
+(kin2<-calculate_kinetics(dat,
+ protein ="db_CD160",
+ sequence ="INITSSASQEGTRLN",
+ state ="CD160_HVEM",
+ start =1,
+ end =15,
+ time_in =0.001,
+ time_out =1440))
+
The function plot_position_frequency plots a histogram of the coverage frequency based on experimental data.
The aim of this plot is to see how many times each position of the sequence was covered (by different peptides).
# load example data
-dat<-read_hdx(system.file(package="HaDeX",
- "HaDeX/data/KD_180110_CD160_HVEM.csv"))
-
+dat<-read_hdx(system.file(package ="HaDeX",
+ "HaDeX/data/KD_180110_CD160_HVEM.csv"))
+
# function call with default parameters
-plot_position_frequency(dat)
+plot_position_frequency(dat)
+
# function call with explicit parameters
-plot_position_frequency(dat, chosen_state="CD160_HVEM")
# load example data
-dat<-read_hdx(system.file(package="HaDeX", "HaDeX/data/KD_180110_CD160_HVEM.csv"))
+dat<-read_hdx(system.file(package ="HaDeX", "HaDeX/data/KD_180110_CD160_HVEM.csv"))# prepare dataset for states `CD160` and `CD160_HVEM` in given time parameters
-prepare_dataset(dat,
- in_state_first="CD160_0.001",
- chosen_state_first="CD160_1",
- out_state_first="CD160_1440",
- in_state_second="CD160_HVEM_0.001",
- chosen_state_second="CD160_HVEM_1",
- out_state_second="CD160_HVEM_1440")
data.frame with mean uncertainty per different `out_time` value
-
Details
The function calculates mean uncertainty of all peptides and its uncertainty (standard error) based on given `in_time` and `chosen_time`
@@ -162,22 +177,21 @@
Details
experimental calculations depends on `out_time` variable. The results are either in form of relative or absolute values depending on the `relative`
parameter supplied by the user.
This data can be useful for general overview of the experiment and analyse of the chosen time parameters.
-
First version accepts files produced by DynamX 3.0 and 2.0 in `cluster data` format.
The function checks if all necessary columns are provided in correct format. The file must
include at least two repetitions of the measurement for the uncertainty to be calculated.
reconstruct_sequence(dat, protein =dat[["Protein"]][1])
+
Arguments
@@ -138,56 +154,48 @@
Arg
the protein of which the structure is to be reconstructed
-
+
Value
reconstructed sequence - character object.
-
Details
The function reconstructs protein sequence from supplied experimental data. If a position is not covered, x is shown.
First version doesn't support manual sequence length correction.
time point (in minutes) for fully deuterated sample. Numeric value, bigger than other
+time points in the file. Obligatory
+
+
+
old_protein_name
+
protein name to be changed. String or string vector (if the file contains
+data from multiple proteins). Not obligatory
+
+
+
new_protein_name
+
new names for old_protein_name. String or string vector (if the file contains
+data from multiple proteins). Not obligatory
+
+
+
old_state_name
+
state names to be changed. String or string vector (if the file contains
+data from multiple states). Not obligatory
+
+
+
new_state_name
+
new names for old_state_name. String or string vector (if the file contains
+data from multiple states). Not obligatory
+
+
+
confidence
+
vector of accepted confidence values (internal flag from HDeXaminer). By default only
+accepted values are `Medium` and `High`, with `Low` excluded. The user can control that by specifying
+this parameter
+
+
+
+
Value
+
+
dat - a data.frame with validated and updated content.
+
Details
+
+
Data from HDeXaminer is condensed and automated data retrieving may be corrected by the user.
+The original file has a mark "FD" for fully deuterated data instead of numerical value for time point
+(provided in minutes) that is not consistent for workflow and not enough for precise data description.
+Moreover, the data about both protein and state is included in one column and for detailed information
+function update_hdexaminer_file allows to change them.
This is the first version - multi-state calculations are not supported.
-
References
Woods, V.L., and Hamuro, Y. (2001). High resolution,
high-throughput amide deuterium exchange-mass spectrometry (DXMS)
determination of protein binding site structure and dynamics: utility
in pharmaceutical design. J. Cell. Biochem. Suppl. Suppl 37, 89–98.
## Warning: pakiet 'ggplot2' został zbudowany w wersji R 4.0.3
+
## Warning: pakiet 'DT' został zbudowany w wersji R 4.0.3
+
+
1 About HaDeX
+
HaDeX is a novel tool for processing, analysis, and visualization of HDX-MS experiments. HaDeX covers the final parts of the analytic process, including a comparison of experiments, quality control and generation of publication-quality figures. To make the HaDeX R package available to the less R-fluent users, we enhanced it with a comprehensive Graphical User Interface available as a HaDeX GUI. The reproducibility of the whole procedure is ensured with advanced reporting functions.
This document covers the main functionalities of both the R package and the GUI.
+
+
1.1 Comparison of the existing HDX-MS software
+
To show the novelty of HaDeX, we compare its functionalities with other relatively new software for analysis of HDX-MS data: MEMHDX (Hourdel et al. 2016) and Deuteros (Lau et al. 2019).
+
+
+
We have not considered HDX Workbench (Pascal et al. 2012) as it deals with the preliminary steps of the analysis. This comparison also does not cover a versatile structural visualisation tool for HDX-MS results, HDX-Viewer (Bouyssié et al. 2019) as its scope is different from the tools mentioned above.
+
Web server: a software is available as a web server.
+
Programmatic access: analytic functionalities are documented and available from a command line.
+
Desktop software: a software can be installed locally.
+
Multi-state analysis: a software supports comparisons of more than two states.
+
ISO-based uncertainty: analytic functions produce ISO-compatible uncertainty intervals.
+
Coverage and peptide overlap: overview of experimental sequence coverage is available in a user-friendly way.
+
Quality control: additional information about course of the experiment.
+
N- and C-terminal length corrections: manual correction of sequence length.
+
Global visualization of deuterium uptake: deuterium uptake for different states is shown together for comparison.
+
Woods plot: deuteration difference between chosen states shown in the format of Woods plot.
+
Zooming of the Woods plot: Woods plot can be zoomed in.
+
Customizable label names and colors: Labels and colors on the plot can be changed by the user.
+
Peptide kinetics chart: Kinetics plot (deuteration change in time) are available for each peptide.
+
3D structure visualization: structure of the protein is visualized in 3D.
+
Downloadable charts: charts are downloadable, preferably in a vector format (.eps, .svg or .pdf).
+
Deuterium uptake download: data shown on Woods plot is downloadable (e.q. as CSV file).
+
Downloadable results of intermediate computations: results of intermediate computations (e.q. pure deuteration data) are downloadable.
+
Report generation: generates a report (e.q. in Html format) with results of the analysis with parametrization.
HDX Data Summary: summary of the experimental data (Masson et al. 2019).
+
+
+
+
2 HaDeX functionalities
+
+
2.1 Data import
+
The HaDeX web server works only on data in the DynamX datafile format (Waters Corp.). The data from other sources may be also adjusted to the format accepted by HaDeX provided it has following columns:
+
+
+
Although data can be imported into R using other tools, we strongly advise to rely on the read_hdx() function:
+
dat <-read_hdx(system.file(package ="HaDeX",
+"HaDeX/data/KD_190304_Nucb2_EDTA_CaCl2_test02_clusterdata.csv"))
+
Currently, read_hdx() supports .csv, .tsv and .xls files fulfilling the data structure described above. Files with data from multiple proteins are supported. The user need to indicate which protein is of interest for calculations.
+
+
+
2.2 Computation of deuteration levels
+
The computation of the level of deuteration involves several pre-processing steps, all of which are described in this section. These steps are performed automatically in the GUI or by the prepare_dataset() function in the console.
+
+
2.2.1 Measured data into overall peptide mass
+
The results of HDX-MS measurements as given in the DynamX data files are represented as the measured mass of peptides plus proton mass to charge ratio (\(Center\)). For later use, this value has to be transformed into an overall mass of a peptide measured after specific time point from a protein in a specific state, as shown in equation 1:
+
\[pepMass = z \times (Center-protonMass)\tag{1}\] where:
+
+
\(pepMass\) - expected mass of the peptide after incubation (Da),
+
\(protonMass\) - the mass of the proton (Da),
+
\(z\) - charge of the peptide,
+
\(Center\) - experimentally measured peptide mass plus proton mass to charge ratio \(\left(\frac{m}{z}\right)\).
+
+
HDX-MS experiments are often repeated (by the rule of thumb at least three times). Thus, we aggregate the results of replicates as a weighted mean mass into a single result per peptide using equation 2:
\(aggMass\) - weighted mean mass of the peptide (Da),
+
\(k\) - replicate index,
+
\(Inten\) - intensity,
+
\(N\) - number of replicates.
+
+
This data manipulation results from an original data structure. Each repetition of the measurement gives the data for given peptide in a given time per possible value of \(z\) as shown in the example below. We need to use the value of \(pepMass\) as shown in equation 1 but still keep the information about original measurement - that’s why we use the weighted mass.
The uncertainty of a measurement is variability associated with the precision of measuring instrumentation. We present here a novel derivation of uncertainty formulas for HDX-MS data according to the ISO guidelines (Joint Committee for Guides in Metrology 2008). Input files always encompass results of more than one measurement. We assume uncorrelatedness of replicates as they come from different samples. Therefore, we average measurements of replicates for each time point and for all protein states. Thus, we compute peptide mass uncertainty \(u\) as uncertainty for aggregate estimate using the formula for standard deviation of the mean:
After obtaining the mass of the peptide, we can compute the deuteration level depending on the chosen maximum deuteration level. The maximum deuteration can also be computed in two different ways: either as theoretical (where the maximum deuteration depends on the theoretical deuteration levels) and experimental (where the maximum deuteration is assumed to be equal to the deuteration measured at the last time point).
+
+
+
2.2.2 Experimental deuteration level
+
The experimental deuteration level is computed as the deuteration level of the peptide from a protein in a specific state and after incubation time \(t\) compared to the deuteration level measured at the start of the incubation (\(t_0\)). It yields a value for the chosen state and chosen time \(t\).
+
\[D = D_{t} - D_{t_0}\tag{4}\]
+
where:
+
+
\(D\) - deuteration level (Da),
+
\(D_{t_0}\) - experimentally measured deuteration at the beginning of the incubation (0 or close to 0),
+
+
The equation 4 produces only absolute deuteration levels. The computations of relative deuteration levels follows a similar logic and is normalized by the difference of deuteration between the start (\(t_0\)) and the end of the experiment (\(t_out\)) as shown in the equation 4a:
All functions in the HaDeX package contain the logical parameter \(relative\) to determine if they should return absolute or relative deuteration levels.
+
+
2.2.2.1 Uncertainty calculations
+
We describe the methodology of the uncertainty calculations for relative deuteration levels. The uncertainty for absolute deuteration levels is computed similarly, but without scaling.
+
To calculate uncertainty related to functions of more than one variables (e. g., equation 4) the Law of propagation of uncertainty is defined by equation 5:
\(u(D_{k})\) - an uncertainty associated with \(D_{k}\) as standard deviation of the mean value,
+
+
Then, expanding the equation 6:
+
\[u_{c}(D) = \sqrt{ \left[
+\frac{1}{D_{t_{out}}-D_{t_0}} u(D_{t}) \right]^2 +
+\left[ \frac{D_{t} - D_{t_{out}}}{(D_{t_{out}}-D_{t_0})^2} u(D_{t_0}) \right]^2 +
+\left[ \frac{D_{t_0} - D_{t}}{(D_{t_{out}}-D_{t_0})^2} u (D_{t_{out}}) \right]^2}\tag{7}\] As expected, the uncertainty associated with \(D_{t}\) has the biggest impact on \(u_{c}(D)\).
+
+
+
+
2.2.3 Theoretical deuteration level
+
As opposed to the experimental deuteration levels, theoretical deuteration level only partially depends on the experimental data. Here, the maximum deuteration level is based on a hypothetical peptide where all hydrogens were replaced by deuterons, as it is shown in equation 8:
For the absolute values, \(u(D)\) is identical with \(u(D_{t})\), based on equations 8a and 9.
+
+
+
+
+
2.3 Difference of deuteration levels between two states
+
The differences of deuteration levels between two states are associated with a different level of protection of hydrogens. Therefore, we are especially interested in the differential analysis of the deuteration levels. Thus, the deuteration level in one state \((D_{2})\) is subtracted from deuteration level in the other state \((D_{1})\):
+
\[diff = D_{1} - D_{2}\tag{11}\]
+
and the uncertainty is a function of two variables (based on equation 11 and 5):
Comparison plots show the deuteration level of all peptides in selected states in a given time. The x-axis represents positions of amino acids in the sequence. The y-axis shows the deuteration level, expressed either as a relative or absolute deuteration. The chart below shows peptide deuteration after 25 minutes of the incubation along with the confidence intervals.
6{r warning=FALSE} # comparison_plot(calc_dat = calc_dat, # theoretical = FALSE, # relative = TRUE, # state_first = "Nucb2 Factor 1", # state_second = "Nucb2 Factor 2") + # labs(title = "Fraction exchanged in state comparison in 25 min time") #
+
+
absolute values:
+
+
+
+
7{r warning=FALSE} # comparison_plot(calc_dat = calc_dat, # theoretical = FALSE, # relative = FALSE, # state_first = "Nucb2 Factor 1", # state_second = "Nucb2 Factor 2") + # labs(title = "Fraction exchanged in state comparison in 25 min time") #
+
+
7.1 Woods plot
+
Woods plots show the difference between the deuteration of all peptides in two different states in a specific time point as described by equation 11. Similarly to the comparison plot, HaDeX provides both experimental and theoretical deuteration levels using either relative or absolute values:
+
– theoretical:
+
+
relative values:
+
+
+
+
+
8{r warning=FALSE} # woods_plot(calc_dat = calc_dat, # theoretical = TRUE, # relative = TRUE) + # labs(title = "Theoretical fraction exchanged between states in 25 min time") #
+
+
absolute values:
+
+
+
+
9{r warning=FALSE} # woods_plot(calc_dat = calc_dat, # theoretical = TRUE, # relative = FALSE) + # labs(title = "Theoretical fraction exchanged between states in 25 min time") #
+
– experimental:
+
+
relative values:
+
+
+
+
10{r warning=FALSE } # woods_plot(calc_dat = calc_dat, # theoretical = FALSE, # relative = TRUE) + # labs(title = "Theoretical fraction exchanged between states in 25 min time") #
+
+
absolute values:
+
+
+
+
11{r warning=FALSE } # woods_plot(calc_dat = calc_dat, # theoretical = FALSE, # relative = FALSE) + # labs(title = "Theoretical fraction exchanged between states in 25 min time") #
+
+
11.0.1 Confidence limit in Woods plot
+
The function calculate_confidence_limit_values() calculates confidence limit values as it is described elsewhere (Houde, Berkowitz, and Engen 2011).
By the term kinetics we understand deuteration change in time. To calculate deuteration values per peptide for different time points is used function calculate_kinetics(). This function uses the calculate_state_deuteration() function.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Calculated data can be shown next to each other on the plot for comparison. To visualize kinetic data we recommend plot_kinetics() function:
+
– theoretical:
+
+
relative values:
+
+
+
+
+
+
+
+
absolute values:
+
+
+
+
+
+
+
– experimental:
+
+
relative values:
+
+
+
+
+
+
+
+
absolute values:
+
+
+
+
+
+
+
+
+
13.2 Additional tools
+
HaDeX provides additional tools for assessment of experiments.
+
+
13.2.1 Peptide coverage
+
The sequence of the protein(s) is reconstructed from the peptides from the input file. Thus, amino acids not covered by peptides are marked as X according to the IUPAC convention. The sequence is reconstructed using the reconstruct_sequence() function.
The user can choose which state (or states) should be included in these plots. If this parameter is not provided, the first possible state is chosen. If a given peptide is available in more than one state, it is shown only once.
+
+
+
13.2.2 Quality control
+
The function quality_control() plots the change in the uncertainty of deuteration levels as a function of incubation time. The uncertainty is averaged over all peptides available at a given time point in a selected state. This chart has a double function: firstly, it allows checking if the measurement uncertainty is decreasing over time (which is the expected behavior) and the second one helps to plan the appropriate incubation length for the tested protein (whether we obtain the desired data reliability values).
+
In HDX-MS experiments, the average uncertainty of measurements decreases over time as the sample is more and more deuterated (even accounting for the back-propagation). Therefore, if the level of uncertainty is stable, the exchange is still ongoing and it would be advisable to prolong the reaction.
+
Moreover, the user can detect a time point after which the decrease of the deuteration uncertainty becomes too marginal to prolong the measurements. This function is most useful in case of multiple measurements of the same or very similar proteins because it helps to optimize the duration of the incubation. The result of this function can be easily visualized.
The chart below shows how we interpret the three most common results of quality control.
+
+
+
16 HaDeX Graphical User Interface
+
The HaDeX Shiny app is launched by the HaDeX_gui() function or available at MS Lab website: http://mslab-ibb.pl/shiny/HaDeX/. In the Input Data tab the user can adjust parameters to be propagated for the whole analysis.
+
+
+
17 Examples
+
+
17.1 Example 1: CD160-HVEM
+
The interaction between HVEM and the CD160 receptor was measured with HDX-MS.
+
Firstly, we read the input data, exactly as provided by the DynamX 3.0 (Waters Corp.)
Then, we reconstruct the protein sequence from the peptides measured during the experiment. We observe the region from amino acid 107 till amino acid 124 is not covered by any peptide.
The theoretical plot allows finding regions, which exchange quickly (N-terminus, regions between 30-70 amino acid) and regions, which exchange slowly (peptides 15-24, 95-110 amino acid). We can also see the differences in the exchange between two states, indicating regions which changed upon binding with other protein.
On the experimental plot, there are visible regions, which exchange quickly (N terminal part, regions between 30-70 amino acid) and regions, which exchange slowly (peptides 15-24, 30-35, 95-110 amino acid).
The plot below shows peptides for which levels of deuteration were significantly lower upon binding with other protein (red) and peptides for which levels of exchange were significantly higher upon binding with other protein (blue). The plot also shows peptides in which no significant changes in deuteration between states are visible (grey). The biggest changes on the theoretical plot can be observed in 3 peptides (15-24, 30-35, 75-90).
Bouyssié, David, Jean Lesne, Marie Locard-Paulet, Renaud Albigot, Odile Burlet-Schiltz, and Julien Marcoux. 2019. “HDX-Viewer: Interactive 3D Visualization of Hydrogen-Deuterium Exchange Data.” Bioinformatics (Oxford, England), July. https://doi.org/10.1093/bioinformatics/btz550.
+
+
+
Houde, Damian, Steven A. Berkowitz, and John R. Engen. 2011. “The Utility of Hydrogen/Deuterium Exchange Mass Spectrometry in Biopharmaceutical Comparability Studies.” Journal of Pharmaceutical Sciences 100 (6): 2071–86. https://doi.org/10.1002/jps.22432.
+
+
+
Hourdel, Véronique, Stevenn Volant, Darragh P. O’Brien, Alexandre Chenal, Julia Chamot-Rooke, Marie-Agnès Dillies, and Sébastien Brier. 2016. “MEMHDX: An Interactive Tool to Expedite the Statistical Validation and Visualization of Large HDX-MS Datasets.” Bioinformatics 32 (22): 3413–9. https://doi.org/10.1093/bioinformatics/btw420.
+
+
+
Joint Committee for Guides in Metrology. 2008. “JCGM 100: Evaluation of Measurement Data - Guide to the Expression of Uncertainty in Measurement.” JCGM.
+
+
+
Lau, Andy M. C., Zainab Ahdash, Chloe Martens, and Argyris Politis. 2019. “Deuteros: Software for Rapid Analysis and Visualization of Data from Differential Hydrogen Deuterium Exchange-Mass Spectrometry.” Bioinformatics (Oxford, England), January. https://doi.org/10.1093/bioinformatics/btz022.
+
+
+
Masson, Glenn R., John E. Burke, Natalie G. Ahn, Ganesh S. Anand, Christoph Borchers, Sébastien Brier, George M. Bou-Assaf, et al. 2019. “Recommendations for Performing, Interpreting and Reporting Hydrogen Deuterium Exchange Mass Spectrometry (HDX-MS) Experiments.” Nature Methods 16 (7): 595–602. https://doi.org/10.1038/s41592-019-0459-y.
+
+
+
Pascal, Bruce D., Scooter Willis, Janelle L. Lauer, Rachelle R. Landgraf, Graham M. West, David Marciano, Scott Novick, Devrishi Goswami, Michael J. Chalmers, and Patrick R. Griffin. 2012. “HDX Workbench: Software for the Analysis of H/D Exchange MS Data.” Journal of the American Society for Mass Spectrometry 23 (9): 1512–21. https://doi.org/10.1007/s13361-012-0419-6.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vignettes/datafiles.Rmd b/vignettes/datafiles.Rmd
new file mode 100644
index 00000000..f8834d9e
--- /dev/null
+++ b/vignettes/datafiles.Rmd
@@ -0,0 +1,136 @@
+---
+title: "Data processing"
+output: html_document
+vignette: >
+ %\VignetteIndexEntry{Data processing}
+ %\VignetteEngine{knitr::rmarkdown}
+ %\VignetteEncoding{UTF-8}
+---
+
+```{r setup, include=FALSE}
+knitr::opts_chunk$set(echo = TRUE)
+```
+
+
+
+Currently, HaDeX is limited to the `cluster` file from DynamX 3.0 or 2.0. Below we explain how the data file is processed.
+
+## Processing data from DynamX
+
+Let's investigate how the data processing of the `cluster` file from DynamX is conducted on the example file from the package.
+
+### Differences between files
+
+What is the difference between `cluster` files from DynamX 3.0 and 2.0?
+The datafiles from DynamX 2.0 don't include `Modification` and `Fragment` columns. The variations of the experiment were limited, while the DynamX 2.0 was the latest version.
+
+### Initial processing of the data
+
+Let's start with a glimpse of the datafile.
+
+```{r warning=FALSE}
+library(HaDeX)
+dat <- read_hdx(system.file(package = "HaDeX", "HaDeX/data/KD_180110_CD160_HVEM.csv"))
+head(dat, 10)
+```
+
+As you can see, the data file has a very specific structure and is not informative yet. In the file, we have `m/z` values for each `z` value (charge) for each time point for each state of each peptide, repeated as many times as measurement was repeated (each measurement should be repeated at least three times).
+
+
+
+Our aim is to have one result with an uncertainty of the measurement per each peptide in each biological state in each measured time point - data in this format allows further calculations, e.q. calculating deuterium uptake values.
+
+For a better understanding of the process of aggregating the data, see the `Data aggregation` article.
+
+Within each replicate of the measurement (we recognize each replicate by the `File` value), the `m/z` values are provided for each possible `z` value. The `m/z` values are in the `Center` column, as it is a geometrical centroid calculated from the isotopic envelope. Firstly, we have to calculate the mass value, measured experimentally:
+
+$$expMass = z \times (Center-protonMass)\tag{1}$$
+
+
+To aggregate data from different `z` values, we have to calculate the mean mass weighted by intensity. Additional information about this step and how the weighted mean impacts the results can be found in `Mass calculation` article.
+
+$$aggMass = \frac{1}{N}\sum_{k = 1}^{N}Inten_k{\cdot}pepMass_k\tag{2}$$.
+
+Where:
+
+* $aggMass$ - mass of the peptide [Da], average from replicates,
+* $Inten_k$ - intensity of the measurement,
+* $pepMass$ - mass of the peptide, calculated using Equation 1.
+
+As we use the aggregated result from the replicates, we need to calculate an uncertainty associated with the measurement. We use the mean value as the final result, so we need to calculate error as a standard deviation of the mean, according to the Equation 3:
+
+$$u(\vec{x}) = \sqrt{\frac{ \sum_{i=1}^n \left( x_{i} - \overline{x} \right)^2}{n(n-1)}}\tag{3}$$.
+
+Where:
+
+* $x_{i}$ - measured value from a replicate,
+* $\overline{x}$ - mean value from all of the replicates,
+* $n$ - number of replicates.
+
+Now we have the format we want for further calculations.
+
+### Calculation of the deuterium uptake
+
+HaDeX package provides the calculated values in different forms. All of them are provided with associated uncertainty of the measurement. All of the uncertainties are derived from the formula - the Law of propagation of uncertainty:
+
+$$u_{c}(y) = \sqrt{\sum_{k} \left[ \frac{\partial y}{\partial x_{k}} u(x_{k}) \right]^2}$$
+
+#### Deuterium uptake
+
+Deuterium uptake is the increase of the mass of the peptide in time $t$. The minimal exchange control $m_{t_0}$ is mass measured directly after adding the buffer (before the start of the exchange), and $m_t$ is the mass measured in chosen time point $t$. The value is in Daltons [Da].
+
+$$D = m_{t} - m_{t_0}$$
+The uncertainty associated with deuterium uptake [Da] (based on equation 3):
+
+$$u_c(D) = \sqrt{u(m_t)^2 + u(m_{t_0})^2}$$
+
+#### Fractional deuterium uptake
+
+Fractional deuterium uptake is the ratio of the increase of the mass in time $t$ to the maximal exchange control. The maximal exchange control $m_{t_{100}}$ is measured after a long time (chosen by the experimenter, usually 1440 min = 24 h). It is assumed that after this long time, the exchange is finished. The minimal exchange control $m_{t_0}$ is mass measured directly after adding the buffer (before the start of the exchange), and $m_t$ is the mass measured in chosen time point $t$. This value is a percentage value [%].
+
+$$D_{frac} = \frac{m_{t} - m_{t_0}}{m_{t_{100}} - m_{t_0}}$$
+
+The uncertainty associated with fractional deuterium uptake [%] (based on equation 3):
+
+$$u_{c}(D_{frac}) = \sqrt{ \left[
+\frac{1}{m_{t_{100}}-m_{t_0}} u(m_{t}) \right]^2 +
+\left[ \frac{m_{t} - m_{t_{100}}}{(m_{t_{100}}-m_{t_0})^2} u(m_{t_0}) \right]^2 +
+\left[ \frac{m_{t_0} - m_{t}}{(m_{t_{100}}-m_{t_0})^2} u (m_{t_{100}}) \right]^2}$$
+
+#### Theoretical deuterium uptake
+
+Theoretical deuterium uptake is the increase of mass in time $t$ compared with the theoretical value of the peptide mass without any exchange ($MHP$ - a mass of the singly charged monoisotopic molecular ion), and $m_t$ is the mass measured in chosen time point $t$. This value is in daltons [Da]:
+
+$$D_{theo} = m_{t} - MHP$$
+
+The uncertainty associated with theoretical deuterium uptake [Da] (the $MHP$ value is a constant without measurement uncertainty - based on the equation 3):
+
+$$u(D_{theo}) = u(m_t)$$
+
+#### Theoretical fractional deuterium uptake
+
+Theoretical fractional deuterium uptake is the ratio of the increase of mass in time $t$ compared with a theoretical value of the mass of the peptide without any exchange to the possible theoretical increase of the mass, based on the maximal potential uptake of the peptide (based on the peptide sequence). This value is a percentage value [%].
+
+$$D_{theo, frac} = \frac{m_{t}-MHP}{MaxUptake \times protonMass}$$
+
+The uncertainty associated with theoretical fractional deuterium uptake [%] (based on the equation 3):
+
+$$u(D_{theo, frac}) = \left|\frac{1}{MaxUptake \times protonMass} u(D_{t}) \right|$$
+
+#### Differential values
+
+Differential value is the way to see how the deuterium uptake differs between two biological states. It allows seeing if the possible difference is statistically important (more information below). This value is calculated as the difference between the previously described (in a chosen form) deuterium uptake of the first and second states.
+
+$$diff = D_{1} - D_{2}$$
+The uncertainty associated with the difference of deuterium uptake (based on the equation 3):
+
+$$u_{c}(diff) = \sqrt{u(D_{1})^2 + u(D_{2})^2}$$
+
+The convenient way to present results calculated as described is the comparison plot and differential plot (Woods' plot).
+
+### Additional information
+
+If the file contains modified peptides - the value from column `Modification` is added to the value from column `State` and is treated as a new biological state. The further aspects of the analysis are the same as for non-modified peptides.
+
+
+
\ No newline at end of file
diff --git a/vignettes/mass_comparison.Rmd b/vignettes/mass_comparison.Rmd
new file mode 100644
index 00000000..125dff48
--- /dev/null
+++ b/vignettes/mass_comparison.Rmd
@@ -0,0 +1,147 @@
+---
+title: "Mass calculation"
+output: html_document
+vignette: >
+ %\VignetteIndexEntry{Mass calculation}
+ %\VignetteEngine{knitr::rmarkdown}
+ %\VignetteEncoding{UTF-8}
+---
+
+## Comparison of results with weighted mean and without
+
+As it is described in `Data processing` article, the data within each replicate of the experiment is aggregated using weighted mean. Below we present the effect it has on the results.
+
+The whole workflow is described in the mentioned article. Here the focus is on the first aspect of the processing.
+
+```{r setup, include=FALSE}
+knitr::opts_chunk$set(echo = TRUE)
+knitr::opts_chunk$set(dev = "png", dev.args = list(type = "cairo-png"))
+
+options(digits=3)
+
+library(tidyr)
+library(dplyr)
+
+calculate_mass <- function(dat){
+
+ proton_mass <- 1.00727647
+
+ dat %>%
+ mutate(exp_mass = Center*z - z*proton_mass) %>%
+ select(-Center, -z, -Modification, -Fragment) %>%
+ group_by(Sequence, Start, End, MHP, MaxUptake, State, Exposure, Protein, File) %>%
+ summarize(avg_exp_mass = weighted.mean(exp_mass, Inten, na.rm = TRUE)) %>%
+ ungroup(.) %>%
+ group_by(Sequence, Start, End, MHP, MaxUptake, State, Exposure, Protein) %>%
+ summarize(mass = mean(avg_exp_mass, na.rm = TRUE),
+ err_mass = coalesce(sd(avg_exp_mass, na.rm = TRUE)/sqrt(sum(!is.na(avg_exp_mass))), 0),
+ num = (sum(!is.na(avg_exp_mass)))) %>%
+ ungroup(.) %>%
+ arrange(Start, End, Start, Exposure) %>%
+ as.data.frame()
+
+}
+
+calculate_mass_no_inten <- function(dat){
+
+ proton_mass <- 1.00727647
+
+ dat %>%
+ mutate(exp_mass = Center*z - z*proton_mass) %>%
+ select(-Center, -z, -Modification, -Fragment) %>%
+ group_by(Sequence, Start, End, MHP, MaxUptake, State, Exposure, Protein, File) %>%
+ summarize(avg_exp_mass = mean(exp_mass, na.rm = TRUE)) %>%
+ ungroup(.) %>%
+ group_by(Sequence, Start, End, MHP, MaxUptake, State, Exposure, Protein) %>%
+ summarize(mass = mean(avg_exp_mass, na.rm = TRUE),
+ err_mass = coalesce(sd(avg_exp_mass, na.rm = TRUE)/sqrt(sum(!is.na(avg_exp_mass))), 0)) %>%
+ ungroup(.) %>%
+ arrange(Start, End, Start, Exposure) %>%
+ as.data.frame()
+
+}
+
+```
+
+For the analysis, we use the example file from HaDeX.
+
+```{r}
+library(HaDeX)
+dat <- read_hdx(system.file(package = "HaDeX", "HaDeX/data/KD_180110_CD160_HVEM.csv"))
+```
+
+As described, the first step is to transform the Center value (geometric centroid of the isotopic envelope for given peptide in a given state in given time point) and then to aggregate the values measured for different charge values. This is all done within each replicate.
+
+The aggregation in our workflow is a weighted mean, with Inten (intensity) values as weights, as shown below.
+
+```{r eval=FALSE}
+avg_exp_mass = weighted.mean(exp_mass, Inten, na.rm = TRUE)
+```
+
+Later, the results from replicates are aggregated using the mean, and their uncertainty is calculated as the standard deviation of the mean.
+
+How the weighted mean change the result in comparison with the simple mean? Let's see.
+
+```{r include=FALSE}
+dat_no_weight <- calculate_mass_no_inten(dat) %>%
+ arrange(Start, End, State, Exposure) %>%
+ mutate(source = "no_weight") %>%
+ select(Sequence, Start, End, State, Exposure, mass, err_mass, source)
+
+dat_weight <- calculate_mass(dat) %>%
+ arrange(Start, End, State, Exposure) %>%
+ mutate(source = "weight") %>%
+ select(Sequence, Start, End, State, Exposure, mass, err_mass, source)
+
+tmp <- bind_rows(dat_no_weight, dat_weight) %>%
+ gather(type, value, -Sequence, -Start, -End, -source, -State, -Exposure) %>%
+ spread(source, value) %>%
+ mutate(diff = (weight-no_weight))
+```
+
+Below are calculated values of mass in two approaches and the difference between them for the example peptide.
+
+```{r echo=FALSE}
+tmp %>%
+ filter(type == "mass") %>%
+ select(-type) %>%
+ filter(Sequence == "ARSQKSGIRLQGHF")
+```
+
+Below are calculated values of the uncertainty of mass in two approaches and the difference between them for the example peptide.
+
+```{r echo=FALSE}
+tmp %>%
+ filter(type == "err_mass") %>%
+ select(-type) %>%
+ filter(Sequence == "ARSQKSGIRLQGHF")
+```
+
+And for the whole set of peptides, the average mass difference is:
+
+```{r echo=FALSE}
+mean(tmp[ tmp[["type"]] == "mass" , "diff"])
+```
+and uncertainty difference is:
+
+```{r echo=FALSE}
+mean(tmp[ tmp[["type"]] == "err_mass" , "diff"])
+```
+Below are the histograms of these differences.
+
+```{r message=FALSE, warning=FALSE, echo=FALSE}
+library(gridExtra)
+library(ggplot2)
+
+p1 <- ggplot(filter(tmp, type == "mass"), aes(diff)) +
+ geom_histogram() +
+ labs(title = "Differences between mass",
+ x = "Difference")
+
+p2 <- ggplot(filter(tmp, type == "err_mass"), aes(diff)) +
+ geom_histogram() +
+ labs(title = "Differences between uncertainties of mass",
+ x = "Difference")
+
+grid.arrange(p1, p2, ncol=2)
+```
diff --git a/vignettes/transformation.Rmd b/vignettes/transformation.Rmd
new file mode 100644
index 00000000..2d19c778
--- /dev/null
+++ b/vignettes/transformation.Rmd
@@ -0,0 +1,121 @@
+---
+title: "Data aggregation"
+output: html_document
+vignette: >
+ %\VignetteIndexEntry{Data aggregation}
+ %\VignetteEngine{knitr::rmarkdown}
+ %\VignetteEncoding{UTF-8}
+---
+
+```{r setup, include=FALSE}
+knitr::opts_chunk$set(echo = FALSE)
+knitr::opts_chunk$set(dev = "png", dev.args = list(type = "cairo-png"))
+```
+
+The aggregation of the data is complex. This article describes the process step by step for a better understanding of the data transformation.
+
+## Aggregation of the data - visualization
+
+```{r, echo=FALSE, message=FALSE, warning=FALSE}
+library(HaDeX)
+library(dplyr)
+library(ggplot2)
+
+tmp_seq <- "LCKDRSGDCSPETSLKQLRLKRDPGIDGVGEISSQL"
+tmp_state <- "CD160"
+tmp_time <- "1 min"
+proton_mass <- 1.00727647
+
+dat <- read_hdx(system.file(package = "HaDeX", "HaDeX/data/KD_180110_CD160_HVEM.csv")) %>%
+ filter(Exposure == 1, State == "CD160", Sequence == "LCKDRSGDCSPETSLKQLRLKRDPGIDGVGEISSQL")
+```
+
+Let's see how the data is transformed. We will use the example file "KD_180110_CD160_HVEM.csv" from the HaDeX package and focus on just one peptide - "LCKDRSGDCSPETSLKQLRLKRDPGIDGVGEISSQL" in the state "CD160". The measurement was made for time point 1 min.
+
+Below is shown the original and not aggregated data for chosen peptide.
+
+```{r}
+dat
+```
+
+As we can see from the `File` column, there are four replicates of the experiment. Each measurement of a replicate provide values for different possible charge values for each peptide. The result of a measurement is in column `Center` - this is a geometrical centroid of an isotopic envelope - the product of the measurement from a mass spectrometer.
+
+Let's take a look for values for each replicate.
+
+```{r echo=FALSE}
+dat %>%
+ filter(File == "KD_160530_CD160_1min_01") %>%
+ggplot() +
+ geom_segment(aes(x = Start, xend = End, y = Center, yend = Center, colour = z)) +
+ coord_cartesian( xlim = c(30, 75)) +
+ labs(title = paste0("Measurements for sequence in ", tmp_state, " state"),
+ x = "Position in the sequence")
+```
+
+The centroid values for different charge values are not useful. We have to transform it to the mass values, according to an equation:
+
+$$ aggMass = z*(Center - protonMass)$$
+The results are shown below.
+
+```{r echo=FALSE}
+dat %>%
+ filter(File == "KD_160530_CD160_1min_01") %>%
+mutate(exp_mass = z*(Center - proton_mass)) %>%
+ ggplot() +
+ geom_segment(aes(x = Start, xend = End, y = exp_mass, yend = exp_mass, colour = z)) +
+ coord_cartesian( xlim = c(30, 75)) +
+ labs(title = "", # paste0("Measurements for sequence in ", tmp_state, " state"),
+ x = "Position in the sequence",
+ y = "Measured mass [Da]")
+```
+
+This results are just for one repetition. We have four of them:
+
+```{r echo=FALSE}
+dat %>%
+mutate(exp_mass = z*(Center - proton_mass)) %>%
+ ggplot() +
+ geom_segment(aes(x = Start, xend = End, y = exp_mass, yend = exp_mass, colour = z, linetype = File)) +
+ coord_cartesian( xlim = c(30, 75)) +
+ labs(title = "", # paste0("Measurements for sequence in ", tmp_state, " state"),
+ x = "Position in the sequence",
+ y = "Measured mass [Da]")
+```
+
+Values from each replicate are aggregated into one value, using weighted mean (with intensity value as weight):
+
+```{r echo=FALSE, warning=FALSE, message=FALSE}
+dat %>%
+ mutate(exp_mass = z*(Center - proton_mass)) %>%
+ group_by(Sequence, Start, End, File) %>%
+ summarize(avg_exp_mass = weighted.mean(exp_mass, Inten, na.rm = TRUE)) %>%
+ ungroup(.) %>%
+ ggplot() +
+ geom_segment(aes(x = Start, xend = End, y = avg_exp_mass, yend = avg_exp_mass, linetype = File)) +
+ coord_cartesian( xlim = c(30, 75), ylim = c(3920.3, 3920.6)) +
+ labs(title = "", # paste0("Measurements for sequence in ", tmp_state, " state"),
+ x = "Position in the sequence",
+ y = "Measured mass [Da]")
+```
+
+The results from replicates are aggregated into the final result (mean), and the uncertainty (standard deviation of the mean) is calculated.
+
+```{r echo=FALSE, warning=FALSE, message=FALSE}
+dat %>%
+ mutate(exp_mass = z*(Center - proton_mass)) %>%
+ group_by(Sequence, Start, End, File) %>%
+ summarize(avg_exp_mass = weighted.mean(exp_mass, Inten, na.rm = TRUE)) %>%
+ ungroup(.) %>%
+ group_by(Sequence, Start, End) %>%
+ summarize(aggMass = mean(avg_exp_mass),
+ err_aggMass = sd(avg_exp_mass)) %>%
+ ggplot() +
+ geom_segment(aes(x = Start, xend = End, y = aggMass, yend = aggMass)) +
+ geom_errorbar(aes(x = 51.5, ymin = aggMass - err_aggMass, ymax = aggMass + err_aggMass)) +
+ coord_cartesian( xlim = c(30, 75), ylim = c(3920.3, 3920.6)) +
+ labs(title = paste0("Measurements for sequence in ", tmp_state, " state"),
+ x = "Position in the sequence",
+ y = "Measured mass [Da]")
+```
+
+Now we have the mass value for chosen peptide in the chosen state, measured in the chosen time point. This calculation is done for every other peptide, and these values of mass and uncertainty are used in the calculation of deuterium uptake, as described in the `Data processing` article.