diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..eca7560 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,62 @@ +name: Docs + +on: + push: + branches: + - master + paths: + - "docs/**" + - "mkdocs.yml" + - "mkdocs_hooks.py" + - "tools/mirror_osf_wiki.py" + - "tools/promote_osf_wiki_to_docs.py" + - ".github/workflows/docs.yml" + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install docs dependencies + run: | + python -m pip install --upgrade pip + pip install mkdocs mkdocs-material pymdown-extensions + + - name: Build docs + run: mkdocs build --strict + + - name: Configure GitHub Pages + uses: actions/configure-pages@v5 + + - name: Upload Pages artifact + uses: actions/upload-pages-artifact@v3 + with: + path: site + + deploy: + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index c912a12..4ff3f34 100644 --- a/.gitignore +++ b/.gitignore @@ -34,8 +34,9 @@ share/python-wheels/ .installed.cfg *.egg MANIFEST +site/ # test output tests/input/*/output/* -sigProfilerPlotting/examples/output/ \ No newline at end of file +sigProfilerPlotting/examples/output/ diff --git a/README.md b/README.md index 86f491a..cfae338 100755 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ -[![Docs](https://img.shields.io/badge/docs-latest-blue.svg)](https://osf.io/2aj6t/wiki/home/) [![License](https://img.shields.io/badge/License-BSD\%202--Clause-orange.svg)](https://opensource.org/licenses/BSD-2-Clause) [![CI](https://github.com/sigprofilersuite/SigProfilerPlotting/actions/workflows/ci.yml/badge.svg)](https://github.com/sigprofilersuite/SigProfilerPlotting/actions/workflows/ci.yml) +[![Docs](https://img.shields.io/badge/docs-latest-blue.svg)](https://sigprofilersuite.github.io/SigProfilerPlotting/) [![License](https://img.shields.io/badge/License-BSD\%202--Clause-orange.svg)](https://opensource.org/licenses/BSD-2-Clause) [![CI](https://github.com/sigprofilersuite/SigProfilerPlotting/actions/workflows/ci.yml/badge.svg)](https://github.com/sigprofilersuite/SigProfilerPlotting/actions/workflows/ci.yml) # SigProfilerPlotting SigProfilerPlotting provides a standard tool for displaying all types of mutational signatures as well as all types of mutational patterns in cancer genomes. The tool seamlessly integrates with other SigProfiler tools. **INTRODUCTION** -The purpose of this document is to provide a guide for using the SigProfilerPlotting framework and associated functions/tools to visualize the output from SigProfilerExtraction and SigProfilerSimulator. An extensive Wiki page detailing the usage of this tool can be found at https://osf.io/2aj6t/wiki/home. +The purpose of this document is to provide a guide for using the SigProfilerPlotting framework and associated functions/tools to visualize the output from SigProfilerExtraction and SigProfilerSimulator. The primary documentation is now maintained in this repository under `docs/`, and the legacy OSF wiki source is at https://osf.io/2aj6t/wiki/home. For users that prefer working in an R environment, a wrapper package is provided and can be found and installed from: https://github.com/AlexandrovLab/SigProfilerPlottingR diff --git a/docs/Example-Program.md b/docs/Example-Program.md new file mode 100644 index 0000000..f876508 --- /dev/null +++ b/docs/Example-Program.md @@ -0,0 +1,25 @@ +## Running the Example Program ## +After you have successfully installed SigProfilerPlotting, [download SigProfilerPlottingExampleProgram.zip][1], and move it to your desktop and unzip it. + +Next, open up your application terminal and enter the following command: + + cd ~/Desktop/SigProfilerPlottingExampleProgram/ + +You can now run the example program by entering the command: + + python3 plot_example.py + +It may take a few seconds to complete. You can find the output graphs in the directory labeled `plots`, which is located in your current directory. If you are having difficulty locating the folder, open the finder application and press `⌘ + Shift + G` and enter into the "Go to the Folder" drop down menu: `~/Desktop/SigProfilerPlottingExampleProgram/plots/` + + @[osf](kw8py) + +If you delete the four plot files and run plot_example.py then they should be generated again. +
+
+Now that you were able to run `plot_example.py` your environment is set up and you are ready to start writing your own applications. Take a look at the sections labeled [Plotting Substitutions][2], [Plotting Indels][3], and [Plotting Dinucleotides][4] for more details about the different functions that SigProfilerPlotting provides. + + + [1]: https://osf.io/2wh7g/ + [2]: https://osf.io/2aj6t/wiki/3.%20Plotting%20Substitutions/ + [3]: https://osf.io/2aj6t/wiki/4.%20Plotting%20Indels/ + [4]: https://osf.io/2aj6t/wiki/5.%20Plotting%20Dinucleotides/ diff --git a/docs/Installation-Python.md b/docs/Installation-Python.md new file mode 100644 index 0000000..dff67c7 --- /dev/null +++ b/docs/Installation-Python.md @@ -0,0 +1,100 @@ +

SigProfilerPlotting Installation Guide

+ +---------- + +## Prerequisites ## + +SigProfilerPlotting requires that you have: + + +## Mac/Unix ## +Check that you have the required python version by opening Terminal (`⌘ + Space` type `terminal` and hit `return` to open the application) and entering the command: + + python3 --version + +You should see an output similar to: + + ~ python3 --version + Python 3.4.0 + +If you do not get a similar output (or a version that is 3.4.0 or newer), you will need to [install python3][1] before continuing with this guide. + +Next you will want to make sure that you have `pip3` installed because it will be used for importing sigProfilerPlotting. Check that you have `pip3` installed by entering into terminal: + + pip3 --version + +You should see an output similar to: + + ~ pip3 --version + pip 19.0.1 /Library/Frameworks/SomeFilePath/ + +If you do not have pip3 installed, then follow [homebrew's guide][2] for installing pip. + + +Next, use pip3 to download SigProfilerPlotting. + + pip3 install sigProfilerPlotting + +You can check that the installation was successful by entering into Terminal: + + pip3 list +This command will output a list of libraries that you have access to. Matplotlib and sigProfilerPlotting should be two of the libraries listed. + +@[osf](uabr5) + +If the download fails or you receive an error, check to make sure that python3 and pip3 are installed by using the --version commands. If they are not, start from the beginning of the guide and follow the directions again to download them. + +## Windows ## +First, start by opening up Command Prompt. Navigate to the search bar in the lower left hand corner of the screen and search `cmd` and open the application `Command Prompt`. + +Next, you will download and install Python and Pip. Check if Python is installed by entering the command: + + python --version + +If you have Python installed, you should receive an output similar to: + + C:\Users\YourUserName>python + Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] on win32 + Type "help", "copyright", "credits" or "license" for more information. + >>> + +If you do not have python, or need Python 3.4.0 or newer, then [download Python here][3]. + +After downloading and installing Python, fill in your username at `YourUsernameHere` and run: + + setx PATH “%PATH%;C:\Users\YourUsernameHere\AppData\Local\Programs\Python\Python37\” + setx PATH “%PATH%;C:\Users\YourUsernameHere\AppData\Local\Programs\Python\Python37\Scripts\” + +This will set the path so that you can call Python and pip from the command line. + +Check that you have the required libraries installed by entering into the command line: + + python --version + pip --version + +If you both commands output version numbers, then you have successfully downloaded and installed Python and pip and you are ready to proceed. Otherwise, go through the process of reinstalling Python and pip. + +Now that your environment is ready, use pip to install sigProfilerPlotting. + + pip install sigProfilerPlotting + +If the download was successful, then sigProfilerPlotting should be one of the libraries outputted by the following command. + + pip list + +@[osf](egk7c) + +Now your environment should be setup and ready to use the sigProfilerPlotting library. + +If you are receiving an error, check to make sure that python and pip are installed by using the --version commands. If they are not installed, start from the beginning of the guide and follow the directions again to download them. + +**Note for Windows Users**: When passing the path to your files as a parameter to any of the functions, you will need make your string into a raw string literal (ie. the String "C:\User\YourUserName\Desktop\\" will need to be r"C:\User\YourUserName\Desktop\\\\"). + + + [1]: https://realpython.com/installing-python/ + [2]: https://docs.brew.sh/Homebrew-and-Python + [3]: https://www.python.org/ diff --git a/docs/Installation-R.md b/docs/Installation-R.md new file mode 100644 index 0000000..68fd5dc --- /dev/null +++ b/docs/Installation-R.md @@ -0,0 +1,75 @@ +

SigProfilerPlotting Installation (R-wrapper) Guide

+ +---------- + +## Prerequisites ## + +SigProfilerPlottingR requires that you have: + + +## Mac/Unix ## +Check that you have the required python version by opening Terminal (`⌘ + Space` type `terminal` and hit `return` to open the application) and entering the command: + + python3 --version + +You should see an output similar to: + + ~ python3 --version + Python 3.4.0 + +If you do not get a similar output (or a version that is 3.4.0 or newer), you will need to [install python3][1] before continuing with this guide. + +Next you will want to make sure that you have `pip3` installed because it will be used for importing sigProfilerPlotting. Check that you have `pip3` installed by entering into terminal: + + pip3 --version + +You should see an output similar to: + + ~ pip3 --version + pip 19.0.1 /Library/Frameworks/SomeFilePath/ + +If you do not have pip3 installed, then follow [homebrew's guide][2] for installing pip. + + +Next, use pip3 to download SigProfilerPlotting. + + pip3 install sigProfilerPlotting + +You can check that the installation was successful by entering into Terminal: + + pip3 list +This command will output a list of libraries that you have access to. Matplotlib and sigProfilerPlotting should be two of the libraries listed. + +@[osf](uabr5) + +If the download fails or you receive an error, check to make sure that python3 and pip3 are installed by using the --version commands. If they are not, start from the beginning of the guide and follow the directions again to download them. + +## Installing R dependencies ## +You must install the devtools and reticulate libraries: + + $ R + >> install.packages("devtools") + >> install.packages("reticulate") + +Now you are ready to install SigProfilerPlottingR: + + $ R + >> library("reticulate") + >> use_python("path_to_your_python3") + >> py_config() + >> library("devtools") + >> install_github("AlexandrovLab/SigProfilerPlottingR") + +Ensure that you can properly load the package: + + >> library("SigProfilerPlottingR") + + + + [1]: https://realpython.com/installing-python/ + [2]: https://docs.brew.sh/Homebrew-and-Python + [3]: https://www.python.org/ diff --git a/docs/Plotting-Dinucleotides.md b/docs/Plotting-Dinucleotides.md new file mode 100644 index 0000000..791d876 --- /dev/null +++ b/docs/Plotting-Dinucleotides.md @@ -0,0 +1,69 @@ +# Plotting Dinucleotides # + +---------- + +Refer to this page to learn about how to plot dinucleotides (DBS) using the plotDBS function. Included below is the function and a list of valid parameter values. There are also examples of each DBS graph with a quick description for interpreting it. + +@[toc](Sections) + +## plotDBS Function ## +Plots the number of double base substitutions. + + plotDBS(matrix_path, output_path, project, plot_type, percentage=False, custom_text_upper=None, custom_text_middle=None, custom_text_lower=None) + +For those using the R-wrapper, you must switch any "True" to "TRUE", "False" to "FALSE", and "None" to "NULL." + +- **matrix_path** -> (String) The path to your matrix (generated by SigProfilerMatrixGenerator).
+- **output_path** -> (String) The path to where the output will be saved.
+- **project** -> (String) The output file will have this value postfixed in the name.
+- **plot type** -> (String) The plot type to be generated. Valid inputs include {"78", "312"}.
+- **percentage** -> (Boolean) True for a normalized percentile plot and False for a numerical plot. This parameter has a default value of False.
+- **custom_text_upper, custom_text_middle, custom_text_bottom** -> (List of Strings) Provide a list of strings for adding a custom text to the upper right-hand corner of the plot. Ideally, there should be one string per sample. Extra strings will not be plotted. The three parameters allow for three rows of custom text (upper, middle, lower). + +Supported SigProfiler Matrices include: 78 and 186.
+ +## plotDBS Examples ## +The following examples were generated in a python environment where sigProfilerPlotting was imported as sigPlt. + + $ python3 + >>import sigProfilerPlotting as sigPlt + +From within a R session: + + $ R + >> library("reticulate") + >> use_python("path_to_your_python3") + >> py_config() + >> library("SigProfilerPlottingR") + +The matrices below are used to generate the example plots. You can download and run the commands to generate the example plots. +- [DBS-78][1] +- [DBS-186][2] + +### Plot DBS-78 ### +From within a Python session: + + sigPlt.plotDBS(matrix_path_DINUC + "DBS78.all", output_path, project_name, "78", percentage=False) + +From within a R session: + + plotDBS(matrix_path_DINUC + "DBS78.all", output_path, project_name, "78", percentage=FALSE) + +@[osf](s7wuj) +The **Double Base Substitution-78 (DBS-78) plot** counts the number of double base mutations. The DBS categories are listed along the top of the plot, and the number of each mutation are represented along the y-axis. The 78 mutational channels are determined using the maximum pyrimidine context of the mutation. + +### Plot DBS-186 ### +From within a Python session: + + sigPlt.plotDBS(matrix_path_DINUC + "DBS186.all", output_path, project_name, "186",False) + +From within a R session: + + plotDBS(matrix_path_DINUC + "DBS186.all", output_path, project_name, "186",FALSE) + +@[osf](uxyfv) +The **Double Base Substitution-186 (DBS-186) plot** counts the number of double base mutations that occur on the transcribed or untranscribed strands within protein coding regions. Only doublet-substitutions containing all pyrimidines or all purines can be classified this way. The DBS categories are listed along the top of the plot, and the number of each mutation are represented along the y-axis. + + + [1]: https://osf.io/d3e6f/ + [2]: https://osf.io/p2fxv/ diff --git a/docs/Plotting-Indels.md b/docs/Plotting-Indels.md new file mode 100644 index 0000000..e269ee3 --- /dev/null +++ b/docs/Plotting-Indels.md @@ -0,0 +1,86 @@ +# Plotting Indels # + +---------- + +Refer to this page to learn about how to plot small insertions and deletions (indels) using the plotID function. Included below is the function and a list of valid parameter values. There are also examples of each indel graph with a quick description for interpreting it. + +@[toc](Sections) + +## plotID Function ## +Plots the number of small insertions, deletions, and microhomologies. + + plotID(matrix_path, output_path, project, plot_type, percentage=False, custom_text_upper=None, custom_text_middle=None, custom_text_lower=None) + +For those using the R-wrapper, you must switch all "False" to "FALSE", "True" to "TRUE", and "None" to "NULL." + +- **matrix_path** -> (String) The path to your matrix (generated by SigProfilerMatrixGenerator).
+- **output_path** -> (String) The path to where the output will be saved.
+- **project** -> (String) The output file will have this value postfixed in the name.
+- **plot type** -> (String) The plot type to be generated. Valid inputs include {"28", "83", "415"}.
+- **percentage** -> (Boolean) True for a normalized percentile plot and False for a numerical plot. This parameter has a default value of False.
+- **custom_text_upper, custom_text_middle, custom_text_bottom** -> (List of Strings) Provide a list of strings for adding a custom text to the upper right-hand corner of the plot. Ideally, there should be one string per sample. Extra strings will not be plotted. The three parameters allow for three rows of custom text (upper, middle, lower). + +Supported SigProfiler Matrices include: 28 (ID_Simple), 83, and 415.
+ +## plotID Examples ## + +The following examples were generated in a python environment where sigProfilerPlotting was imported as sigPlt. + + $ python3 + >>import sigProfilerPlotting as sigPlt + +From within a R session: + + $ R + >> library("reticulate") + >> use_python("path_to_your_python3") + >> py_config() + >> library("SigProfilerPlottingR") + +The matrices below are used to generate the example plots. You can download and run the commands to generate the example plots. +- [ID Simple][1] +- [ID-83][2] +- [ID-415][3] + +### Plot ID_Simple ### +From within a Python session: + + sigPlt.plotID(matrix_path_INDEL + "INDEL28.all", output_path, project_name, "28", percentage=False) + +From within a R session: + + plotID(matrix_path_INDEL + "INDEL28.all", output_path, project_name, "28", percentage=FALSE) + +@[osf](kwd3y) +The **Insertion Deletion Simple (ID-Simple) plot** shows single base pair insertion and deletions with respect to the pyrimidine context. The x-axis represents the number of repeated bases of the given indel (homopolymer length). The y-axis is the number of mutations that occurred for the given category. On the far right of the plot, there are columns for large deletions, insertions, and microhomologies greater than one base pair. There is an additional column for complex indels which represent events that both deleted bases and inserted bases into the same region of the genome. + + +### Plot ID-83 ### +From within a Python session: + + sigPlt.plotID(matrix_path_INDEL + "INDEL83.all", output_path, project_name, "83", percentage=False) + +From within a R session: + + plotID(matrix_path_INDEL + "INDEL83.all", output_path, project_name, "83", percentage=FALSE) + + +@[osf](hfqr2) +The **Insertion Deletion-83 (ID-83) plot** counts the number of small insertions and deletions that occur at a single base pair and at sequences of base pairs longer than one. The plot also displays microhomologies which are deletions that occur adjacent to a substring of the deleted sequence. + +### Plot ID-415 ### +From within a Python session: + + sigPlt.plotID(matrix_path_INDEL + "INDEL415.all", output_path, project_name, "415",False) + +From within a R session: + + plotID(matrix_path_INDEL + "INDEL415.all", output_path, project_name, "415",FALSE) + +@[osf](b7m2t) +The **Insertion Deletion-415 (ID415) plot** counts the number of small insertions and deletions that occur at a single base pair and at sequences of base pairs longer than one. The plot also displays microhomologies which are deletions that occur adjacent to a substring of the deleted sequence. The plot shows the mutations that occur on the transcribed or untranscribed strands within protein-coding regions (bidirectional, non-transcribed, and unclassifiable indels are not plotted). + + + [1]: https://osf.io/xd9ym/ + [2]: https://osf.io/3rm96/ + [3]: https://osf.io/2ydqt/ diff --git a/docs/Plotting-Substitutions.md b/docs/Plotting-Substitutions.md new file mode 100644 index 0000000..0a924ed --- /dev/null +++ b/docs/Plotting-Substitutions.md @@ -0,0 +1,133 @@ +# Plotting Substitutions # + +---------- + +Refer to this page to learn about how to plot single base substitutions (SBS) using the plotSBS function. Included below is the function and a list of valid parameter values. There are also examples of each SBS graph with a quick description for interpreting it. + + +@[toc](Sections) + +## plotSBS Function ## +The plotSBS function provides a standard approach for displaying mutational signatures and mutational patterns of single base substitutions. Depending on the specified parameters, the function can generate a number of distinct representations of signatures/patterns. + + plotSBS(matrix_path, output_path, project, plot_type, percentage=False, custom_text_upper=None, custom_text_middle=None, custom_text_bottom=None) + +or if you are running the R-wrapper package, any "False" must be changed to FALSE, "True" changed to "TRUE", and "None" changed to "NULL." + +- **matrix_path** -> (String) The path to your matrix (generated by SigProfilerMatrixGenerator)
+- **output_path** -> (String) The path to where the output will be saved
+- **project** -> (String) The output file will have this value postfixed in the name.
+- **plot type** -> (String) The plot type to be generated. Valid inputs include {"6", "24", "96", "384", and "1536"}. +
+- **percentage** -> (Boolean) True for a normalized percentile plot and False for a numerical plot. This parameter has a default value of False.
+- **custom_text_upper, custom_text_middle, custom_text_bottom** -> (List of Strings) Provide a list of strings for adding a custom text to the upper right-hand corner of the plot. Ideally, there should be one string per sample. Extra strings will not be plotted. The three parameters allow for three rows of custom text (upper, middle, lower). + + +Supported SigProfiler Matrices include: 6, 24, 96, 384, and 1536.
+ +## plotSBS Examples ## +The following examples were generated in a python environment where sigProfilerPlotting was imported as sigPlt. + + $ python3 + >>import sigProfilerPlotting as sigPlt + +From within a R session, you will import the library as follows: + + $ R + >> library("reticulate") + >> use_python("path_to_your_python3") + >> py_config() + >> library("SigProfilerPlottingR") + + +The matrices below are used to generate the example plots. You can download and run the commands to generate the example plots. +- [SBS-6][1] +- [SBS-24][2] +- [SBS-96][3] +- [SBS-384][4] +- [SBS-1536][5] + +### Plot SBS-6 Numerical ### +From within a Python session: + + sigPlt.plotSBS(matrix_path_SBS + "SBS6.all", output_path, project_name, "6", percentage=False) + +From within a R session: + + >> plotSBS(matrix_path_SBS + "SBS6.all", output_path, project_name, "6", percentage=FALSE) + + + +@[osf](cmv6d) +The **Single Base Substitution-6 (SBS-6) numerical plot** has the six different mutation categories on the y-axis and the number of each mutation on the x-axis. The sample name and total number of substitutions are provided at the top of the plot. + +### Plot SBS-6 Percentile ### +From within a Python session: + + sigPlt.plotSBS(matrix_path_to_SBS_file + "SBS6.all", output_path, "BRCA_example", "6", percentage=True) + +From within a R session: + + plotSBS(matrix_path_to_SBS_file + "SBS6.all", output_path, "BRCA_example", "6", percentage=TRUE) + +@[osf](kmd2f) +The **Single Base Substitution-6 (SBS-6) percentile plot** includes the six different mutation categories on the y-axis and the normalized percentages of each mutation on the x-axis. + +### Plot SBS-24 ### +From within a Python session: + + sigPlt.plotSBS(matrix_path_SBS + "SBS24.all", output_path,"BRCA_example", "24",False) + +From within a R session: + + plotSBS(matrix_path_SBS + "SBS24.all", output_path,"BRCA_example", "24",FALSE) + +@[osf](jcemf) +The **Single Base Substitution-24 (SBS-24) numerical plot** includes the six different mutation categories on the y-axis , and the number of mutations that occurred on the transcribed and untranscribed strands on the x-axis (does not plot bidirectional and nontranscribed TSB categories). +
+
+ +### Plot SBS-96 ### +From within a Python session: + + sigPlt.plotSBS(matrix_path_SBS + "SBS96.all", output_path,"BRCA_example", "96",False) + +From within a R session: + + plotSBS(matrix_path_SBS + "SBS96.all", output_path,"BRCA_example", "96",FALSE) + +@[osf](fgc8z) +The **Single Base Substitution-96 (SBS-96) numerical plot** graphs the trinucleotide contexts of each mutation. Along the x-axis are the six main categories that represent the different mutations (C>A, C>G,...,T>G). Each of these six categories has an additional 16 categories to represent the combinations of bases that can prefix and postfix the mutation (ie. ACA, ACC, ACG, ACT, CCA,..., TCT). The y-axis presents the number of each mutation. +
+
+### Plot SBS-384 ### +From within a Python session: + + sigPlt.plotSBS(matrix_path_SBS + "SBS384.all", output_path,"BRCA_example", "384",False) + +From within a R session: + + plotSBS(matrix_path_SBS + "SBS384.all", output_path,"BRCA_example", "384", FALSE) + +@[osf](78htw) +The **Single Base Substitution-384 (SBS-384) numerical plot** graphs the trinucleotide contexts of each mutation. Along the x-axis are the six main categories that represent the different mutations (C>A, C>G,...,T>G). Each of these six categories has an additional 16 categories to represent the combinations of bases that can prefix and postfix the mutation (ie. ACA, ACC, ACG, ACT, CCA,..., TCT). Additionally, the mutation is categorized depending whether it was located on the transcribed or untranscribed strand. The y-axis is the number of such mutations that occurred. + +### Plot SBS-1536 ### +From within a Python session: + + sigPlt.plotSBS(matrix_path_SBS + "SBS1536.all", output_path,"BRCA_example", "1536",False) + +From within a R session: + + plotSBS(matrix_path_SBS + "SBS1536.all", output_path,"BRCA_example", "1536",FALSE) + +@[osf](sc9qj) + +The **Single Base Substitution-1536 (SBS-1536) numerical plot** graphs the trinucleotide contexts of each mutations. Along the top on the x-axis are the six main categories that represent the different mutations (C>A, C>G,...,T>G). Directly below these categories are a set of bar graphs that have the number of each mutation. Also, beneath the bar graphs are heat maps of the pentanucleotide contexts. The probability is normalized to the maximum pentanucleotide count. + + + [1]: https://osf.io/8ubjp/ + [2]: https://osf.io/synw4/ + [3]: https://osf.io/p3yzs/ + [4]: https://osf.io/gmcyp/ + [5]: https://osf.io/43e76/ diff --git a/docs/Plotting-a-Sample-Portrait.md b/docs/Plotting-a-Sample-Portrait.md new file mode 100644 index 0000000..1cef90c --- /dev/null +++ b/docs/Plotting-a-Sample-Portrait.md @@ -0,0 +1,55 @@ +# Plotting a Sample Portrait # + +---------- + +Refer to this page to learn about how to use the Sample Portrait function. Included below is the function and a list of valid parameter values. There is also an example of the Sample Portrait. + + +@[toc](Sections) + +## samplePortrait Function ## +Outputs a file with the different substitution, indel, and dinucleotide graphs. + + samplePortrait(matrix, output_path, project, percentage=False) + +For those using the R-wrapper, you must switch any "True" to "TRUE", "False" to "FALSE", and "None" to "NULL." + +- **matrix_path** -> (String) The path to your matrix (generated by SigProfilerMatrixGenerator).
+- **output_path** -> (String) The path to where the output will be saved.
+- **project** -> (String) The output file will have this value postfixed in the name.
+- **percentage** -> (Boolean) True for a normalized percentile plot and False for a numerical plot. This parameter has a default value of False.
+ +To create a sample portrait, ensure that you have a matrix for all required contexts (SBS-6, SBS-24, SBS-96, SBS-384, SBS-1536, DBS-78, DBS-312, ID-83, ID-28, ID-96). + +## plotDBS Examples ## +The following examples were generated in a python environment where sample_portrait was imported as sP from sigProfilerPlotting. + + $python3 + >>from sigProfilerPlotting import sample_portrait as sP + +From within a R session: + + $ R + >> library("reticulate") + >> use_python("path_to_your_python3") + >> py_config() + >> library("SigProfilerPlottingR") + + +### The Sample Portrait ### +From within a Python session: + + sP.samplePortrait(sample_matrices_path, output_path, project, percentage=False) + +From within a R session: + + samplePortrait(sample_matrices_path, output_path, project, percentage=FALSE) + +@[osf](2he54) + +This collection of graphs includes the variations that are produced by each function. To produce an individual graph found in the collection, navigate to [Plotting Susbtitutions][1], [Plotting Indels][2], or [Plotting Dinucleotides][3], and call the corresponding function. + + + [1]: https://osf.io/2aj6t/wiki/3.%20Plotting%20Substitutions/ + [2]: https://osf.io/2aj6t/wiki/4.%20Plotting%20Indels/ + [3]: https://osf.io/2aj6t/wiki/5.%20Plotting%20Dinucleotides/ diff --git a/docs/assets/osf/2wh7g.zip b/docs/assets/osf/2wh7g.zip new file mode 100644 index 0000000..919fd80 Binary files /dev/null and b/docs/assets/osf/2wh7g.zip differ diff --git a/docs/assets/osf/2ydqt.bin b/docs/assets/osf/2ydqt.bin new file mode 100644 index 0000000..e72bbba --- /dev/null +++ b/docs/assets/osf/2ydqt.bin @@ -0,0 +1,416 @@ +MutationType TutorialSample TutorialSample_snv +T:1:Del:C:0 7 0 +T:1:Del:C:1 10 0 +T:1:Del:C:2 6 0 +T:1:Del:C:3 0 0 +T:1:Del:C:4 2 0 +T:1:Del:C:5 2 0 +T:1:Del:T:0 16 0 +T:1:Del:T:1 6 0 +T:1:Del:T:2 7 0 +T:1:Del:T:3 5 0 +T:1:Del:T:4 7 0 +T:1:Del:T:5 5 0 +T:2:Del:R:0 3 0 +T:2:Del:R:1 2 0 +T:2:Del:R:2 0 0 +T:2:Del:R:3 0 0 +T:2:Del:R:4 0 0 +T:2:Del:R:5 0 0 +T:3:Del:R:0 0 0 +T:3:Del:R:1 1 0 +T:3:Del:R:2 0 0 +T:3:Del:R:3 0 0 +T:3:Del:R:4 0 0 +T:3:Del:R:5 0 0 +T:4:Del:R:0 1 0 +T:4:Del:R:1 0 0 +T:4:Del:R:2 0 0 +T:4:Del:R:3 0 0 +T:4:Del:R:4 0 0 +T:4:Del:R:5 0 0 +T:5:Del:R:0 1 0 +T:5:Del:R:1 5 0 +T:5:Del:R:2 1 0 +T:5:Del:R:3 0 0 +T:5:Del:R:4 1 0 +T:5:Del:R:5 1 0 +T:2:Del:M:1 3 0 +T:3:Del:M:1 0 0 +T:3:Del:M:2 1 0 +T:4:Del:M:1 0 0 +T:4:Del:M:2 0 0 +T:4:Del:M:3 0 0 +T:5:Del:M:1 0 0 +T:5:Del:M:2 0 0 +T:5:Del:M:3 0 0 +T:5:Del:M:4 1 0 +T:5:Del:M:5 1 0 +T:1:Ins:C:0 0 0 +T:1:Ins:C:1 1 0 +T:1:Ins:C:2 1 0 +T:1:Ins:C:3 1 0 +T:1:Ins:C:4 0 0 +T:1:Ins:C:5 0 0 +T:1:Ins:T:0 2 0 +T:1:Ins:T:1 4 0 +T:1:Ins:T:2 9 0 +T:1:Ins:T:3 3 0 +T:1:Ins:T:4 2 0 +T:1:Ins:T:5 9 0 +T:2:Ins:R:0 0 0 +T:2:Ins:R:1 1 0 +T:2:Ins:R:2 1 0 +T:2:Ins:R:3 0 0 +T:2:Ins:R:4 0 0 +T:2:Ins:R:5 0 0 +T:3:Ins:R:0 0 0 +T:3:Ins:R:1 0 0 +T:3:Ins:R:2 0 0 +T:3:Ins:R:3 0 0 +T:3:Ins:R:4 0 0 +T:3:Ins:R:5 0 0 +T:4:Ins:R:0 0 0 +T:4:Ins:R:1 1 0 +T:4:Ins:R:2 0 0 +T:4:Ins:R:3 0 0 +T:4:Ins:R:4 0 0 +T:4:Ins:R:5 0 0 +T:5:Ins:R:0 1 0 +T:5:Ins:R:1 0 0 +T:5:Ins:R:2 3 0 +T:5:Ins:R:3 0 0 +T:5:Ins:R:4 0 0 +T:5:Ins:R:5 0 0 +U:1:Del:C:0 8 0 +U:1:Del:C:1 5 0 +U:1:Del:C:2 6 0 +U:1:Del:C:3 2 0 +U:1:Del:C:4 1 0 +U:1:Del:C:5 0 0 +U:1:Del:T:0 10 0 +U:1:Del:T:1 10 0 +U:1:Del:T:2 13 0 +U:1:Del:T:3 13 0 +U:1:Del:T:4 5 0 +U:1:Del:T:5 7 0 +U:2:Del:R:0 0 0 +U:2:Del:R:1 0 0 +U:2:Del:R:2 1 0 +U:2:Del:R:3 0 0 +U:2:Del:R:4 0 0 +U:2:Del:R:5 1 0 +U:3:Del:R:0 1 0 +U:3:Del:R:1 1 0 +U:3:Del:R:2 0 0 +U:3:Del:R:3 0 0 +U:3:Del:R:4 0 0 +U:3:Del:R:5 0 0 +U:4:Del:R:0 1 0 +U:4:Del:R:1 0 0 +U:4:Del:R:2 0 0 +U:4:Del:R:3 0 0 +U:4:Del:R:4 0 0 +U:4:Del:R:5 0 0 +U:5:Del:R:0 0 0 +U:5:Del:R:1 1 0 +U:5:Del:R:2 1 0 +U:5:Del:R:3 3 0 +U:5:Del:R:4 1 0 +U:5:Del:R:5 1 0 +U:2:Del:M:1 0 0 +U:3:Del:M:1 0 0 +U:3:Del:M:2 1 0 +U:4:Del:M:1 0 0 +U:4:Del:M:2 0 0 +U:4:Del:M:3 0 0 +U:5:Del:M:1 0 0 +U:5:Del:M:2 0 0 +U:5:Del:M:3 0 0 +U:5:Del:M:4 0 0 +U:5:Del:M:5 0 0 +U:1:Ins:C:0 1 0 +U:1:Ins:C:1 0 0 +U:1:Ins:C:2 1 0 +U:1:Ins:C:3 0 0 +U:1:Ins:C:4 1 0 +U:1:Ins:C:5 2 0 +U:1:Ins:T:0 1 0 +U:1:Ins:T:1 9 0 +U:1:Ins:T:2 6 0 +U:1:Ins:T:3 5 0 +U:1:Ins:T:4 1 0 +U:1:Ins:T:5 10 0 +U:2:Ins:R:0 0 0 +U:2:Ins:R:1 1 0 +U:2:Ins:R:2 1 0 +U:2:Ins:R:3 0 0 +U:2:Ins:R:4 0 0 +U:2:Ins:R:5 0 0 +U:3:Ins:R:0 1 0 +U:3:Ins:R:1 0 0 +U:3:Ins:R:2 0 0 +U:3:Ins:R:3 0 0 +U:3:Ins:R:4 0 0 +U:3:Ins:R:5 0 0 +U:4:Ins:R:0 1 0 +U:4:Ins:R:1 0 0 +U:4:Ins:R:2 0 0 +U:4:Ins:R:3 0 0 +U:4:Ins:R:4 0 0 +U:4:Ins:R:5 0 0 +U:5:Ins:R:0 3 0 +U:5:Ins:R:1 4 0 +U:5:Ins:R:2 4 0 +U:5:Ins:R:3 4 0 +U:5:Ins:R:4 1 0 +U:5:Ins:R:5 2 0 +B:1:Del:C:0 0 0 +B:1:Del:C:1 0 0 +B:1:Del:C:2 0 0 +B:1:Del:C:3 0 0 +B:1:Del:C:4 0 0 +B:1:Del:C:5 0 0 +B:1:Del:T:0 1 0 +B:1:Del:T:1 0 0 +B:1:Del:T:2 0 0 +B:1:Del:T:3 0 0 +B:1:Del:T:4 0 0 +B:1:Del:T:5 0 0 +B:2:Del:R:0 0 0 +B:2:Del:R:1 0 0 +B:2:Del:R:2 0 0 +B:2:Del:R:3 0 0 +B:2:Del:R:4 0 0 +B:2:Del:R:5 0 0 +B:3:Del:R:0 0 0 +B:3:Del:R:1 0 0 +B:3:Del:R:2 0 0 +B:3:Del:R:3 0 0 +B:3:Del:R:4 0 0 +B:3:Del:R:5 0 0 +B:4:Del:R:0 0 0 +B:4:Del:R:1 0 0 +B:4:Del:R:2 0 0 +B:4:Del:R:3 0 0 +B:4:Del:R:4 0 0 +B:4:Del:R:5 0 0 +B:5:Del:R:0 0 0 +B:5:Del:R:1 0 0 +B:5:Del:R:2 0 0 +B:5:Del:R:3 0 0 +B:5:Del:R:4 0 0 +B:5:Del:R:5 0 0 +B:2:Del:M:1 0 0 +B:3:Del:M:1 0 0 +B:3:Del:M:2 0 0 +B:4:Del:M:1 0 0 +B:4:Del:M:2 0 0 +B:4:Del:M:3 0 0 +B:5:Del:M:1 0 0 +B:5:Del:M:2 0 0 +B:5:Del:M:3 0 0 +B:5:Del:M:4 0 0 +B:5:Del:M:5 0 0 +B:1:Ins:C:0 0 0 +B:1:Ins:C:1 0 0 +B:1:Ins:C:2 0 0 +B:1:Ins:C:3 0 0 +B:1:Ins:C:4 0 0 +B:1:Ins:C:5 0 0 +B:1:Ins:T:0 0 0 +B:1:Ins:T:1 0 0 +B:1:Ins:T:2 0 0 +B:1:Ins:T:3 0 0 +B:1:Ins:T:4 0 0 +B:1:Ins:T:5 1 0 +B:2:Ins:R:0 0 0 +B:2:Ins:R:1 0 0 +B:2:Ins:R:2 0 0 +B:2:Ins:R:3 0 0 +B:2:Ins:R:4 0 0 +B:2:Ins:R:5 0 0 +B:3:Ins:R:0 0 0 +B:3:Ins:R:1 0 0 +B:3:Ins:R:2 0 0 +B:3:Ins:R:3 0 0 +B:3:Ins:R:4 0 0 +B:3:Ins:R:5 0 0 +B:4:Ins:R:0 0 0 +B:4:Ins:R:1 0 0 +B:4:Ins:R:2 0 0 +B:4:Ins:R:3 0 0 +B:4:Ins:R:4 0 0 +B:4:Ins:R:5 0 0 +B:5:Ins:R:0 0 0 +B:5:Ins:R:1 0 0 +B:5:Ins:R:2 0 0 +B:5:Ins:R:3 0 0 +B:5:Ins:R:4 0 0 +B:5:Ins:R:5 0 0 +N:1:Del:C:0 22 0 +N:1:Del:C:1 14 0 +N:1:Del:C:2 8 0 +N:1:Del:C:3 13 0 +N:1:Del:C:4 2 0 +N:1:Del:C:5 1 0 +N:1:Del:T:0 27 0 +N:1:Del:T:1 25 0 +N:1:Del:T:2 38 0 +N:1:Del:T:3 21 0 +N:1:Del:T:4 13 0 +N:1:Del:T:5 19 0 +N:2:Del:R:0 5 0 +N:2:Del:R:1 2 0 +N:2:Del:R:2 0 0 +N:2:Del:R:3 0 0 +N:2:Del:R:4 0 0 +N:2:Del:R:5 3 0 +N:3:Del:R:0 0 0 +N:3:Del:R:1 2 0 +N:3:Del:R:2 1 0 +N:3:Del:R:3 0 0 +N:3:Del:R:4 0 0 +N:3:Del:R:5 0 0 +N:4:Del:R:0 2 0 +N:4:Del:R:1 2 0 +N:4:Del:R:2 0 0 +N:4:Del:R:3 0 0 +N:4:Del:R:4 0 0 +N:4:Del:R:5 0 0 +N:5:Del:R:0 1 0 +N:5:Del:R:1 3 0 +N:5:Del:R:2 6 0 +N:5:Del:R:3 1 0 +N:5:Del:R:4 3 0 +N:5:Del:R:5 2 0 +N:2:Del:M:1 8 0 +N:3:Del:M:1 2 0 +N:3:Del:M:2 2 0 +N:4:Del:M:1 1 0 +N:4:Del:M:2 2 0 +N:4:Del:M:3 0 0 +N:5:Del:M:1 1 0 +N:5:Del:M:2 2 0 +N:5:Del:M:3 2 0 +N:5:Del:M:4 0 0 +N:5:Del:M:5 2 0 +N:1:Ins:C:0 2 0 +N:1:Ins:C:1 2 0 +N:1:Ins:C:2 1 0 +N:1:Ins:C:3 0 0 +N:1:Ins:C:4 1 0 +N:1:Ins:C:5 1 0 +N:1:Ins:T:0 2 0 +N:1:Ins:T:1 11 0 +N:1:Ins:T:2 10 0 +N:1:Ins:T:3 7 0 +N:1:Ins:T:4 3 0 +N:1:Ins:T:5 20 0 +N:2:Ins:R:0 3 0 +N:2:Ins:R:1 8 0 +N:2:Ins:R:2 0 0 +N:2:Ins:R:3 0 0 +N:2:Ins:R:4 0 0 +N:2:Ins:R:5 0 0 +N:3:Ins:R:0 2 0 +N:3:Ins:R:1 0 0 +N:3:Ins:R:2 0 0 +N:3:Ins:R:3 0 0 +N:3:Ins:R:4 0 0 +N:3:Ins:R:5 0 0 +N:4:Ins:R:0 0 0 +N:4:Ins:R:1 0 0 +N:4:Ins:R:2 0 0 +N:4:Ins:R:3 0 0 +N:4:Ins:R:4 0 0 +N:4:Ins:R:5 0 0 +N:5:Ins:R:0 5 0 +N:5:Ins:R:1 8 0 +N:5:Ins:R:2 3 0 +N:5:Ins:R:3 3 0 +N:5:Ins:R:4 0 0 +N:5:Ins:R:5 0 0 +Q:1:Del:C:0 0 0 +Q:1:Del:C:1 0 0 +Q:1:Del:C:2 0 0 +Q:1:Del:C:3 0 0 +Q:1:Del:C:4 0 0 +Q:1:Del:C:5 0 0 +Q:1:Del:T:0 0 0 +Q:1:Del:T:1 0 0 +Q:1:Del:T:2 0 0 +Q:1:Del:T:3 0 0 +Q:1:Del:T:4 0 0 +Q:1:Del:T:5 0 0 +Q:2:Del:R:0 9 0 +Q:2:Del:R:1 4 0 +Q:2:Del:R:2 0 0 +Q:2:Del:R:3 0 0 +Q:2:Del:R:4 0 0 +Q:2:Del:R:5 2 0 +Q:3:Del:R:0 3 0 +Q:3:Del:R:1 1 0 +Q:3:Del:R:2 0 0 +Q:3:Del:R:3 2 0 +Q:3:Del:R:4 0 0 +Q:3:Del:R:5 0 0 +Q:4:Del:R:0 4 0 +Q:4:Del:R:1 2 0 +Q:4:Del:R:2 0 0 +Q:4:Del:R:3 0 0 +Q:4:Del:R:4 0 0 +Q:4:Del:R:5 0 0 +Q:5:Del:R:0 33 0 +Q:5:Del:R:1 0 0 +Q:5:Del:R:2 0 0 +Q:5:Del:R:3 0 0 +Q:5:Del:R:4 0 0 +Q:5:Del:R:5 0 0 +Q:2:Del:M:1 8 0 +Q:3:Del:M:1 1 0 +Q:3:Del:M:2 2 0 +Q:4:Del:M:1 4 0 +Q:4:Del:M:2 2 0 +Q:4:Del:M:3 3 0 +Q:5:Del:M:1 25 0 +Q:5:Del:M:2 18 0 +Q:5:Del:M:3 2 0 +Q:5:Del:M:4 3 0 +Q:5:Del:M:5 5 0 +Q:1:Ins:C:0 0 0 +Q:1:Ins:C:1 0 0 +Q:1:Ins:C:2 0 0 +Q:1:Ins:C:3 0 0 +Q:1:Ins:C:4 0 0 +Q:1:Ins:C:5 0 0 +Q:1:Ins:T:0 0 0 +Q:1:Ins:T:1 0 0 +Q:1:Ins:T:2 0 0 +Q:1:Ins:T:3 0 0 +Q:1:Ins:T:4 0 0 +Q:1:Ins:T:5 0 0 +Q:2:Ins:R:0 3 0 +Q:2:Ins:R:1 3 0 +Q:2:Ins:R:2 1 0 +Q:2:Ins:R:3 0 0 +Q:2:Ins:R:4 0 0 +Q:2:Ins:R:5 1 0 +Q:3:Ins:R:0 2 0 +Q:3:Ins:R:1 1 0 +Q:3:Ins:R:2 1 0 +Q:3:Ins:R:3 0 0 +Q:3:Ins:R:4 0 0 +Q:3:Ins:R:5 0 0 +Q:4:Ins:R:0 1 0 +Q:4:Ins:R:1 2 0 +Q:4:Ins:R:2 0 0 +Q:4:Ins:R:3 0 0 +Q:4:Ins:R:4 0 0 +Q:4:Ins:R:5 0 0 +Q:5:Ins:R:0 12 0 +Q:5:Ins:R:1 14 0 +Q:5:Ins:R:2 0 0 +Q:5:Ins:R:3 0 0 +Q:5:Ins:R:4 0 0 +Q:5:Ins:R:5 0 0 diff --git a/docs/assets/osf/3rm96.bin b/docs/assets/osf/3rm96.bin new file mode 100644 index 0000000..b136b69 --- /dev/null +++ b/docs/assets/osf/3rm96.bin @@ -0,0 +1,97 @@ +MutationType TutorialSample TutorialSample_snv +1:Del:C:0 37 0 +1:Del:C:1 29 0 +1:Del:C:2 20 0 +1:Del:C:3 15 0 +1:Del:C:4 5 0 +1:Del:C:5 3 0 +1:Del:T:0 54 0 +1:Del:T:1 41 0 +1:Del:T:2 58 0 +1:Del:T:3 39 0 +1:Del:T:4 25 0 +1:Del:T:5 31 0 +1:Ins:C:0 3 0 +1:Ins:C:1 3 0 +1:Ins:C:2 3 0 +1:Ins:C:3 1 0 +1:Ins:C:4 2 0 +1:Ins:C:5 3 0 +1:Ins:T:0 5 0 +1:Ins:T:1 24 0 +1:Ins:T:2 25 0 +1:Ins:T:3 15 0 +1:Ins:T:4 6 0 +1:Ins:T:5 40 0 +2:Del:R:0 17 0 +2:Del:R:1 8 0 +2:Del:R:2 1 0 +2:Del:R:3 0 0 +2:Del:R:4 0 0 +2:Del:R:5 6 0 +3:Del:R:0 4 0 +3:Del:R:1 5 0 +3:Del:R:2 1 0 +3:Del:R:3 2 0 +3:Del:R:4 0 0 +3:Del:R:5 0 0 +4:Del:R:0 8 0 +4:Del:R:1 4 0 +4:Del:R:2 0 0 +4:Del:R:3 0 0 +4:Del:R:4 0 0 +4:Del:R:5 0 0 +5:Del:R:0 35 0 +5:Del:R:1 9 0 +5:Del:R:2 8 0 +5:Del:R:3 4 0 +5:Del:R:4 5 0 +5:Del:R:5 4 0 +2:Ins:R:0 6 0 +2:Ins:R:1 13 0 +2:Ins:R:2 3 0 +2:Ins:R:3 0 0 +2:Ins:R:4 0 0 +2:Ins:R:5 1 0 +3:Ins:R:0 5 0 +3:Ins:R:1 1 0 +3:Ins:R:2 1 0 +3:Ins:R:3 0 0 +3:Ins:R:4 0 0 +3:Ins:R:5 0 0 +4:Ins:R:0 2 0 +4:Ins:R:1 3 0 +4:Ins:R:2 0 0 +4:Ins:R:3 0 0 +4:Ins:R:4 0 0 +4:Ins:R:5 0 0 +5:Ins:R:0 21 0 +5:Ins:R:1 26 0 +5:Ins:R:2 10 0 +5:Ins:R:3 7 0 +5:Ins:R:4 1 0 +5:Ins:R:5 2 0 +2:Del:M:1 19 0 +3:Del:M:1 3 0 +3:Del:M:2 6 0 +4:Del:M:1 5 0 +4:Del:M:2 4 0 +4:Del:M:3 3 0 +5:Del:M:1 26 0 +5:Del:M:2 20 0 +5:Del:M:3 4 0 +5:Del:M:4 4 0 +5:Del:M:5 8 0 +2:Ins:M:1 0 0 +3:Ins:M:1 0 0 +3:Ins:M:2 0 0 +4:Ins:M:1 0 0 +4:Ins:M:2 0 0 +4:Ins:M:3 0 0 +5:Ins:M:1 0 0 +5:Ins:M:2 0 0 +5:Ins:M:3 0 0 +5:Ins:M:4 0 0 +5:Ins:M:5 0 0 +complex 3 0 +non_matching 0 0 diff --git a/docs/assets/osf/43e76.bin b/docs/assets/osf/43e76.bin new file mode 100644 index 0000000..1cd936e --- /dev/null +++ b/docs/assets/osf/43e76.bin @@ -0,0 +1,1537 @@ +MutationType TutorialSample_snv +AA[C>A]AA 11 +AA[C>A]AC 4 +AA[C>A]AG 6 +AA[C>A]AT 10 +AA[C>A]CA 6 +AA[C>A]CC 2 +AA[C>A]CG 2 +AA[C>A]CT 4 +AA[C>A]GA 0 +AA[C>A]GC 0 +AA[C>A]GG 0 +AA[C>A]GT 0 +AA[C>A]TA 4 +AA[C>A]TC 2 +AA[C>A]TG 5 +AA[C>A]TT 2 +AA[C>G]AA 4 +AA[C>G]AC 3 +AA[C>G]AG 6 +AA[C>G]AT 3 +AA[C>G]CA 3 +AA[C>G]CC 4 +AA[C>G]CG 0 +AA[C>G]CT 13 +AA[C>G]GA 1 +AA[C>G]GC 0 +AA[C>G]GG 0 +AA[C>G]GT 1 +AA[C>G]TA 5 +AA[C>G]TC 7 +AA[C>G]TG 5 +AA[C>G]TT 10 +AA[C>T]AA 9 +AA[C>T]AC 4 +AA[C>T]AG 5 +AA[C>T]AT 10 +AA[C>T]CA 5 +AA[C>T]CC 3 +AA[C>T]CG 0 +AA[C>T]CT 3 +AA[C>T]GA 5 +AA[C>T]GC 4 +AA[C>T]GG 4 +AA[C>T]GT 5 +AA[C>T]TA 4 +AA[C>T]TC 6 +AA[C>T]TG 5 +AA[C>T]TT 3 +AA[T>A]AA 12 +AA[T>A]AC 5 +AA[T>A]AG 3 +AA[T>A]AT 8 +AA[T>A]CA 4 +AA[T>A]CC 3 +AA[T>A]CG 0 +AA[T>A]CT 4 +AA[T>A]GA 5 +AA[T>A]GC 4 +AA[T>A]GG 9 +AA[T>A]GT 4 +AA[T>A]TA 9 +AA[T>A]TC 1 +AA[T>A]TG 4 +AA[T>A]TT 20 +AA[T>C]AA 7 +AA[T>C]AC 6 +AA[T>C]AG 8 +AA[T>C]AT 11 +AA[T>C]CA 3 +AA[T>C]CC 2 +AA[T>C]CG 0 +AA[T>C]CT 1 +AA[T>C]GA 16 +AA[T>C]GC 0 +AA[T>C]GG 11 +AA[T>C]GT 11 +AA[T>C]TA 3 +AA[T>C]TC 6 +AA[T>C]TG 11 +AA[T>C]TT 12 +AA[T>G]AA 8 +AA[T>G]AC 1 +AA[T>G]AG 3 +AA[T>G]AT 4 +AA[T>G]CA 9 +AA[T>G]CC 1 +AA[T>G]CG 0 +AA[T>G]CT 4 +AA[T>G]GA 6 +AA[T>G]GC 2 +AA[T>G]GG 1 +AA[T>G]GT 7 +AA[T>G]TA 17 +AA[T>G]TC 4 +AA[T>G]TG 10 +AA[T>G]TT 21 +AC[C>A]AA 5 +AC[C>A]AC 4 +AC[C>A]AG 1 +AC[C>A]AT 8 +AC[C>A]CA 6 +AC[C>A]CC 1 +AC[C>A]CG 0 +AC[C>A]CT 2 +AC[C>A]GA 0 +AC[C>A]GC 1 +AC[C>A]GG 0 +AC[C>A]GT 0 +AC[C>A]TA 3 +AC[C>A]TC 7 +AC[C>A]TG 4 +AC[C>A]TT 5 +AC[C>G]AA 6 +AC[C>G]AC 3 +AC[C>G]AG 4 +AC[C>G]AT 4 +AC[C>G]CA 12 +AC[C>G]CC 6 +AC[C>G]CG 0 +AC[C>G]CT 7 +AC[C>G]GA 0 +AC[C>G]GC 0 +AC[C>G]GG 1 +AC[C>G]GT 0 +AC[C>G]TA 6 +AC[C>G]TC 5 +AC[C>G]TG 4 +AC[C>G]TT 6 +AC[C>T]AA 1 +AC[C>T]AC 3 +AC[C>T]AG 5 +AC[C>T]AT 9 +AC[C>T]CA 9 +AC[C>T]CC 4 +AC[C>T]CG 2 +AC[C>T]CT 9 +AC[C>T]GA 1 +AC[C>T]GC 2 +AC[C>T]GG 1 +AC[C>T]GT 3 +AC[C>T]TA 8 +AC[C>T]TC 5 +AC[C>T]TG 9 +AC[C>T]TT 7 +AC[T>A]AA 3 +AC[T>A]AC 2 +AC[T>A]AG 1 +AC[T>A]AT 4 +AC[T>A]CA 4 +AC[T>A]CC 3 +AC[T>A]CG 0 +AC[T>A]CT 4 +AC[T>A]GA 3 +AC[T>A]GC 4 +AC[T>A]GG 4 +AC[T>A]GT 8 +AC[T>A]TA 2 +AC[T>A]TC 5 +AC[T>A]TG 2 +AC[T>A]TT 6 +AC[T>C]AA 5 +AC[T>C]AC 4 +AC[T>C]AG 4 +AC[T>C]AT 3 +AC[T>C]CA 4 +AC[T>C]CC 2 +AC[T>C]CG 1 +AC[T>C]CT 6 +AC[T>C]GA 7 +AC[T>C]GC 5 +AC[T>C]GG 4 +AC[T>C]GT 11 +AC[T>C]TA 5 +AC[T>C]TC 3 +AC[T>C]TG 5 +AC[T>C]TT 6 +AC[T>G]AA 1 +AC[T>G]AC 1 +AC[T>G]AG 0 +AC[T>G]AT 1 +AC[T>G]CA 2 +AC[T>G]CC 2 +AC[T>G]CG 0 +AC[T>G]CT 4 +AC[T>G]GA 6 +AC[T>G]GC 2 +AC[T>G]GG 2 +AC[T>G]GT 1 +AC[T>G]TA 2 +AC[T>G]TC 3 +AC[T>G]TG 2 +AC[T>G]TT 3 +AG[C>A]AA 2 +AG[C>A]AC 6 +AG[C>A]AG 3 +AG[C>A]AT 2 +AG[C>A]CA 3 +AG[C>A]CC 2 +AG[C>A]CG 0 +AG[C>A]CT 8 +AG[C>A]GA 0 +AG[C>A]GC 1 +AG[C>A]GG 1 +AG[C>A]GT 1 +AG[C>A]TA 3 +AG[C>A]TC 3 +AG[C>A]TG 6 +AG[C>A]TT 1 +AG[C>G]AA 5 +AG[C>G]AC 1 +AG[C>G]AG 2 +AG[C>G]AT 4 +AG[C>G]CA 2 +AG[C>G]CC 3 +AG[C>G]CG 0 +AG[C>G]CT 7 +AG[C>G]GA 0 +AG[C>G]GC 1 +AG[C>G]GG 0 +AG[C>G]GT 0 +AG[C>G]TA 7 +AG[C>G]TC 2 +AG[C>G]TG 1 +AG[C>G]TT 6 +AG[C>T]AA 8 +AG[C>T]AC 6 +AG[C>T]AG 10 +AG[C>T]AT 1 +AG[C>T]CA 4 +AG[C>T]CC 7 +AG[C>T]CG 0 +AG[C>T]CT 10 +AG[C>T]GA 4 +AG[C>T]GC 3 +AG[C>T]GG 1 +AG[C>T]GT 1 +AG[C>T]TA 4 +AG[C>T]TC 9 +AG[C>T]TG 3 +AG[C>T]TT 5 +AG[T>A]AA 1 +AG[T>A]AC 2 +AG[T>A]AG 6 +AG[T>A]AT 5 +AG[T>A]CA 2 +AG[T>A]CC 3 +AG[T>A]CG 0 +AG[T>A]CT 2 +AG[T>A]GA 5 +AG[T>A]GC 1 +AG[T>A]GG 4 +AG[T>A]GT 3 +AG[T>A]TA 2 +AG[T>A]TC 2 +AG[T>A]TG 4 +AG[T>A]TT 3 +AG[T>C]AA 2 +AG[T>C]AC 3 +AG[T>C]AG 4 +AG[T>C]AT 8 +AG[T>C]CA 3 +AG[T>C]CC 2 +AG[T>C]CG 0 +AG[T>C]CT 1 +AG[T>C]GA 10 +AG[T>C]GC 7 +AG[T>C]GG 7 +AG[T>C]GT 6 +AG[T>C]TA 3 +AG[T>C]TC 3 +AG[T>C]TG 7 +AG[T>C]TT 9 +AG[T>G]AA 2 +AG[T>G]AC 1 +AG[T>G]AG 1 +AG[T>G]AT 1 +AG[T>G]CA 2 +AG[T>G]CC 2 +AG[T>G]CG 0 +AG[T>G]CT 3 +AG[T>G]GA 0 +AG[T>G]GC 2 +AG[T>G]GG 0 +AG[T>G]GT 1 +AG[T>G]TA 1 +AG[T>G]TC 2 +AG[T>G]TG 1 +AG[T>G]TT 2 +AT[C>A]AA 12 +AT[C>A]AC 14 +AT[C>A]AG 2 +AT[C>A]AT 9 +AT[C>A]CA 4 +AT[C>A]CC 7 +AT[C>A]CG 2 +AT[C>A]CT 10 +AT[C>A]GA 1 +AT[C>A]GC 1 +AT[C>A]GG 0 +AT[C>A]GT 2 +AT[C>A]TA 3 +AT[C>A]TC 7 +AT[C>A]TG 4 +AT[C>A]TT 16 +AT[C>G]AA 7 +AT[C>G]AC 3 +AT[C>G]AG 4 +AT[C>G]AT 5 +AT[C>G]CA 7 +AT[C>G]CC 5 +AT[C>G]CG 0 +AT[C>G]CT 4 +AT[C>G]GA 0 +AT[C>G]GC 3 +AT[C>G]GG 0 +AT[C>G]GT 0 +AT[C>G]TA 9 +AT[C>G]TC 8 +AT[C>G]TG 2 +AT[C>G]TT 4 +AT[C>T]AA 6 +AT[C>T]AC 10 +AT[C>T]AG 7 +AT[C>T]AT 8 +AT[C>T]CA 6 +AT[C>T]CC 2 +AT[C>T]CG 0 +AT[C>T]CT 7 +AT[C>T]GA 1 +AT[C>T]GC 2 +AT[C>T]GG 1 +AT[C>T]GT 4 +AT[C>T]TA 4 +AT[C>T]TC 2 +AT[C>T]TG 5 +AT[C>T]TT 1 +AT[T>A]AA 7 +AT[T>A]AC 5 +AT[T>A]AG 5 +AT[T>A]AT 14 +AT[T>A]CA 7 +AT[T>A]CC 9 +AT[T>A]CG 0 +AT[T>A]CT 14 +AT[T>A]GA 3 +AT[T>A]GC 3 +AT[T>A]GG 4 +AT[T>A]GT 5 +AT[T>A]TA 17 +AT[T>A]TC 7 +AT[T>A]TG 12 +AT[T>A]TT 31 +AT[T>C]AA 4 +AT[T>C]AC 5 +AT[T>C]AG 3 +AT[T>C]AT 10 +AT[T>C]CA 0 +AT[T>C]CC 3 +AT[T>C]CG 0 +AT[T>C]CT 2 +AT[T>C]GA 0 +AT[T>C]GC 3 +AT[T>C]GG 2 +AT[T>C]GT 1 +AT[T>C]TA 3 +AT[T>C]TC 3 +AT[T>C]TG 3 +AT[T>C]TT 1 +AT[T>G]AA 7 +AT[T>G]AC 2 +AT[T>G]AG 3 +AT[T>G]AT 5 +AT[T>G]CA 8 +AT[T>G]CC 6 +AT[T>G]CG 1 +AT[T>G]CT 5 +AT[T>G]GA 3 +AT[T>G]GC 2 +AT[T>G]GG 1 +AT[T>G]GT 3 +AT[T>G]TA 16 +AT[T>G]TC 5 +AT[T>G]TG 3 +AT[T>G]TT 14 +CA[C>A]AA 6 +CA[C>A]AC 0 +CA[C>A]AG 2 +CA[C>A]AT 9 +CA[C>A]CA 3 +CA[C>A]CC 1 +CA[C>A]CG 1 +CA[C>A]CT 5 +CA[C>A]GA 3 +CA[C>A]GC 1 +CA[C>A]GG 2 +CA[C>A]GT 1 +CA[C>A]TA 2 +CA[C>A]TC 3 +CA[C>A]TG 7 +CA[C>A]TT 2 +CA[C>G]AA 4 +CA[C>G]AC 1 +CA[C>G]AG 1 +CA[C>G]AT 1 +CA[C>G]CA 7 +CA[C>G]CC 2 +CA[C>G]CG 1 +CA[C>G]CT 4 +CA[C>G]GA 0 +CA[C>G]GC 3 +CA[C>G]GG 1 +CA[C>G]GT 1 +CA[C>G]TA 6 +CA[C>G]TC 3 +CA[C>G]TG 0 +CA[C>G]TT 4 +CA[C>T]AA 8 +CA[C>T]AC 8 +CA[C>T]AG 4 +CA[C>T]AT 8 +CA[C>T]CA 3 +CA[C>T]CC 9 +CA[C>T]CG 0 +CA[C>T]CT 6 +CA[C>T]GA 6 +CA[C>T]GC 6 +CA[C>T]GG 6 +CA[C>T]GT 7 +CA[C>T]TA 7 +CA[C>T]TC 4 +CA[C>T]TG 7 +CA[C>T]TT 4 +CA[T>A]AA 4 +CA[T>A]AC 3 +CA[T>A]AG 3 +CA[T>A]AT 5 +CA[T>A]CA 2 +CA[T>A]CC 3 +CA[T>A]CG 0 +CA[T>A]CT 4 +CA[T>A]GA 4 +CA[T>A]GC 7 +CA[T>A]GG 3 +CA[T>A]GT 7 +CA[T>A]TA 1 +CA[T>A]TC 4 +CA[T>A]TG 7 +CA[T>A]TT 11 +CA[T>C]AA 4 +CA[T>C]AC 8 +CA[T>C]AG 9 +CA[T>C]AT 9 +CA[T>C]CA 4 +CA[T>C]CC 6 +CA[T>C]CG 0 +CA[T>C]CT 4 +CA[T>C]GA 5 +CA[T>C]GC 7 +CA[T>C]GG 12 +CA[T>C]GT 11 +CA[T>C]TA 3 +CA[T>C]TC 7 +CA[T>C]TG 13 +CA[T>C]TT 6 +CA[T>G]AA 5 +CA[T>G]AC 1 +CA[T>G]AG 2 +CA[T>G]AT 2 +CA[T>G]CA 4 +CA[T>G]CC 1 +CA[T>G]CG 1 +CA[T>G]CT 4 +CA[T>G]GA 5 +CA[T>G]GC 1 +CA[T>G]GG 2 +CA[T>G]GT 2 +CA[T>G]TA 6 +CA[T>G]TC 2 +CA[T>G]TG 4 +CA[T>G]TT 5 +CC[C>A]AA 4 +CC[C>A]AC 4 +CC[C>A]AG 10 +CC[C>A]AT 5 +CC[C>A]CA 6 +CC[C>A]CC 3 +CC[C>A]CG 1 +CC[C>A]CT 4 +CC[C>A]GA 0 +CC[C>A]GC 1 +CC[C>A]GG 1 +CC[C>A]GT 2 +CC[C>A]TA 1 +CC[C>A]TC 0 +CC[C>A]TG 4 +CC[C>A]TT 7 +CC[C>G]AA 7 +CC[C>G]AC 2 +CC[C>G]AG 4 +CC[C>G]AT 1 +CC[C>G]CA 3 +CC[C>G]CC 7 +CC[C>G]CG 2 +CC[C>G]CT 7 +CC[C>G]GA 2 +CC[C>G]GC 2 +CC[C>G]GG 3 +CC[C>G]GT 3 +CC[C>G]TA 3 +CC[C>G]TC 7 +CC[C>G]TG 7 +CC[C>G]TT 11 +CC[C>T]AA 3 +CC[C>T]AC 0 +CC[C>T]AG 6 +CC[C>T]AT 5 +CC[C>T]CA 4 +CC[C>T]CC 7 +CC[C>T]CG 2 +CC[C>T]CT 4 +CC[C>T]GA 4 +CC[C>T]GC 3 +CC[C>T]GG 13 +CC[C>T]GT 4 +CC[C>T]TA 2 +CC[C>T]TC 2 +CC[C>T]TG 6 +CC[C>T]TT 2 +CC[T>A]AA 3 +CC[T>A]AC 2 +CC[T>A]AG 2 +CC[T>A]AT 1 +CC[T>A]CA 5 +CC[T>A]CC 2 +CC[T>A]CG 0 +CC[T>A]CT 6 +CC[T>A]GA 2 +CC[T>A]GC 5 +CC[T>A]GG 13 +CC[T>A]GT 5 +CC[T>A]TA 1 +CC[T>A]TC 5 +CC[T>A]TG 3 +CC[T>A]TT 4 +CC[T>C]AA 2 +CC[T>C]AC 3 +CC[T>C]AG 5 +CC[T>C]AT 2 +CC[T>C]CA 4 +CC[T>C]CC 2 +CC[T>C]CG 1 +CC[T>C]CT 4 +CC[T>C]GA 2 +CC[T>C]GC 5 +CC[T>C]GG 11 +CC[T>C]GT 3 +CC[T>C]TA 2 +CC[T>C]TC 4 +CC[T>C]TG 4 +CC[T>C]TT 2 +CC[T>G]AA 2 +CC[T>G]AC 2 +CC[T>G]AG 0 +CC[T>G]AT 1 +CC[T>G]CA 2 +CC[T>G]CC 4 +CC[T>G]CG 2 +CC[T>G]CT 6 +CC[T>G]GA 0 +CC[T>G]GC 3 +CC[T>G]GG 5 +CC[T>G]GT 1 +CC[T>G]TA 3 +CC[T>G]TC 4 +CC[T>G]TG 2 +CC[T>G]TT 3 +CG[C>A]AA 0 +CG[C>A]AC 1 +CG[C>A]AG 0 +CG[C>A]AT 2 +CG[C>A]CA 0 +CG[C>A]CC 1 +CG[C>A]CG 0 +CG[C>A]CT 1 +CG[C>A]GA 0 +CG[C>A]GC 0 +CG[C>A]GG 0 +CG[C>A]GT 0 +CG[C>A]TA 0 +CG[C>A]TC 1 +CG[C>A]TG 1 +CG[C>A]TT 0 +CG[C>G]AA 0 +CG[C>G]AC 0 +CG[C>G]AG 1 +CG[C>G]AT 1 +CG[C>G]CA 1 +CG[C>G]CC 0 +CG[C>G]CG 0 +CG[C>G]CT 0 +CG[C>G]GA 0 +CG[C>G]GC 1 +CG[C>G]GG 1 +CG[C>G]GT 1 +CG[C>G]TA 1 +CG[C>G]TC 1 +CG[C>G]TG 0 +CG[C>G]TT 0 +CG[C>T]AA 2 +CG[C>T]AC 4 +CG[C>T]AG 1 +CG[C>T]AT 0 +CG[C>T]CA 0 +CG[C>T]CC 2 +CG[C>T]CG 0 +CG[C>T]CT 0 +CG[C>T]GA 2 +CG[C>T]GC 3 +CG[C>T]GG 2 +CG[C>T]GT 0 +CG[C>T]TA 0 +CG[C>T]TC 0 +CG[C>T]TG 2 +CG[C>T]TT 0 +CG[T>A]AA 0 +CG[T>A]AC 0 +CG[T>A]AG 0 +CG[T>A]AT 0 +CG[T>A]CA 0 +CG[T>A]CC 0 +CG[T>A]CG 0 +CG[T>A]CT 2 +CG[T>A]GA 0 +CG[T>A]GC 1 +CG[T>A]GG 0 +CG[T>A]GT 1 +CG[T>A]TA 0 +CG[T>A]TC 0 +CG[T>A]TG 1 +CG[T>A]TT 2 +CG[T>C]AA 0 +CG[T>C]AC 0 +CG[T>C]AG 0 +CG[T>C]AT 0 +CG[T>C]CA 0 +CG[T>C]CC 1 +CG[T>C]CG 0 +CG[T>C]CT 2 +CG[T>C]GA 0 +CG[T>C]GC 1 +CG[T>C]GG 1 +CG[T>C]GT 0 +CG[T>C]TA 0 +CG[T>C]TC 0 +CG[T>C]TG 1 +CG[T>C]TT 2 +CG[T>G]AA 0 +CG[T>G]AC 0 +CG[T>G]AG 0 +CG[T>G]AT 0 +CG[T>G]CA 0 +CG[T>G]CC 0 +CG[T>G]CG 0 +CG[T>G]CT 0 +CG[T>G]GA 0 +CG[T>G]GC 1 +CG[T>G]GG 0 +CG[T>G]GT 0 +CG[T>G]TA 0 +CG[T>G]TC 0 +CG[T>G]TG 0 +CG[T>G]TT 0 +CT[C>A]AA 5 +CT[C>A]AC 8 +CT[C>A]AG 6 +CT[C>A]AT 7 +CT[C>A]CA 8 +CT[C>A]CC 8 +CT[C>A]CG 0 +CT[C>A]CT 11 +CT[C>A]GA 4 +CT[C>A]GC 0 +CT[C>A]GG 0 +CT[C>A]GT 1 +CT[C>A]TA 3 +CT[C>A]TC 3 +CT[C>A]TG 6 +CT[C>A]TT 5 +CT[C>G]AA 5 +CT[C>G]AC 1 +CT[C>G]AG 8 +CT[C>G]AT 10 +CT[C>G]CA 7 +CT[C>G]CC 5 +CT[C>G]CG 1 +CT[C>G]CT 10 +CT[C>G]GA 0 +CT[C>G]GC 1 +CT[C>G]GG 2 +CT[C>G]GT 0 +CT[C>G]TA 11 +CT[C>G]TC 11 +CT[C>G]TG 8 +CT[C>G]TT 10 +CT[C>T]AA 13 +CT[C>T]AC 7 +CT[C>T]AG 11 +CT[C>T]AT 10 +CT[C>T]CA 3 +CT[C>T]CC 3 +CT[C>T]CG 2 +CT[C>T]CT 15 +CT[C>T]GA 4 +CT[C>T]GC 0 +CT[C>T]GG 6 +CT[C>T]GT 1 +CT[C>T]TA 1 +CT[C>T]TC 8 +CT[C>T]TG 2 +CT[C>T]TT 4 +CT[T>A]AA 4 +CT[T>A]AC 2 +CT[T>A]AG 2 +CT[T>A]AT 4 +CT[T>A]CA 6 +CT[T>A]CC 6 +CT[T>A]CG 1 +CT[T>A]CT 3 +CT[T>A]GA 4 +CT[T>A]GC 2 +CT[T>A]GG 1 +CT[T>A]GT 2 +CT[T>A]TA 2 +CT[T>A]TC 2 +CT[T>A]TG 5 +CT[T>A]TT 6 +CT[T>C]AA 3 +CT[T>C]AC 2 +CT[T>C]AG 5 +CT[T>C]AT 8 +CT[T>C]CA 3 +CT[T>C]CC 4 +CT[T>C]CG 0 +CT[T>C]CT 7 +CT[T>C]GA 1 +CT[T>C]GC 4 +CT[T>C]GG 5 +CT[T>C]GT 3 +CT[T>C]TA 4 +CT[T>C]TC 6 +CT[T>C]TG 4 +CT[T>C]TT 8 +CT[T>G]AA 5 +CT[T>G]AC 0 +CT[T>G]AG 0 +CT[T>G]AT 3 +CT[T>G]CA 3 +CT[T>G]CC 4 +CT[T>G]CG 0 +CT[T>G]CT 4 +CT[T>G]GA 4 +CT[T>G]GC 2 +CT[T>G]GG 3 +CT[T>G]GT 3 +CT[T>G]TA 10 +CT[T>G]TC 4 +CT[T>G]TG 3 +CT[T>G]TT 9 +GA[C>A]AA 7 +GA[C>A]AC 6 +GA[C>A]AG 1 +GA[C>A]AT 0 +GA[C>A]CA 4 +GA[C>A]CC 2 +GA[C>A]CG 2 +GA[C>A]CT 3 +GA[C>A]GA 0 +GA[C>A]GC 0 +GA[C>A]GG 2 +GA[C>A]GT 1 +GA[C>A]TA 2 +GA[C>A]TC 2 +GA[C>A]TG 4 +GA[C>A]TT 2 +GA[C>G]AA 4 +GA[C>G]AC 0 +GA[C>G]AG 4 +GA[C>G]AT 3 +GA[C>G]CA 4 +GA[C>G]CC 4 +GA[C>G]CG 0 +GA[C>G]CT 2 +GA[C>G]GA 0 +GA[C>G]GC 5 +GA[C>G]GG 2 +GA[C>G]GT 1 +GA[C>G]TA 4 +GA[C>G]TC 2 +GA[C>G]TG 4 +GA[C>G]TT 1 +GA[C>T]AA 5 +GA[C>T]AC 1 +GA[C>T]AG 5 +GA[C>T]AT 8 +GA[C>T]CA 3 +GA[C>T]CC 4 +GA[C>T]CG 0 +GA[C>T]CT 2 +GA[C>T]GA 9 +GA[C>T]GC 6 +GA[C>T]GG 4 +GA[C>T]GT 2 +GA[C>T]TA 2 +GA[C>T]TC 0 +GA[C>T]TG 5 +GA[C>T]TT 4 +GA[T>A]AA 1 +GA[T>A]AC 3 +GA[T>A]AG 2 +GA[T>A]AT 1 +GA[T>A]CA 4 +GA[T>A]CC 2 +GA[T>A]CG 0 +GA[T>A]CT 2 +GA[T>A]GA 3 +GA[T>A]GC 2 +GA[T>A]GG 3 +GA[T>A]GT 4 +GA[T>A]TA 6 +GA[T>A]TC 3 +GA[T>A]TG 2 +GA[T>A]TT 5 +GA[T>C]AA 2 +GA[T>C]AC 6 +GA[T>C]AG 7 +GA[T>C]AT 6 +GA[T>C]CA 2 +GA[T>C]CC 0 +GA[T>C]CG 0 +GA[T>C]CT 2 +GA[T>C]GA 1 +GA[T>C]GC 3 +GA[T>C]GG 11 +GA[T>C]GT 4 +GA[T>C]TA 6 +GA[T>C]TC 4 +GA[T>C]TG 4 +GA[T>C]TT 6 +GA[T>G]AA 4 +GA[T>G]AC 1 +GA[T>G]AG 0 +GA[T>G]AT 2 +GA[T>G]CA 1 +GA[T>G]CC 2 +GA[T>G]CG 0 +GA[T>G]CT 0 +GA[T>G]GA 3 +GA[T>G]GC 1 +GA[T>G]GG 0 +GA[T>G]GT 2 +GA[T>G]TA 0 +GA[T>G]TC 6 +GA[T>G]TG 1 +GA[T>G]TT 2 +GC[C>A]AA 3 +GC[C>A]AC 2 +GC[C>A]AG 0 +GC[C>A]AT 5 +GC[C>A]CA 2 +GC[C>A]CC 5 +GC[C>A]CG 1 +GC[C>A]CT 6 +GC[C>A]GA 1 +GC[C>A]GC 1 +GC[C>A]GG 1 +GC[C>A]GT 0 +GC[C>A]TA 3 +GC[C>A]TC 3 +GC[C>A]TG 5 +GC[C>A]TT 0 +GC[C>G]AA 4 +GC[C>G]AC 2 +GC[C>G]AG 0 +GC[C>G]AT 3 +GC[C>G]CA 2 +GC[C>G]CC 3 +GC[C>G]CG 1 +GC[C>G]CT 4 +GC[C>G]GA 3 +GC[C>G]GC 0 +GC[C>G]GG 2 +GC[C>G]GT 0 +GC[C>G]TA 2 +GC[C>G]TC 6 +GC[C>G]TG 7 +GC[C>G]TT 6 +GC[C>T]AA 3 +GC[C>T]AC 3 +GC[C>T]AG 5 +GC[C>T]AT 5 +GC[C>T]CA 6 +GC[C>T]CC 4 +GC[C>T]CG 2 +GC[C>T]CT 10 +GC[C>T]GA 5 +GC[C>T]GC 1 +GC[C>T]GG 8 +GC[C>T]GT 5 +GC[C>T]TA 1 +GC[C>T]TC 6 +GC[C>T]TG 3 +GC[C>T]TT 5 +GC[T>A]AA 3 +GC[T>A]AC 0 +GC[T>A]AG 1 +GC[T>A]AT 1 +GC[T>A]CA 6 +GC[T>A]CC 0 +GC[T>A]CG 0 +GC[T>A]CT 3 +GC[T>A]GA 8 +GC[T>A]GC 5 +GC[T>A]GG 5 +GC[T>A]GT 4 +GC[T>A]TA 0 +GC[T>A]TC 2 +GC[T>A]TG 6 +GC[T>A]TT 2 +GC[T>C]AA 4 +GC[T>C]AC 4 +GC[T>C]AG 2 +GC[T>C]AT 1 +GC[T>C]CA 1 +GC[T>C]CC 1 +GC[T>C]CG 1 +GC[T>C]CT 4 +GC[T>C]GA 6 +GC[T>C]GC 1 +GC[T>C]GG 5 +GC[T>C]GT 1 +GC[T>C]TA 2 +GC[T>C]TC 1 +GC[T>C]TG 4 +GC[T>C]TT 7 +GC[T>G]AA 3 +GC[T>G]AC 1 +GC[T>G]AG 2 +GC[T>G]AT 1 +GC[T>G]CA 4 +GC[T>G]CC 1 +GC[T>G]CG 0 +GC[T>G]CT 4 +GC[T>G]GA 4 +GC[T>G]GC 1 +GC[T>G]GG 2 +GC[T>G]GT 0 +GC[T>G]TA 0 +GC[T>G]TC 0 +GC[T>G]TG 2 +GC[T>G]TT 0 +GG[C>A]AA 4 +GG[C>A]AC 3 +GG[C>A]AG 3 +GG[C>A]AT 4 +GG[C>A]CA 7 +GG[C>A]CC 2 +GG[C>A]CG 0 +GG[C>A]CT 3 +GG[C>A]GA 1 +GG[C>A]GC 2 +GG[C>A]GG 3 +GG[C>A]GT 3 +GG[C>A]TA 2 +GG[C>A]TC 6 +GG[C>A]TG 2 +GG[C>A]TT 1 +GG[C>G]AA 2 +GG[C>G]AC 1 +GG[C>G]AG 8 +GG[C>G]AT 0 +GG[C>G]CA 0 +GG[C>G]CC 3 +GG[C>G]CG 1 +GG[C>G]CT 1 +GG[C>G]GA 1 +GG[C>G]GC 2 +GG[C>G]GG 2 +GG[C>G]GT 1 +GG[C>G]TA 3 +GG[C>G]TC 3 +GG[C>G]TG 0 +GG[C>G]TT 0 +GG[C>T]AA 7 +GG[C>T]AC 3 +GG[C>T]AG 8 +GG[C>T]AT 3 +GG[C>T]CA 5 +GG[C>T]CC 8 +GG[C>T]CG 2 +GG[C>T]CT 7 +GG[C>T]GA 8 +GG[C>T]GC 9 +GG[C>T]GG 13 +GG[C>T]GT 5 +GG[C>T]TA 2 +GG[C>T]TC 4 +GG[C>T]TG 11 +GG[C>T]TT 4 +GG[T>A]AA 3 +GG[T>A]AC 1 +GG[T>A]AG 2 +GG[T>A]AT 0 +GG[T>A]CA 1 +GG[T>A]CC 2 +GG[T>A]CG 0 +GG[T>A]CT 3 +GG[T>A]GA 2 +GG[T>A]GC 2 +GG[T>A]GG 4 +GG[T>A]GT 3 +GG[T>A]TA 1 +GG[T>A]TC 1 +GG[T>A]TG 2 +GG[T>A]TT 2 +GG[T>C]AA 2 +GG[T>C]AC 2 +GG[T>C]AG 3 +GG[T>C]AT 5 +GG[T>C]CA 2 +GG[T>C]CC 1 +GG[T>C]CG 0 +GG[T>C]CT 6 +GG[T>C]GA 4 +GG[T>C]GC 4 +GG[T>C]GG 7 +GG[T>C]GT 4 +GG[T>C]TA 1 +GG[T>C]TC 1 +GG[T>C]TG 4 +GG[T>C]TT 2 +GG[T>G]AA 1 +GG[T>G]AC 0 +GG[T>G]AG 0 +GG[T>G]AT 1 +GG[T>G]CA 1 +GG[T>G]CC 0 +GG[T>G]CG 1 +GG[T>G]CT 1 +GG[T>G]GA 2 +GG[T>G]GC 0 +GG[T>G]GG 0 +GG[T>G]GT 1 +GG[T>G]TA 2 +GG[T>G]TC 0 +GG[T>G]TG 0 +GG[T>G]TT 5 +GT[C>A]AA 6 +GT[C>A]AC 5 +GT[C>A]AG 5 +GT[C>A]AT 8 +GT[C>A]CA 8 +GT[C>A]CC 1 +GT[C>A]CG 0 +GT[C>A]CT 4 +GT[C>A]GA 0 +GT[C>A]GC 1 +GT[C>A]GG 2 +GT[C>A]GT 0 +GT[C>A]TA 5 +GT[C>A]TC 2 +GT[C>A]TG 2 +GT[C>A]TT 6 +GT[C>G]AA 2 +GT[C>G]AC 2 +GT[C>G]AG 6 +GT[C>G]AT 2 +GT[C>G]CA 3 +GT[C>G]CC 0 +GT[C>G]CG 0 +GT[C>G]CT 5 +GT[C>G]GA 1 +GT[C>G]GC 0 +GT[C>G]GG 1 +GT[C>G]GT 0 +GT[C>G]TA 4 +GT[C>G]TC 5 +GT[C>G]TG 6 +GT[C>G]TT 5 +GT[C>T]AA 7 +GT[C>T]AC 4 +GT[C>T]AG 2 +GT[C>T]AT 7 +GT[C>T]CA 1 +GT[C>T]CC 8 +GT[C>T]CG 0 +GT[C>T]CT 4 +GT[C>T]GA 0 +GT[C>T]GC 2 +GT[C>T]GG 3 +GT[C>T]GT 6 +GT[C>T]TA 0 +GT[C>T]TC 7 +GT[C>T]TG 2 +GT[C>T]TT 3 +GT[T>A]AA 2 +GT[T>A]AC 1 +GT[T>A]AG 4 +GT[T>A]AT 4 +GT[T>A]CA 3 +GT[T>A]CC 3 +GT[T>A]CG 1 +GT[T>A]CT 1 +GT[T>A]GA 0 +GT[T>A]GC 3 +GT[T>A]GG 1 +GT[T>A]GT 0 +GT[T>A]TA 1 +GT[T>A]TC 1 +GT[T>A]TG 2 +GT[T>A]TT 8 +GT[T>C]AA 2 +GT[T>C]AC 5 +GT[T>C]AG 2 +GT[T>C]AT 2 +GT[T>C]CA 0 +GT[T>C]CC 1 +GT[T>C]CG 0 +GT[T>C]CT 1 +GT[T>C]GA 3 +GT[T>C]GC 5 +GT[T>C]GG 1 +GT[T>C]GT 2 +GT[T>C]TA 1 +GT[T>C]TC 5 +GT[T>C]TG 2 +GT[T>C]TT 3 +GT[T>G]AA 0 +GT[T>G]AC 0 +GT[T>G]AG 3 +GT[T>G]AT 1 +GT[T>G]CA 3 +GT[T>G]CC 1 +GT[T>G]CG 0 +GT[T>G]CT 1 +GT[T>G]GA 0 +GT[T>G]GC 2 +GT[T>G]GG 0 +GT[T>G]GT 1 +GT[T>G]TA 6 +GT[T>G]TC 6 +GT[T>G]TG 4 +GT[T>G]TT 9 +TA[C>A]AA 5 +TA[C>A]AC 1 +TA[C>A]AG 6 +TA[C>A]AT 2 +TA[C>A]CA 1 +TA[C>A]CC 4 +TA[C>A]CG 1 +TA[C>A]CT 4 +TA[C>A]GA 1 +TA[C>A]GC 0 +TA[C>A]GG 1 +TA[C>A]GT 0 +TA[C>A]TA 5 +TA[C>A]TC 0 +TA[C>A]TG 4 +TA[C>A]TT 8 +TA[C>G]AA 3 +TA[C>G]AC 2 +TA[C>G]AG 2 +TA[C>G]AT 0 +TA[C>G]CA 3 +TA[C>G]CC 3 +TA[C>G]CG 1 +TA[C>G]CT 1 +TA[C>G]GA 1 +TA[C>G]GC 1 +TA[C>G]GG 0 +TA[C>G]GT 3 +TA[C>G]TA 1 +TA[C>G]TC 2 +TA[C>G]TG 6 +TA[C>G]TT 7 +TA[C>T]AA 4 +TA[C>T]AC 3 +TA[C>T]AG 4 +TA[C>T]AT 8 +TA[C>T]CA 2 +TA[C>T]CC 4 +TA[C>T]CG 0 +TA[C>T]CT 0 +TA[C>T]GA 5 +TA[C>T]GC 1 +TA[C>T]GG 5 +TA[C>T]GT 5 +TA[C>T]TA 6 +TA[C>T]TC 4 +TA[C>T]TG 6 +TA[C>T]TT 3 +TA[T>A]AA 8 +TA[T>A]AC 4 +TA[T>A]AG 1 +TA[T>A]AT 1 +TA[T>A]CA 2 +TA[T>A]CC 1 +TA[T>A]CG 0 +TA[T>A]CT 2 +TA[T>A]GA 2 +TA[T>A]GC 3 +TA[T>A]GG 0 +TA[T>A]GT 6 +TA[T>A]TA 3 +TA[T>A]TC 4 +TA[T>A]TG 3 +TA[T>A]TT 5 +TA[T>C]AA 9 +TA[T>C]AC 3 +TA[T>C]AG 14 +TA[T>C]AT 12 +TA[T>C]CA 3 +TA[T>C]CC 5 +TA[T>C]CG 0 +TA[T>C]CT 7 +TA[T>C]GA 4 +TA[T>C]GC 2 +TA[T>C]GG 6 +TA[T>C]GT 8 +TA[T>C]TA 6 +TA[T>C]TC 2 +TA[T>C]TG 12 +TA[T>C]TT 19 +TA[T>G]AA 3 +TA[T>G]AC 3 +TA[T>G]AG 0 +TA[T>G]AT 0 +TA[T>G]CA 2 +TA[T>G]CC 1 +TA[T>G]CG 0 +TA[T>G]CT 3 +TA[T>G]GA 2 +TA[T>G]GC 0 +TA[T>G]GG 2 +TA[T>G]GT 0 +TA[T>G]TA 6 +TA[T>G]TC 2 +TA[T>G]TG 3 +TA[T>G]TT 9 +TC[C>A]AA 4 +TC[C>A]AC 3 +TC[C>A]AG 4 +TC[C>A]AT 0 +TC[C>A]CA 4 +TC[C>A]CC 2 +TC[C>A]CG 2 +TC[C>A]CT 4 +TC[C>A]GA 0 +TC[C>A]GC 0 +TC[C>A]GG 1 +TC[C>A]GT 1 +TC[C>A]TA 3 +TC[C>A]TC 5 +TC[C>A]TG 2 +TC[C>A]TT 2 +TC[C>G]AA 2 +TC[C>G]AC 1 +TC[C>G]AG 0 +TC[C>G]AT 3 +TC[C>G]CA 4 +TC[C>G]CC 3 +TC[C>G]CG 1 +TC[C>G]CT 6 +TC[C>G]GA 0 +TC[C>G]GC 0 +TC[C>G]GG 0 +TC[C>G]GT 0 +TC[C>G]TA 2 +TC[C>G]TC 5 +TC[C>G]TG 5 +TC[C>G]TT 6 +TC[C>T]AA 5 +TC[C>T]AC 2 +TC[C>T]AG 8 +TC[C>T]AT 5 +TC[C>T]CA 15 +TC[C>T]CC 11 +TC[C>T]CG 0 +TC[C>T]CT 10 +TC[C>T]GA 4 +TC[C>T]GC 7 +TC[C>T]GG 1 +TC[C>T]GT 2 +TC[C>T]TA 8 +TC[C>T]TC 6 +TC[C>T]TG 7 +TC[C>T]TT 10 +TC[T>A]AA 1 +TC[T>A]AC 2 +TC[T>A]AG 1 +TC[T>A]AT 4 +TC[T>A]CA 6 +TC[T>A]CC 6 +TC[T>A]CG 0 +TC[T>A]CT 11 +TC[T>A]GA 3 +TC[T>A]GC 4 +TC[T>A]GG 4 +TC[T>A]GT 11 +TC[T>A]TA 2 +TC[T>A]TC 5 +TC[T>A]TG 8 +TC[T>A]TT 6 +TC[T>C]AA 6 +TC[T>C]AC 6 +TC[T>C]AG 4 +TC[T>C]AT 4 +TC[T>C]CA 7 +TC[T>C]CC 2 +TC[T>C]CG 1 +TC[T>C]CT 2 +TC[T>C]GA 2 +TC[T>C]GC 10 +TC[T>C]GG 2 +TC[T>C]GT 7 +TC[T>C]TA 1 +TC[T>C]TC 11 +TC[T>C]TG 8 +TC[T>C]TT 11 +TC[T>G]AA 3 +TC[T>G]AC 0 +TC[T>G]AG 1 +TC[T>G]AT 3 +TC[T>G]CA 2 +TC[T>G]CC 2 +TC[T>G]CG 0 +TC[T>G]CT 3 +TC[T>G]GA 1 +TC[T>G]GC 3 +TC[T>G]GG 1 +TC[T>G]GT 2 +TC[T>G]TA 2 +TC[T>G]TC 3 +TC[T>G]TG 2 +TC[T>G]TT 7 +TG[C>A]AA 2 +TG[C>A]AC 2 +TG[C>A]AG 5 +TG[C>A]AT 5 +TG[C>A]CA 2 +TG[C>A]CC 3 +TG[C>A]CG 0 +TG[C>A]CT 2 +TG[C>A]GA 0 +TG[C>A]GC 0 +TG[C>A]GG 0 +TG[C>A]GT 0 +TG[C>A]TA 3 +TG[C>A]TC 5 +TG[C>A]TG 2 +TG[C>A]TT 5 +TG[C>G]AA 2 +TG[C>G]AC 1 +TG[C>G]AG 3 +TG[C>G]AT 0 +TG[C>G]CA 2 +TG[C>G]CC 4 +TG[C>G]CG 0 +TG[C>G]CT 4 +TG[C>G]GA 1 +TG[C>G]GC 0 +TG[C>G]GG 1 +TG[C>G]GT 1 +TG[C>G]TA 2 +TG[C>G]TC 1 +TG[C>G]TG 5 +TG[C>G]TT 3 +TG[C>T]AA 7 +TG[C>T]AC 3 +TG[C>T]AG 6 +TG[C>T]AT 3 +TG[C>T]CA 5 +TG[C>T]CC 5 +TG[C>T]CG 1 +TG[C>T]CT 6 +TG[C>T]GA 2 +TG[C>T]GC 4 +TG[C>T]GG 7 +TG[C>T]GT 3 +TG[C>T]TA 1 +TG[C>T]TC 8 +TG[C>T]TG 15 +TG[C>T]TT 8 +TG[T>A]AA 2 +TG[T>A]AC 2 +TG[T>A]AG 1 +TG[T>A]AT 1 +TG[T>A]CA 1 +TG[T>A]CC 3 +TG[T>A]CG 0 +TG[T>A]CT 1 +TG[T>A]GA 4 +TG[T>A]GC 3 +TG[T>A]GG 3 +TG[T>A]GT 5 +TG[T>A]TA 2 +TG[T>A]TC 2 +TG[T>A]TG 2 +TG[T>A]TT 1 +TG[T>C]AA 4 +TG[T>C]AC 3 +TG[T>C]AG 6 +TG[T>C]AT 9 +TG[T>C]CA 1 +TG[T>C]CC 4 +TG[T>C]CG 1 +TG[T>C]CT 7 +TG[T>C]GA 3 +TG[T>C]GC 3 +TG[T>C]GG 4 +TG[T>C]GT 4 +TG[T>C]TA 2 +TG[T>C]TC 9 +TG[T>C]TG 8 +TG[T>C]TT 6 +TG[T>G]AA 2 +TG[T>G]AC 1 +TG[T>G]AG 0 +TG[T>G]AT 2 +TG[T>G]CA 0 +TG[T>G]CC 2 +TG[T>G]CG 0 +TG[T>G]CT 0 +TG[T>G]GA 3 +TG[T>G]GC 0 +TG[T>G]GG 1 +TG[T>G]GT 2 +TG[T>G]TA 3 +TG[T>G]TC 1 +TG[T>G]TG 0 +TG[T>G]TT 3 +TT[C>A]AA 4 +TT[C>A]AC 6 +TT[C>A]AG 4 +TT[C>A]AT 11 +TT[C>A]CA 8 +TT[C>A]CC 6 +TT[C>A]CG 1 +TT[C>A]CT 16 +TT[C>A]GA 2 +TT[C>A]GC 0 +TT[C>A]GG 1 +TT[C>A]GT 2 +TT[C>A]TA 5 +TT[C>A]TC 8 +TT[C>A]TG 3 +TT[C>A]TT 8 +TT[C>G]AA 4 +TT[C>G]AC 2 +TT[C>G]AG 0 +TT[C>G]AT 4 +TT[C>G]CA 7 +TT[C>G]CC 1 +TT[C>G]CG 0 +TT[C>G]CT 12 +TT[C>G]GA 0 +TT[C>G]GC 1 +TT[C>G]GG 1 +TT[C>G]GT 1 +TT[C>G]TA 10 +TT[C>G]TC 12 +TT[C>G]TG 8 +TT[C>G]TT 8 +TT[C>T]AA 8 +TT[C>T]AC 1 +TT[C>T]AG 9 +TT[C>T]AT 13 +TT[C>T]CA 11 +TT[C>T]CC 8 +TT[C>T]CG 0 +TT[C>T]CT 15 +TT[C>T]GA 6 +TT[C>T]GC 0 +TT[C>T]GG 1 +TT[C>T]GT 0 +TT[C>T]TA 9 +TT[C>T]TC 12 +TT[C>T]TG 13 +TT[C>T]TT 5 +TT[T>A]AA 15 +TT[T>A]AC 3 +TT[T>A]AG 6 +TT[T>A]AT 10 +TT[T>A]CA 5 +TT[T>A]CC 8 +TT[T>A]CG 2 +TT[T>A]CT 13 +TT[T>A]GA 9 +TT[T>A]GC 2 +TT[T>A]GG 4 +TT[T>A]GT 10 +TT[T>A]TA 14 +TT[T>A]TC 3 +TT[T>A]TG 4 +TT[T>A]TT 19 +TT[T>C]AA 7 +TT[T>C]AC 6 +TT[T>C]AG 5 +TT[T>C]AT 16 +TT[T>C]CA 4 +TT[T>C]CC 7 +TT[T>C]CG 0 +TT[T>C]CT 10 +TT[T>C]GA 9 +TT[T>C]GC 2 +TT[T>C]GG 5 +TT[T>C]GT 8 +TT[T>C]TA 7 +TT[T>C]TC 5 +TT[T>C]TG 3 +TT[T>C]TT 12 +TT[T>G]AA 4 +TT[T>G]AC 3 +TT[T>G]AG 5 +TT[T>G]AT 2 +TT[T>G]CA 6 +TT[T>G]CC 2 +TT[T>G]CG 0 +TT[T>G]CT 11 +TT[T>G]GA 5 +TT[T>G]GC 2 +TT[T>G]GG 6 +TT[T>G]GT 9 +TT[T>G]TA 16 +TT[T>G]TC 4 +TT[T>G]TG 3 +TT[T>G]TT 30 diff --git a/docs/assets/osf/5c5de3d676653c0018270138.png b/docs/assets/osf/5c5de3d676653c0018270138.png new file mode 100644 index 0000000..c01a3e3 Binary files /dev/null and b/docs/assets/osf/5c5de3d676653c0018270138.png differ diff --git a/docs/assets/osf/5c73d34f8d5d98001a393840.png b/docs/assets/osf/5c73d34f8d5d98001a393840.png new file mode 100644 index 0000000..03c0bed Binary files /dev/null and b/docs/assets/osf/5c73d34f8d5d98001a393840.png differ diff --git a/docs/assets/osf/8ubjp.bin b/docs/assets/osf/8ubjp.bin new file mode 100644 index 0000000..d12e454 --- /dev/null +++ b/docs/assets/osf/8ubjp.bin @@ -0,0 +1,7 @@ +MutationType TutorialSample_snv +C>A 802 +C>G 769 +C>T 1206 +T>A 956 +T>C 1108 +T>G 681 diff --git a/docs/assets/osf/d3e6f.bin b/docs/assets/osf/d3e6f.bin new file mode 100644 index 0000000..f594ce0 --- /dev/null +++ b/docs/assets/osf/d3e6f.bin @@ -0,0 +1,79 @@ +MutationType Sample_Tutorial +AC>CA 1 +AC>CG 0 +AC>CT 0 +AC>GA 0 +AC>GG 0 +AC>GT 2 +AC>TA 0 +AC>TG 0 +AC>TT 0 +AT>CA 1 +AT>CC 0 +AT>CG 0 +AT>GA 0 +AT>GC 0 +AT>TA 0 +CC>AA 0 +CC>AG 0 +CC>AT 2 +CC>GA 0 +CC>GG 0 +CC>GT 0 +CC>TA 4 +CC>TG 1 +CC>TT 273 +CG>AT 0 +CG>GC 0 +CG>GT 0 +CG>TA 30 +CG>TC 0 +CG>TT 0 +CT>AA 0 +CT>AC 0 +CT>AG 0 +CT>GA 0 +CT>GC 1 +CT>GG 0 +CT>TA 0 +CT>TC 3 +CT>TG 0 +GC>AA 0 +GC>AG 0 +GC>AT 1 +GC>CA 0 +GC>CG 0 +GC>TA 0 +TA>AT 0 +TA>CG 1 +TA>CT 0 +TA>GC 0 +TA>GG 0 +TA>GT 0 +TC>AA 0 +TC>AG 0 +TC>AT 10 +TC>CA 0 +TC>CG 0 +TC>CT 10 +TC>GA 0 +TC>GG 0 +TC>GT 0 +TG>AA 0 +TG>AC 0 +TG>AT 0 +TG>CA 3 +TG>CC 0 +TG>CT 0 +TG>GA 1 +TG>GC 0 +TG>GT 0 +TT>AA 5 +TT>AC 1 +TT>AG 0 +TT>CA 0 +TT>CC 4 +TT>CG 0 +TT>GA 0 +TT>GC 0 +TT>GG 0 \ No newline at end of file diff --git a/docs/assets/osf/gmcyp.bin b/docs/assets/osf/gmcyp.bin new file mode 100644 index 0000000..9af1c02 --- /dev/null +++ b/docs/assets/osf/gmcyp.bin @@ -0,0 +1,385 @@ +MutationType TutorialSample_snv +T:A[C>A]A 18 +T:A[C>A]C 9 +T:A[C>A]G 3 +T:A[C>A]T 13 +T:A[C>G]A 8 +T:A[C>G]C 10 +T:A[C>G]G 5 +T:A[C>G]T 23 +T:A[C>T]A 25 +T:A[C>T]C 13 +T:A[C>T]G 22 +T:A[C>T]T 19 +T:A[T>A]A 10 +T:A[T>A]C 5 +T:A[T>A]G 14 +T:A[T>A]T 21 +T:A[T>C]A 23 +T:A[T>C]C 10 +T:A[T>C]G 32 +T:A[T>C]T 30 +T:A[T>G]A 6 +T:A[T>G]C 11 +T:A[T>G]G 8 +T:A[T>G]T 14 +T:C[C>A]A 12 +T:C[C>A]C 15 +T:C[C>A]G 3 +T:C[C>A]T 14 +T:C[C>G]A 14 +T:C[C>G]C 18 +T:C[C>G]G 4 +T:C[C>G]T 19 +T:C[C>T]A 14 +T:C[C>T]C 20 +T:C[C>T]G 15 +T:C[C>T]T 13 +T:C[T>A]A 5 +T:C[T>A]C 13 +T:C[T>A]G 22 +T:C[T>A]T 11 +T:C[T>C]A 14 +T:C[T>C]C 11 +T:C[T>C]G 20 +T:C[T>C]T 18 +T:C[T>G]A 4 +T:C[T>G]C 11 +T:C[T>G]G 8 +T:C[T>G]T 6 +T:G[C>A]A 11 +T:G[C>A]C 6 +T:G[C>A]G 4 +T:G[C>A]T 12 +T:G[C>G]A 11 +T:G[C>G]C 7 +T:G[C>G]G 2 +T:G[C>G]T 6 +T:G[C>T]A 16 +T:G[C>T]C 15 +T:G[C>T]G 23 +T:G[C>T]T 11 +T:G[T>A]A 1 +T:G[T>A]C 3 +T:G[T>A]G 5 +T:G[T>A]T 5 +T:G[T>C]A 11 +T:G[T>C]C 7 +T:G[T>C]G 11 +T:G[T>C]T 15 +T:G[T>G]A 3 +T:G[T>G]C 5 +T:G[T>G]G 2 +T:G[T>G]T 3 +T:T[C>A]A 23 +T:T[C>A]C 25 +T:T[C>A]G 7 +T:T[C>A]T 20 +T:T[C>G]A 8 +T:T[C>G]C 15 +T:T[C>G]G 7 +T:T[C>G]T 21 +T:T[C>T]A 26 +T:T[C>T]C 17 +T:T[C>T]G 2 +T:T[C>T]T 14 +T:T[T>A]A 13 +T:T[T>A]C 15 +T:T[T>A]G 8 +T:T[T>A]T 23 +T:T[T>C]A 17 +T:T[T>C]C 5 +T:T[T>C]G 10 +T:T[T>C]T 17 +T:T[T>G]A 11 +T:T[T>G]C 11 +T:T[T>G]G 7 +T:T[T>G]T 28 +U:A[C>A]A 13 +U:A[C>A]C 12 +U:A[C>A]G 4 +U:A[C>A]T 13 +U:A[C>G]A 9 +U:A[C>G]C 13 +U:A[C>G]G 4 +U:A[C>G]T 8 +U:A[C>T]A 15 +U:A[C>T]C 11 +U:A[C>T]G 13 +U:A[C>T]T 12 +U:A[T>A]A 21 +U:A[T>A]C 9 +U:A[T>A]G 11 +U:A[T>A]T 20 +U:A[T>C]A 22 +U:A[T>C]C 6 +U:A[T>C]G 28 +U:A[T>C]T 26 +U:A[T>G]A 4 +U:A[T>G]C 4 +U:A[T>G]G 6 +U:A[T>G]T 27 +U:C[C>A]A 14 +U:C[C>A]C 9 +U:C[C>A]G 2 +U:C[C>A]T 10 +U:C[C>G]A 4 +U:C[C>G]C 20 +U:C[C>G]G 4 +U:C[C>G]T 22 +U:C[C>T]A 14 +U:C[C>T]C 26 +U:C[C>T]G 14 +U:C[C>T]T 19 +U:C[T>A]A 5 +U:C[T>A]C 14 +U:C[T>A]G 26 +U:C[T>A]T 19 +U:C[T>C]A 11 +U:C[T>C]C 9 +U:C[T>C]G 16 +U:C[T>C]T 21 +U:C[T>G]A 5 +U:C[T>G]C 11 +U:C[T>G]G 9 +U:C[T>G]T 10 +U:G[C>A]A 13 +U:G[C>A]C 7 +U:G[C>A]G 6 +U:G[C>A]T 10 +U:G[C>G]A 2 +U:G[C>G]C 6 +U:G[C>G]G 4 +U:G[C>G]T 8 +U:G[C>T]A 10 +U:G[C>T]C 19 +U:G[C>T]G 12 +U:G[C>T]T 20 +U:G[T>A]A 9 +U:G[T>A]C 9 +U:G[T>A]G 15 +U:G[T>A]T 7 +U:G[T>C]A 10 +U:G[T>C]C 8 +U:G[T>C]G 13 +U:G[T>C]T 5 +U:G[T>G]A 3 +U:G[T>G]C 1 +U:G[T>G]G 1 +U:G[T>G]T 6 +U:T[C>A]A 24 +U:T[C>A]C 15 +U:T[C>A]G 1 +U:T[C>A]T 13 +U:T[C>G]A 12 +U:T[C>G]C 17 +U:T[C>G]G 1 +U:T[C>G]T 27 +U:T[C>T]A 31 +U:T[C>T]C 21 +U:T[C>T]G 10 +U:T[C>T]T 21 +U:T[T>A]A 22 +U:T[T>A]C 14 +U:T[T>A]G 16 +U:T[T>A]T 35 +U:T[T>C]A 22 +U:T[T>C]C 11 +U:T[T>C]G 12 +U:T[T>C]T 14 +U:T[T>G]A 8 +U:T[T>G]C 12 +U:T[T>G]G 10 +U:T[T>G]T 32 +B:A[C>A]A 0 +B:A[C>A]C 0 +B:A[C>A]G 0 +B:A[C>A]T 0 +B:A[C>G]A 1 +B:A[C>G]C 0 +B:A[C>G]G 0 +B:A[C>G]T 0 +B:A[C>T]A 0 +B:A[C>T]C 0 +B:A[C>T]G 0 +B:A[C>T]T 0 +B:A[T>A]A 0 +B:A[T>A]C 0 +B:A[T>A]G 0 +B:A[T>A]T 0 +B:A[T>C]A 0 +B:A[T>C]C 1 +B:A[T>C]G 1 +B:A[T>C]T 1 +B:A[T>G]A 0 +B:A[T>G]C 0 +B:A[T>G]G 0 +B:A[T>G]T 0 +B:C[C>A]A 1 +B:C[C>A]C 0 +B:C[C>A]G 0 +B:C[C>A]T 1 +B:C[C>G]A 1 +B:C[C>G]C 1 +B:C[C>G]G 0 +B:C[C>G]T 1 +B:C[C>T]A 0 +B:C[C>T]C 0 +B:C[C>T]G 0 +B:C[C>T]T 0 +B:C[T>A]A 0 +B:C[T>A]C 0 +B:C[T>A]G 0 +B:C[T>A]T 0 +B:C[T>C]A 1 +B:C[T>C]C 0 +B:C[T>C]G 0 +B:C[T>C]T 1 +B:C[T>G]A 0 +B:C[T>G]C 0 +B:C[T>G]G 1 +B:C[T>G]T 0 +B:G[C>A]A 0 +B:G[C>A]C 1 +B:G[C>A]G 0 +B:G[C>A]T 0 +B:G[C>G]A 0 +B:G[C>G]C 0 +B:G[C>G]G 0 +B:G[C>G]T 1 +B:G[C>T]A 0 +B:G[C>T]C 0 +B:G[C>T]G 0 +B:G[C>T]T 0 +B:G[T>A]A 0 +B:G[T>A]C 0 +B:G[T>A]G 0 +B:G[T>A]T 0 +B:G[T>C]A 0 +B:G[T>C]C 0 +B:G[T>C]G 1 +B:G[T>C]T 0 +B:G[T>G]A 0 +B:G[T>G]C 0 +B:G[T>G]G 0 +B:G[T>G]T 0 +B:T[C>A]A 2 +B:T[C>A]C 0 +B:T[C>A]G 0 +B:T[C>A]T 0 +B:T[C>G]A 0 +B:T[C>G]C 0 +B:T[C>G]G 0 +B:T[C>G]T 0 +B:T[C>T]A 0 +B:T[C>T]C 0 +B:T[C>T]G 0 +B:T[C>T]T 0 +B:T[T>A]A 1 +B:T[T>A]C 0 +B:T[T>A]G 0 +B:T[T>A]T 1 +B:T[T>C]A 1 +B:T[T>C]C 0 +B:T[T>C]G 0 +B:T[T>C]T 0 +B:T[T>G]A 0 +B:T[T>G]C 0 +B:T[T>G]G 0 +B:T[T>G]T 1 +N:A[C>A]A 45 +N:A[C>A]C 24 +N:A[C>A]G 5 +N:A[C>A]T 28 +N:A[C>G]A 23 +N:A[C>G]C 29 +N:A[C>G]G 11 +N:A[C>G]T 36 +N:A[C>T]A 54 +N:A[C>T]C 20 +N:A[C>T]G 45 +N:A[C>T]T 39 +N:A[T>A]A 33 +N:A[T>A]C 19 +N:A[T>A]G 41 +N:A[T>A]T 47 +N:A[T>C]A 76 +N:A[T>C]C 22 +N:A[T>C]G 51 +N:A[T>C]T 63 +N:A[T>G]A 29 +N:A[T>G]C 18 +N:A[T>G]G 22 +N:A[T>G]T 57 +N:C[C>A]A 35 +N:C[C>A]C 25 +N:C[C>A]G 5 +N:C[C>A]T 29 +N:C[C>G]A 27 +N:C[C>G]C 29 +N:C[C>G]G 8 +N:C[C>G]T 46 +N:C[C>T]A 40 +N:C[C>T]C 53 +N:C[C>T]G 35 +N:C[C>T]T 55 +N:C[T>A]A 21 +N:C[T>A]C 29 +N:C[T>A]G 40 +N:C[T>A]T 29 +N:C[T>C]A 33 +N:C[T>C]C 23 +N:C[T>C]G 46 +N:C[T>C]T 36 +N:C[T>G]A 13 +N:C[T>G]C 16 +N:C[T>G]G 16 +N:C[T>G]T 22 +N:G[C>A]A 20 +N:G[C>A]C 20 +N:G[C>A]G 2 +N:G[C>A]T 19 +N:G[C>G]A 18 +N:G[C>G]C 15 +N:G[C>G]G 7 +N:G[C>G]T 20 +N:G[C>T]A 46 +N:G[C>T]C 28 +N:G[C>T]G 32 +N:G[C>T]T 45 +N:G[T>A]A 16 +N:G[T>A]C 8 +N:G[T>A]G 21 +N:G[T>A]T 15 +N:G[T>C]A 30 +N:G[T>C]C 16 +N:G[T>C]G 40 +N:G[T>C]T 38 +N:G[T>G]A 6 +N:G[T>G]C 6 +N:G[T>G]G 10 +N:G[T>G]T 11 +N:T[C>A]A 63 +N:T[C>A]C 54 +N:T[C>A]G 9 +N:T[C>A]T 53 +N:T[C>G]A 45 +N:T[C>G]C 35 +N:T[C>G]G 3 +N:T[C>G]T 73 +N:T[C>T]A 66 +N:T[C>T]C 47 +N:T[C>T]G 25 +N:T[C>T]T 43 +N:T[T>A]A 52 +N:T[T>A]C 53 +N:T[T>A]G 29 +N:T[T>A]T 75 +N:T[T>C]A 45 +N:T[T>C]C 26 +N:T[T>C]G 32 +N:T[T>C]T 39 +N:T[T>G]A 24 +N:T[T>G]C 32 +N:T[T>G]G 29 +N:T[T>G]T 81 diff --git a/docs/assets/osf/manifest.json b/docs/assets/osf/manifest.json new file mode 100644 index 0000000..4a1b680 --- /dev/null +++ b/docs/assets/osf/manifest.json @@ -0,0 +1,15 @@ +{ + "https://files.osf.io/v1/resources/2aj6t/providers/osfstorage/5c5de3d676653c0018270138?mode=render": "assets/osf/5c5de3d676653c0018270138.png", + "https://files.osf.io/v1/resources/2aj6t/providers/osfstorage/5c73d34f8d5d98001a393840?mode=render": "assets/osf/5c73d34f8d5d98001a393840.png", + "https://osf.io/2wh7g/": "assets/osf/2wh7g.zip", + "https://osf.io/2ydqt/": "assets/osf/2ydqt.bin", + "https://osf.io/3rm96/": "assets/osf/3rm96.bin", + "https://osf.io/43e76/": "assets/osf/43e76.bin", + "https://osf.io/8ubjp/": "assets/osf/8ubjp.bin", + "https://osf.io/d3e6f/": "assets/osf/d3e6f.bin", + "https://osf.io/gmcyp/": "assets/osf/gmcyp.bin", + "https://osf.io/p2fxv/": "assets/osf/p2fxv.bin", + "https://osf.io/p3yzs/": "assets/osf/p3yzs.bin", + "https://osf.io/synw4/": "assets/osf/synw4.bin", + "https://osf.io/xd9ym/": "assets/osf/xd9ym.bin" +} diff --git a/docs/assets/osf/missing_assets.json b/docs/assets/osf/missing_assets.json new file mode 100644 index 0000000..4d57950 --- /dev/null +++ b/docs/assets/osf/missing_assets.json @@ -0,0 +1,26 @@ +{ + "https://files.osf.io/v1/resources/2aj6t/providers/osfstorage/5c6b0c28737a510019aa3e15?mode=render": { + "error": "HTTP 404 fetching https://files.osf.io/v1/resources/2aj6t/providers/osfstorage/5c6b0c28737a510019aa3e15?action=download (from https://files.osf.io/v1/resources/2aj6t/providers/osfstorage/5c6b0c28737a510019aa3e15?mode=render): '{\"message_short\": \"Page not found\", \"message_long\": \"The requested resource could not be found. If this should not have occurred and the issue persists, please report it to + + + + Image unavailable + This OSF-hosted asset is not accessible (HTTP 403) and could not be mirrored. + + + + + + + diff --git a/docs/assets/osf/p2fxv.bin b/docs/assets/osf/p2fxv.bin new file mode 100644 index 0000000..7d21f6b --- /dev/null +++ b/docs/assets/osf/p2fxv.bin @@ -0,0 +1,187 @@ +MutationType Sample_Tutorial +T:CC>AA 0 +T:CC>AG 0 +T:CC>AT 1 +T:CC>GA 0 +T:CC>GG 0 +T:CC>GT 0 +T:CC>TA 0 +T:CC>TG 0 +T:CC>TT 30 +T:CT>AA 0 +T:CT>AC 0 +T:CT>AG 0 +T:CT>GA 0 +T:CT>GC 0 +T:CT>GG 0 +T:CT>TA 0 +T:CT>TC 2 +T:CT>TG 0 +T:TC>AA 0 +T:TC>AG 0 +T:TC>AT 0 +T:TC>CA 0 +T:TC>CG 0 +T:TC>CT 2 +T:TC>GA 0 +T:TC>GG 0 +T:TC>GT 0 +T:TT>AA 0 +T:TT>AC 1 +T:TT>AG 0 +T:TT>CA 0 +T:TT>CC 1 +T:TT>CG 0 +T:TT>GA 0 +T:TT>GC 0 +T:TT>GG 0 +U:CC>AA 0 +U:CC>AG 0 +U:CC>AT 0 +U:CC>GA 0 +U:CC>GG 0 +U:CC>GT 0 +U:CC>TA 1 +U:CC>TG 0 +U:CC>TT 42 +U:CT>AA 0 +U:CT>AC 0 +U:CT>AG 0 +U:CT>GA 0 +U:CT>GC 0 +U:CT>GG 0 +U:CT>TA 0 +U:CT>TC 0 +U:CT>TG 0 +U:TC>AA 0 +U:TC>AG 0 +U:TC>AT 1 +U:TC>CA 0 +U:TC>CG 0 +U:TC>CT 2 +U:TC>GA 0 +U:TC>GG 0 +U:TC>GT 0 +U:TT>AA 2 +U:TT>AC 0 +U:TT>AG 0 +U:TT>CA 0 +U:TT>CC 2 +U:TT>CG 0 +U:TT>GA 0 +U:TT>GC 0 +U:TT>GG 0 +B:CC>AA 0 +B:CC>AG 0 +B:CC>AT 0 +B:CC>GA 0 +B:CC>GG 0 +B:CC>GT 0 +B:CC>TA 0 +B:CC>TG 0 +B:CC>TT 0 +B:CT>AA 0 +B:CT>AC 0 +B:CT>AG 0 +B:CT>GA 0 +B:CT>GC 0 +B:CT>GG 0 +B:CT>TA 0 +B:CT>TC 0 +B:CT>TG 0 +B:TC>AA 0 +B:TC>AG 0 +B:TC>AT 0 +B:TC>CA 0 +B:TC>CG 0 +B:TC>CT 0 +B:TC>GA 0 +B:TC>GG 0 +B:TC>GT 0 +B:TT>AA 0 +B:TT>AC 0 +B:TT>AG 0 +B:TT>CA 0 +B:TT>CC 0 +B:TT>CG 0 +B:TT>GA 0 +B:TT>GC 0 +B:TT>GG 0 +N:CC>AA 0 +N:CC>AG 0 +N:CC>AT 1 +N:CC>GA 0 +N:CC>GG 0 +N:CC>GT 0 +N:CC>TA 3 +N:CC>TG 1 +N:CC>TT 202 +N:CT>AA 0 +N:CT>AC 0 +N:CT>AG 0 +N:CT>GA 0 +N:CT>GC 1 +N:CT>GG 0 +N:CT>TA 0 +N:CT>TC 1 +N:CT>TG 0 +N:TC>AA 0 +N:TC>AG 0 +N:TC>AT 9 +N:TC>CA 0 +N:TC>CG 0 +N:TC>CT 6 +N:TC>GA 0 +N:TC>GG 0 +N:TC>GT 0 +N:TT>AA 3 +N:TT>AC 0 +N:TT>AG 0 +N:TT>CA 0 +N:TT>CC 1 +N:TT>CG 0 +N:TT>GA 0 +N:TT>GC 0 +N:TT>GG 0 +Q:AC>CA 1 +Q:AC>CG 0 +Q:AC>CT 0 +Q:AC>GA 0 +Q:AC>GG 0 +Q:AC>GT 2 +Q:AC>TA 0 +Q:AC>TG 0 +Q:AC>TT 0 +Q:AT>CA 1 +Q:AT>CC 0 +Q:AT>CG 0 +Q:AT>GA 0 +Q:AT>GC 0 +Q:AT>TA 0 +Q:CG>AT 0 +Q:CG>GC 0 +Q:CG>GT 0 +Q:CG>TA 30 +Q:CG>TC 0 +Q:CG>TT 0 +Q:GC>AA 0 +Q:GC>AG 0 +Q:GC>AT 1 +Q:GC>CA 0 +Q:GC>CG 0 +Q:GC>TA 0 +Q:TA>AT 0 +Q:TA>CG 1 +Q:TA>CT 0 +Q:TA>GC 0 +Q:TA>GG 0 +Q:TA>GT 0 +Q:TG>AA 0 +Q:TG>AC 0 +Q:TG>AT 0 +Q:TG>CA 3 +Q:TG>CC 0 +Q:TG>CT 0 +Q:TG>GA 1 +Q:TG>GC 0 +Q:TG>GT 0 \ No newline at end of file diff --git a/docs/assets/osf/p3yzs.bin b/docs/assets/osf/p3yzs.bin new file mode 100644 index 0000000..965073d --- /dev/null +++ b/docs/assets/osf/p3yzs.bin @@ -0,0 +1,97 @@ +MutationType TutorialSample_snv +A[C>A]A 76 +A[C>A]C 45 +A[C>A]G 12 +A[C>A]T 54 +A[C>G]A 41 +A[C>G]C 52 +A[C>G]G 20 +A[C>G]T 67 +A[C>T]A 94 +A[C>T]C 44 +A[C>T]G 80 +A[C>T]T 70 +A[T>A]A 64 +A[T>A]C 33 +A[T>A]G 66 +A[T>A]T 88 +A[T>C]A 121 +A[T>C]C 39 +A[T>C]G 112 +A[T>C]T 120 +A[T>G]A 39 +A[T>G]C 33 +A[T>G]G 36 +A[T>G]T 98 +C[C>A]A 62 +C[C>A]C 49 +C[C>A]G 10 +C[C>A]T 54 +C[C>G]A 46 +C[C>G]C 68 +C[C>G]G 16 +C[C>G]T 88 +C[C>T]A 68 +C[C>T]C 99 +C[C>T]G 64 +C[C>T]T 87 +C[T>A]A 31 +C[T>A]C 56 +C[T>A]G 88 +C[T>A]T 59 +C[T>C]A 59 +C[T>C]C 43 +C[T>C]G 82 +C[T>C]T 76 +C[T>G]A 22 +C[T>G]C 38 +C[T>G]G 34 +C[T>G]T 38 +G[C>A]A 44 +G[C>A]C 34 +G[C>A]G 12 +G[C>A]T 41 +G[C>G]A 31 +G[C>G]C 28 +G[C>G]G 13 +G[C>G]T 35 +G[C>T]A 72 +G[C>T]C 62 +G[C>T]G 67 +G[C>T]T 76 +G[T>A]A 26 +G[T>A]C 20 +G[T>A]G 41 +G[T>A]T 27 +G[T>C]A 51 +G[T>C]C 31 +G[T>C]G 65 +G[T>C]T 58 +G[T>G]A 12 +G[T>G]C 12 +G[T>G]G 13 +G[T>G]T 20 +T[C>A]A 112 +T[C>A]C 94 +T[C>A]G 17 +T[C>A]T 86 +T[C>G]A 65 +T[C>G]C 67 +T[C>G]G 11 +T[C>G]T 121 +T[C>T]A 123 +T[C>T]C 85 +T[C>T]G 37 +T[C>T]T 78 +T[T>A]A 88 +T[T>A]C 82 +T[T>A]G 53 +T[T>A]T 134 +T[T>C]A 85 +T[T>C]C 42 +T[T>C]G 54 +T[T>C]T 70 +T[T>G]A 43 +T[T>G]C 55 +T[T>G]G 46 +T[T>G]T 142 diff --git a/docs/assets/osf/synw4.bin b/docs/assets/osf/synw4.bin new file mode 100644 index 0000000..39381c0 --- /dev/null +++ b/docs/assets/osf/synw4.bin @@ -0,0 +1,25 @@ +MutationType TutorialSample_snv +T:C>A 195 +T:C>G 178 +T:C>T 265 +T:T>A 174 +T:T>C 251 +T:T>G 138 +U:C>A 166 +U:C>G 161 +U:C>T 268 +U:T>A 252 +U:T>C 234 +U:T>G 149 +B:C>A 5 +B:C>G 5 +B:C>T 0 +B:T>A 2 +B:T>C 7 +B:T>G 2 +N:C>A 436 +N:C>G 425 +N:C>T 673 +N:T>A 528 +N:T>C 616 +N:T>G 392 diff --git a/docs/assets/osf/xd9ym.bin b/docs/assets/osf/xd9ym.bin new file mode 100644 index 0000000..eb150df --- /dev/null +++ b/docs/assets/osf/xd9ym.bin @@ -0,0 +1,29 @@ +MutationType TutorialSample TutorialSample_snv +1:Del:C:0 37 0 +1:Del:C:1 29 0 +1:Del:C:2 20 0 +1:Del:C:3 15 0 +1:Del:C:4 5 0 +1:Del:C:5 3 0 +1:Del:T:0 54 0 +1:Del:T:1 41 0 +1:Del:T:2 58 0 +1:Del:T:3 39 0 +1:Del:T:4 25 0 +1:Del:T:5 31 0 +1:Ins:C:0 3 0 +1:Ins:C:1 3 0 +1:Ins:C:2 3 0 +1:Ins:C:3 1 0 +1:Ins:C:4 2 0 +1:Ins:C:5 3 0 +1:Ins:T:0 5 0 +1:Ins:T:1 24 0 +1:Ins:T:2 25 0 +1:Ins:T:3 15 0 +1:Ins:T:4 6 0 +1:Ins:T:5 40 0 +long_Del 121 0 +long_Ins 87 0 +MH 117 0 +complex 3 0 diff --git a/docs/assets/stylesheets/extra.css b/docs/assets/stylesheets/extra.css new file mode 100644 index 0000000..f921199 --- /dev/null +++ b/docs/assets/stylesheets/extra.css @@ -0,0 +1,7 @@ +.md-grid { + max-width: 1200px; +} + +.md-typeset__table { + overflow-x: auto; +} diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..a6189c3 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,40 @@ +# SigProfilerPlotting # +---------- + +SigProfilerPlotting provides a standard tool for displaying all types of mutational signatures as well as all types of mutational patterns in cancer genomes. The tool seamlessly integrates with other SigProfiler tools. + +The SigProfilerPlotting library can be found on github [here][2]. +The [README.md][3] file provides a great overview if you already have python and pip installed on your computer. For users that prefer working in an R environment, we provide an R wrapper (SigProfilerPlottingR) that can be found on github [here][12]. + +## Citation ## +Bergstrom EN, Huang MN, Mahto U, Barnes M, Stratton MR, Rozen SG, and Alexandrov LB (2019) SigProfilerMatrixGenerator: a tool for visualizing and exploring patterns of small mutational events. **BMC Genomics** 20, Article number: 685. +https://bmcgenomics.biomedcentral.com/articles/10.1186/s12864-019-6041-2 +## License ## + +Copyright (c) 2019, Erik Bergstrom [Alexandrov Lab] +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +## Contact ## + +Please address any queries or bug reports to Erik Bergstrom at ebergstr@eng.ucsd.edu + + [1]: https://files.osf.io/v1/resources/2aj6t/providers/osfstorage/5c73d34f8d5d98001a393840?mode=render + [2]: https://github.com/AlexandrovLab/SigProfilerPlotting + [3]: https://github.com/AlexandrovLab/SigProfilerPlotting/blob/master/README.md + [4]: https://realpython.com/installing-python/ + [5]: https://docs.brew.sh/Homebrew-and-Python + [6]: https://files.osf.io/v1/resources/2aj6t/providers/osfstorage/5c6b0c28737a510019aa3e15?mode=render + [7]: https://github.com/AlexandrovLab/SigProfilerPlotting + [8]: https://files.osf.io/v1/resources/2aj6t/providers/osfstorage/5c5de3d676653c0018270138?mode=render + [9]: https://files.osf.io/v1/resources/2aj6t/providers/osfstorage/5c73d2c482a3950017d09b92?mode=render + [10]: https://files.osf.io/v1/resources/2aj6t/providers/osfstorage/5c73c72862c82a0019dae02f?mode=render + [11]: https://files.osf.io/v1/resources/2aj6t/providers/osfstorage/5c73c7eb82a3950018cbfddc?mode=render + [12]: https://github.com/AlexandrovLab/SigProfilerPlottingR diff --git a/docs/osf_wiki/1. Installation - Python.md b/docs/osf_wiki/1. Installation - Python.md new file mode 100644 index 0000000..9b8f464 --- /dev/null +++ b/docs/osf_wiki/1. Installation - Python.md @@ -0,0 +1,100 @@ +

SigProfilerPlotting Installation Guide

+ +---------- + +## Prerequisites ## + +SigProfilerPlotting requires that you have: +
    +
  • Internet Connection
  • +
  • Python version 3.4.0 or newer
  • +
  • SigProfilerMatrixGenerator (recommended)
  • +
+ +## Mac/Unix ## +Check that you have the required python version by opening Terminal (`⌘ + Space` type `terminal` and hit `return` to open the application) and entering the command: + + python3 --version + +You should see an output similar to: + + ~ python3 --version + Python 3.4.0 + +If you do not get a similar output (or a version that is 3.4.0 or newer), you will need to [install python3][1] before continuing with this guide. + +Next you will want to make sure that you have `pip3` installed because it will be used for importing sigProfilerPlotting. Check that you have `pip3` installed by entering into terminal: + + pip3 --version + +You should see an output similar to: + + ~ pip3 --version + pip 19.0.1 /Library/Frameworks/SomeFilePath/ + +If you do not have pip3 installed, then follow [homebrew's guide][2] for installing pip. + + +Next, use pip3 to download SigProfilerPlotting. + + pip3 install sigProfilerPlotting + +You can check that the installation was successful by entering into Terminal: + + pip3 list +This command will output a list of libraries that you have access to. Matplotlib and sigProfilerPlotting should be two of the libraries listed. + +@[osf](uabr5) + +If the download fails or you receive an error, check to make sure that python3 and pip3 are installed by using the --version commands. If they are not, start from the beginning of the guide and follow the directions again to download them. + +## Windows ## +First, start by opening up Command Prompt. Navigate to the search bar in the lower left hand corner of the screen and search `cmd` and open the application `Command Prompt`. + +Next, you will download and install Python and Pip. Check if Python is installed by entering the command: + + python --version + +If you have Python installed, you should receive an output similar to: + + C:\Users\YourUserName>python + Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] on win32 + Type "help", "copyright", "credits" or "license" for more information. + >>> + +If you do not have python, or need Python 3.4.0 or newer, then [download Python here][3]. + +After downloading and installing Python, fill in your username at `YourUsernameHere` and run: + + setx PATH “%PATH%;C:\Users\YourUsernameHere\AppData\Local\Programs\Python\Python37\” + setx PATH “%PATH%;C:\Users\YourUsernameHere\AppData\Local\Programs\Python\Python37\Scripts\” + +This will set the path so that you can call Python and pip from the command line. + +Check that you have the required libraries installed by entering into the command line: + + python --version + pip --version + +If you both commands output version numbers, then you have successfully downloaded and installed Python and pip and you are ready to proceed. Otherwise, go through the process of reinstalling Python and pip. + +Now that your environment is ready, use pip to install sigProfilerPlotting. + + pip install sigProfilerPlotting + +If the download was successful, then sigProfilerPlotting should be one of the libraries outputted by the following command. + + pip list + +@[osf](egk7c) + +Now your environment should be setup and ready to use the sigProfilerPlotting library. + +If you are receiving an error, check to make sure that python and pip are installed by using the --version commands. If they are not installed, start from the beginning of the guide and follow the directions again to download them. + +**Note for Windows Users**: When passing the path to your files as a parameter to any of the functions, you will need make your string into a raw string literal (ie. the String "C:\User\YourUserName\Desktop\\" will need to be r"C:\User\YourUserName\Desktop\\\\"). + + + [1]: https://realpython.com/installing-python/ + [2]: https://docs.brew.sh/Homebrew-and-Python + [3]: https://www.python.org/ diff --git a/docs/osf_wiki/2. Installation - R.md b/docs/osf_wiki/2. Installation - R.md new file mode 100644 index 0000000..a81be20 --- /dev/null +++ b/docs/osf_wiki/2. Installation - R.md @@ -0,0 +1,75 @@ +

SigProfilerPlotting Installation (R-wrapper) Guide

+ +---------- + +## Prerequisites ## + +SigProfilerPlottingR requires that you have: +
    +
  • Internet Connection
  • +
  • Python version 3.4.0 or newer
  • +
  • SigProfilerMatrixGeneratorR (recommended)
  • +
+ +## Mac/Unix ## +Check that you have the required python version by opening Terminal (`⌘ + Space` type `terminal` and hit `return` to open the application) and entering the command: + + python3 --version + +You should see an output similar to: + + ~ python3 --version + Python 3.4.0 + +If you do not get a similar output (or a version that is 3.4.0 or newer), you will need to [install python3][1] before continuing with this guide. + +Next you will want to make sure that you have `pip3` installed because it will be used for importing sigProfilerPlotting. Check that you have `pip3` installed by entering into terminal: + + pip3 --version + +You should see an output similar to: + + ~ pip3 --version + pip 19.0.1 /Library/Frameworks/SomeFilePath/ + +If you do not have pip3 installed, then follow [homebrew's guide][2] for installing pip. + + +Next, use pip3 to download SigProfilerPlotting. + + pip3 install sigProfilerPlotting + +You can check that the installation was successful by entering into Terminal: + + pip3 list +This command will output a list of libraries that you have access to. Matplotlib and sigProfilerPlotting should be two of the libraries listed. + +@[osf](uabr5) + +If the download fails or you receive an error, check to make sure that python3 and pip3 are installed by using the --version commands. If they are not, start from the beginning of the guide and follow the directions again to download them. + +## Installing R dependencies ## +You must install the devtools and reticulate libraries: + + $ R + >> install.packages("devtools") + >> install.packages("reticulate") + +Now you are ready to install SigProfilerPlottingR: + + $ R + >> library("reticulate") + >> use_python("path_to_your_python3") + >> py_config() + >> library("devtools") + >> install_github("AlexandrovLab/SigProfilerPlottingR") + +Ensure that you can properly load the package: + + >> library("SigProfilerPlottingR") + + + + [1]: https://realpython.com/installing-python/ + [2]: https://docs.brew.sh/Homebrew-and-Python + [3]: https://www.python.org/ diff --git a/docs/osf_wiki/3. Plotting Substitutions.md b/docs/osf_wiki/3. Plotting Substitutions.md new file mode 100644 index 0000000..bbee613 --- /dev/null +++ b/docs/osf_wiki/3. Plotting Substitutions.md @@ -0,0 +1,133 @@ +# Plotting Substitutions # + +---------- + +Refer to this page to learn about how to plot single base substitutions (SBS) using the plotSBS function. Included below is the function and a list of valid parameter values. There are also examples of each SBS graph with a quick description for interpreting it. + + +@[toc](Sections) + +## plotSBS Function ## +The plotSBS function provides a standard approach for displaying mutational signatures and mutational patterns of single base substitutions. Depending on the specified parameters, the function can generate a number of distinct representations of signatures/patterns. + + plotSBS(matrix_path, output_path, project, plot_type, percentage=False, custom_text_upper=None, custom_text_middle=None, custom_text_bottom=None) + +or if you are running the R-wrapper package, any "False" must be changed to FALSE, "True" changed to "TRUE", and "None" changed to "NULL." + +- **matrix_path** -> (String) The path to your matrix (generated by SigProfilerMatrixGenerator)
+- **output_path** -> (String) The path to where the output will be saved
+- **project** -> (String) The output file will have this value postfixed in the name.
+- **plot type** -> (String) The plot type to be generated. Valid inputs include {"6", "24", "96", "384", and "1536"}. +
+- **percentage** -> (Boolean) True for a normalized percentile plot and False for a numerical plot. This parameter has a default value of False.
+- **custom_text_upper, custom_text_middle, custom_text_bottom** -> (List of Strings) Provide a list of strings for adding a custom text to the upper right-hand corner of the plot. Ideally, there should be one string per sample. Extra strings will not be plotted. The three parameters allow for three rows of custom text (upper, middle, lower). + + +Supported SigProfiler Matrices include: 6, 24, 96, 384, and 1536.
+ +## plotSBS Examples ## +The following examples were generated in a python environment where sigProfilerPlotting was imported as sigPlt. + + $ python3 + >>import sigProfilerPlotting as sigPlt + +From within a R session, you will import the library as follows: + + $ R + >> library("reticulate") + >> use_python("path_to_your_python3") + >> py_config() + >> library("SigProfilerPlottingR") + + +The matrices below are used to generate the example plots. You can download and run the commands to generate the example plots. +- [SBS-6][1] +- [SBS-24][2] +- [SBS-96][3] +- [SBS-384][4] +- [SBS-1536][5] + +### Plot SBS-6 Numerical ### +From within a Python session: + + sigPlt.plotSBS(matrix_path_SBS + "SBS6.all", output_path, project_name, "6", percentage=False) + +From within a R session: + + >> plotSBS(matrix_path_SBS + "SBS6.all", output_path, project_name, "6", percentage=FALSE) + + + +@[osf](cmv6d) +The **Single Base Substitution-6 (SBS-6) numerical plot** has the six different mutation categories on the y-axis and the number of each mutation on the x-axis. The sample name and total number of substitutions are provided at the top of the plot. + +### Plot SBS-6 Percentile ### +From within a Python session: + + sigPlt.plotSBS(matrix_path_to_SBS_file + "SBS6.all", output_path, "BRCA_example", "6", percentage=True) + +From within a R session: + + plotSBS(matrix_path_to_SBS_file + "SBS6.all", output_path, "BRCA_example", "6", percentage=TRUE) + +@[osf](kmd2f) +The **Single Base Substitution-6 (SBS-6) percentile plot** includes the six different mutation categories on the y-axis and the normalized percentages of each mutation on the x-axis. + +### Plot SBS-24 ### +From within a Python session: + + sigPlt.plotSBS(matrix_path_SBS + "SBS24.all", output_path,"BRCA_example", "24",False) + +From within a R session: + + plotSBS(matrix_path_SBS + "SBS24.all", output_path,"BRCA_example", "24",FALSE) + +@[osf](jcemf) +The **Single Base Substitution-24 (SBS-24) numerical plot** includes the six different mutation categories on the y-axis , and the number of mutations that occurred on the transcribed and untranscribed strands on the x-axis (does not plot bidirectional and nontranscribed TSB categories). +
+
+ +### Plot SBS-96 ### +From within a Python session: + + sigPlt.plotSBS(matrix_path_SBS + "SBS96.all", output_path,"BRCA_example", "96",False) + +From within a R session: + + plotSBS(matrix_path_SBS + "SBS96.all", output_path,"BRCA_example", "96",FALSE) + +@[osf](fgc8z) +The **Single Base Substitution-96 (SBS-96) numerical plot** graphs the trinucleotide contexts of each mutation. Along the x-axis are the six main categories that represent the different mutations (C>A, C>G,...,T>G). Each of these six categories has an additional 16 categories to represent the combinations of bases that can prefix and postfix the mutation (ie. ACA, ACC, ACG, ACT, CCA,..., TCT). The y-axis presents the number of each mutation. +
+
+### Plot SBS-384 ### +From within a Python session: + + sigPlt.plotSBS(matrix_path_SBS + "SBS384.all", output_path,"BRCA_example", "384",False) + +From within a R session: + + plotSBS(matrix_path_SBS + "SBS384.all", output_path,"BRCA_example", "384", FALSE) + +@[osf](78htw) +The **Single Base Substitution-384 (SBS-384) numerical plot** graphs the trinucleotide contexts of each mutation. Along the x-axis are the six main categories that represent the different mutations (C>A, C>G,...,T>G). Each of these six categories has an additional 16 categories to represent the combinations of bases that can prefix and postfix the mutation (ie. ACA, ACC, ACG, ACT, CCA,..., TCT). Additionally, the mutation is categorized depending whether it was located on the transcribed or untranscribed strand. The y-axis is the number of such mutations that occurred. + +### Plot SBS-1536 ### +From within a Python session: + + sigPlt.plotSBS(matrix_path_SBS + "SBS1536.all", output_path,"BRCA_example", "1536",False) + +From within a R session: + + plotSBS(matrix_path_SBS + "SBS1536.all", output_path,"BRCA_example", "1536",FALSE) + +@[osf](sc9qj) + +The **Single Base Substitution-1536 (SBS-1536) numerical plot** graphs the trinucleotide contexts of each mutations. Along the top on the x-axis are the six main categories that represent the different mutations (C>A, C>G,...,T>G). Directly below these categories are a set of bar graphs that have the number of each mutation. Also, beneath the bar graphs are heat maps of the pentanucleotide contexts. The probability is normalized to the maximum pentanucleotide count. + + + [1]: https://osf.io/8ubjp/ + [2]: https://osf.io/synw4/ + [3]: https://osf.io/p3yzs/ + [4]: https://osf.io/gmcyp/ + [5]: https://osf.io/43e76/ diff --git a/docs/osf_wiki/4. Plotting Indels.md b/docs/osf_wiki/4. Plotting Indels.md new file mode 100644 index 0000000..b50fc4e --- /dev/null +++ b/docs/osf_wiki/4. Plotting Indels.md @@ -0,0 +1,86 @@ +# Plotting Indels # + +---------- + +Refer to this page to learn about how to plot small insertions and deletions (indels) using the plotID function. Included below is the function and a list of valid parameter values. There are also examples of each indel graph with a quick description for interpreting it. + +@[toc](Sections) + +## plotID Function ## +Plots the number of small insertions, deletions, and microhomologies. + + plotID(matrix_path, output_path, project, plot_type, percentage=False, custom_text_upper=None, custom_text_middle=None, custom_text_lower=None) + +For those using the R-wrapper, you must switch all "False" to "FALSE", "True" to "TRUE", and "None" to "NULL." + +- **matrix_path** -> (String) The path to your matrix (generated by SigProfilerMatrixGenerator).
+- **output_path** -> (String) The path to where the output will be saved.
+- **project** -> (String) The output file will have this value postfixed in the name.
+- **plot type** -> (String) The plot type to be generated. Valid inputs include {"28", "83", "415"}.
+- **percentage** -> (Boolean) True for a normalized percentile plot and False for a numerical plot. This parameter has a default value of False.
+- **custom_text_upper, custom_text_middle, custom_text_bottom** -> (List of Strings) Provide a list of strings for adding a custom text to the upper right-hand corner of the plot. Ideally, there should be one string per sample. Extra strings will not be plotted. The three parameters allow for three rows of custom text (upper, middle, lower). + +Supported SigProfiler Matrices include: 28 (ID_Simple), 83, and 415.
+ +## plotID Examples ## + +The following examples were generated in a python environment where sigProfilerPlotting was imported as sigPlt. + + $ python3 + >>import sigProfilerPlotting as sigPlt + +From within a R session: + + $ R + >> library("reticulate") + >> use_python("path_to_your_python3") + >> py_config() + >> library("SigProfilerPlottingR") + +The matrices below are used to generate the example plots. You can download and run the commands to generate the example plots. +- [ID Simple][1] +- [ID-83][2] +- [ID-415][3] + +### Plot ID_Simple ### +From within a Python session: + + sigPlt.plotID(matrix_path_INDEL + "INDEL28.all", output_path, project_name, "28", percentage=False) + +From within a R session: + + plotID(matrix_path_INDEL + "INDEL28.all", output_path, project_name, "28", percentage=FALSE) + +@[osf](kwd3y) +The **Insertion Deletion Simple (ID-Simple) plot** shows single base pair insertion and deletions with respect to the pyrimidine context. The x-axis represents the number of repeated bases of the given indel (homopolymer length). The y-axis is the number of mutations that occurred for the given category. On the far right of the plot, there are columns for large deletions, insertions, and microhomologies greater than one base pair. There is an additional column for complex indels which represent events that both deleted bases and inserted bases into the same region of the genome. + + +### Plot ID-83 ### +From within a Python session: + + sigPlt.plotID(matrix_path_INDEL + "INDEL83.all", output_path, project_name, "83", percentage=False) + +From within a R session: + + plotID(matrix_path_INDEL + "INDEL83.all", output_path, project_name, "83", percentage=FALSE) + + +@[osf](hfqr2) +The **Insertion Deletion-83 (ID-83) plot** counts the number of small insertions and deletions that occur at a single base pair and at sequences of base pairs longer than one. The plot also displays microhomologies which are deletions that occur adjacent to a substring of the deleted sequence. + +### Plot ID-415 ### +From within a Python session: + + sigPlt.plotID(matrix_path_INDEL + "INDEL415.all", output_path, project_name, "415",False) + +From within a R session: + + plotID(matrix_path_INDEL + "INDEL415.all", output_path, project_name, "415",FALSE) + +@[osf](b7m2t) +The **Insertion Deletion-415 (ID415) plot** counts the number of small insertions and deletions that occur at a single base pair and at sequences of base pairs longer than one. The plot also displays microhomologies which are deletions that occur adjacent to a substring of the deleted sequence. The plot shows the mutations that occur on the transcribed or untranscribed strands within protein-coding regions (bidirectional, non-transcribed, and unclassifiable indels are not plotted). + + + [1]: https://osf.io/xd9ym/ + [2]: https://osf.io/3rm96/ + [3]: https://osf.io/2ydqt/ diff --git a/docs/osf_wiki/5. Plotting Dinucleotides.md b/docs/osf_wiki/5. Plotting Dinucleotides.md new file mode 100644 index 0000000..76fd43e --- /dev/null +++ b/docs/osf_wiki/5. Plotting Dinucleotides.md @@ -0,0 +1,69 @@ +# Plotting Dinucleotides # + +---------- + +Refer to this page to learn about how to plot dinucleotides (DBS) using the plotDBS function. Included below is the function and a list of valid parameter values. There are also examples of each DBS graph with a quick description for interpreting it. + +@[toc](Sections) + +## plotDBS Function ## +Plots the number of double base substitutions. + + plotDBS(matrix_path, output_path, project, plot_type, percentage=False, custom_text_upper=None, custom_text_middle=None, custom_text_lower=None) + +For those using the R-wrapper, you must switch any "True" to "TRUE", "False" to "FALSE", and "None" to "NULL." + +- **matrix_path** -> (String) The path to your matrix (generated by SigProfilerMatrixGenerator).
+- **output_path** -> (String) The path to where the output will be saved.
+- **project** -> (String) The output file will have this value postfixed in the name.
+- **plot type** -> (String) The plot type to be generated. Valid inputs include {"78", "312"}.
+- **percentage** -> (Boolean) True for a normalized percentile plot and False for a numerical plot. This parameter has a default value of False.
+- **custom_text_upper, custom_text_middle, custom_text_bottom** -> (List of Strings) Provide a list of strings for adding a custom text to the upper right-hand corner of the plot. Ideally, there should be one string per sample. Extra strings will not be plotted. The three parameters allow for three rows of custom text (upper, middle, lower). + +Supported SigProfiler Matrices include: 78 and 186.
+ +## plotDBS Examples ## +The following examples were generated in a python environment where sigProfilerPlotting was imported as sigPlt. + + $ python3 + >>import sigProfilerPlotting as sigPlt + +From within a R session: + + $ R + >> library("reticulate") + >> use_python("path_to_your_python3") + >> py_config() + >> library("SigProfilerPlottingR") + +The matrices below are used to generate the example plots. You can download and run the commands to generate the example plots. +- [DBS-78][1] +- [DBS-186][2] + +### Plot DBS-78 ### +From within a Python session: + + sigPlt.plotDBS(matrix_path_DINUC + "DBS78.all", output_path, project_name, "78", percentage=False) + +From within a R session: + + plotDBS(matrix_path_DINUC + "DBS78.all", output_path, project_name, "78", percentage=FALSE) + +@[osf](s7wuj) +The **Double Base Substitution-78 (DBS-78) plot** counts the number of double base mutations. The DBS categories are listed along the top of the plot, and the number of each mutation are represented along the y-axis. The 78 mutational channels are determined using the maximum pyrimidine context of the mutation. + +### Plot DBS-186 ### +From within a Python session: + + sigPlt.plotDBS(matrix_path_DINUC + "DBS186.all", output_path, project_name, "186",False) + +From within a R session: + + plotDBS(matrix_path_DINUC + "DBS186.all", output_path, project_name, "186",FALSE) + +@[osf](uxyfv) +The **Double Base Substitution-186 (DBS-186) plot** counts the number of double base mutations that occur on the transcribed or untranscribed strands within protein coding regions. Only doublet-substitutions containing all pyrimidines or all purines can be classified this way. The DBS categories are listed along the top of the plot, and the number of each mutation are represented along the y-axis. + + + [1]: https://osf.io/d3e6f/ + [2]: https://osf.io/p2fxv/ diff --git a/docs/osf_wiki/6. Plotting a Sample Portrait.md b/docs/osf_wiki/6. Plotting a Sample Portrait.md new file mode 100644 index 0000000..d37c7cb --- /dev/null +++ b/docs/osf_wiki/6. Plotting a Sample Portrait.md @@ -0,0 +1,55 @@ +# Plotting a Sample Portrait # + +---------- + +Refer to this page to learn about how to use the Sample Portrait function. Included below is the function and a list of valid parameter values. There is also an example of the Sample Portrait. + + +@[toc](Sections) + +## samplePortrait Function ## +Outputs a file with the different substitution, indel, and dinucleotide graphs. + + samplePortrait(matrix, output_path, project, percentage=False) + +For those using the R-wrapper, you must switch any "True" to "TRUE", "False" to "FALSE", and "None" to "NULL." + +- **matrix_path** -> (String) The path to your matrix (generated by SigProfilerMatrixGenerator).
+- **output_path** -> (String) The path to where the output will be saved.
+- **project** -> (String) The output file will have this value postfixed in the name.
+- **percentage** -> (Boolean) True for a normalized percentile plot and False for a numerical plot. This parameter has a default value of False.
+ +To create a sample portrait, ensure that you have a matrix for all required contexts (SBS-6, SBS-24, SBS-96, SBS-384, SBS-1536, DBS-78, DBS-312, ID-83, ID-28, ID-96). + +## plotDBS Examples ## +The following examples were generated in a python environment where sample_portrait was imported as sP from sigProfilerPlotting. + + $python3 + >>from sigProfilerPlotting import sample_portrait as sP + +From within a R session: + + $ R + >> library("reticulate") + >> use_python("path_to_your_python3") + >> py_config() + >> library("SigProfilerPlottingR") + + +### The Sample Portrait ### +From within a Python session: + + sP.samplePortrait(sample_matrices_path, output_path, project, percentage=False) + +From within a R session: + + samplePortrait(sample_matrices_path, output_path, project, percentage=FALSE) + +@[osf](2he54) + +This collection of graphs includes the variations that are produced by each function. To produce an individual graph found in the collection, navigate to [Plotting Susbtitutions][1], [Plotting Indels][2], or [Plotting Dinucleotides][3], and call the corresponding function. + + + [1]: https://osf.io/2aj6t/wiki/3.%20Plotting%20Substitutions/ + [2]: https://osf.io/2aj6t/wiki/4.%20Plotting%20Indels/ + [3]: https://osf.io/2aj6t/wiki/5.%20Plotting%20Dinucleotides/ diff --git a/docs/osf_wiki/7. Example Program.md b/docs/osf_wiki/7. Example Program.md new file mode 100644 index 0000000..c3d9c19 --- /dev/null +++ b/docs/osf_wiki/7. Example Program.md @@ -0,0 +1,25 @@ +## Running the Example Program ## +After you have successfully installed SigProfilerPlotting, [download SigProfilerPlottingExampleProgram.zip][1], and move it to your desktop and unzip it. + +Next, open up your application terminal and enter the following command: + + cd ~/Desktop/SigProfilerPlottingExampleProgram/ + +You can now run the example program by entering the command: + + python3 plot_example.py + +It may take a few seconds to complete. You can find the output graphs in the directory labeled `plots`, which is located in your current directory. If you are having difficulty locating the folder, open the finder application and press `⌘ + Shift + G` and enter into the "Go to the Folder" drop down menu: `~/Desktop/SigProfilerPlottingExampleProgram/plots/` + + @[osf](kw8py) + +If you delete the four plot files and run plot_example.py then they should be generated again. +
+
+Now that you were able to run `plot_example.py` your environment is set up and you are ready to start writing your own applications. Take a look at the sections labeled [Plotting Substitutions][2], [Plotting Indels][3], and [Plotting Dinucleotides][4] for more details about the different functions that SigProfilerPlotting provides. + + + [1]: https://osf.io/2wh7g/ + [2]: https://osf.io/2aj6t/wiki/3.%20Plotting%20Substitutions/ + [3]: https://osf.io/2aj6t/wiki/4.%20Plotting%20Indels/ + [4]: https://osf.io/2aj6t/wiki/5.%20Plotting%20Dinucleotides/ diff --git a/docs/osf_wiki/home.md b/docs/osf_wiki/home.md new file mode 100644 index 0000000..bd41d33 --- /dev/null +++ b/docs/osf_wiki/home.md @@ -0,0 +1,40 @@ +# SigProfilerPlotting # +---------- + +SigProfilerPlotting provides a standard tool for displaying all types of mutational signatures as well as all types of mutational patterns in cancer genomes. The tool seamlessly integrates with other SigProfiler tools. + +The SigProfilerPlotting library can be found on github [here][2]. +The [README.md][3] file provides a great overview if you already have python and pip installed on your computer. For users that prefer working in an R environment, we provide an R wrapper (SigProfilerPlottingR) that can be found on github [here][12]. + +## Citation ## +Bergstrom EN, Huang MN, Mahto U, Barnes M, Stratton MR, Rozen SG, and Alexandrov LB (2019) SigProfilerMatrixGenerator: a tool for visualizing and exploring patterns of small mutational events. **BMC Genomics** 20, Article number: 685. +https://bmcgenomics.biomedcentral.com/articles/10.1186/s12864-019-6041-2 +## License ## + +Copyright (c) 2019, Erik Bergstrom [Alexandrov Lab] +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +## Contact ## + +Please address any queries or bug reports to Erik Bergstrom at ebergstr@eng.ucsd.edu + + [1]: https://files.osf.io/v1/resources/2aj6t/providers/osfstorage/5c73d34f8d5d98001a393840?mode=render + [2]: https://github.com/AlexandrovLab/SigProfilerPlotting + [3]: https://github.com/AlexandrovLab/SigProfilerPlotting/blob/master/README.md + [4]: https://realpython.com/installing-python/ + [5]: https://docs.brew.sh/Homebrew-and-Python + [6]: https://files.osf.io/v1/resources/2aj6t/providers/osfstorage/5c6b0c28737a510019aa3e15?mode=render + [7]: https://github.com/AlexandrovLab/SigProfilerPlotting + [8]: https://files.osf.io/v1/resources/2aj6t/providers/osfstorage/5c5de3d676653c0018270138?mode=render + [9]: https://files.osf.io/v1/resources/2aj6t/providers/osfstorage/5c73d2c482a3950017d09b92?mode=render + [10]: https://files.osf.io/v1/resources/2aj6t/providers/osfstorage/5c73c72862c82a0019dae02f?mode=render + [11]: https://files.osf.io/v1/resources/2aj6t/providers/osfstorage/5c73c7eb82a3950018cbfddc?mode=render + [12]: https://github.com/AlexandrovLab/SigProfilerPlottingR diff --git a/docs/osf_wiki/index.md b/docs/osf_wiki/index.md new file mode 100644 index 0000000..9e69c10 --- /dev/null +++ b/docs/osf_wiki/index.md @@ -0,0 +1,22 @@ +# OSF Wiki (Mirrored) + +These pages are mirrored from the OSF wiki and stored in-repo for local viewing. + +To regenerate the mirror: + +```bash +python3 tools/mirror_osf_wiki.py --node 2aj6t --continue-on-asset-error +``` + +Some OSF-hosted assets could not be downloaded (e.g. HTTP 403). See [Missing Assets](missing-assets.md). + +## Pages + +- [1. Installation - Python](1. Installation - Python.md) +- [2. Installation - R](2. Installation - R.md) +- [3. Plotting Substitutions](3. Plotting Substitutions.md) +- [4. Plotting Indels](4. Plotting Indels.md) +- [5. Plotting Dinucleotides](5. Plotting Dinucleotides.md) +- [6. Plotting a Sample Portrait](6. Plotting a Sample Portrait.md) +- [7. Example Program](7. Example Program.md) +- [home](home.md) diff --git a/docs/osf_wiki/missing-assets.md b/docs/osf_wiki/missing-assets.md new file mode 100644 index 0000000..01e4ca6 --- /dev/null +++ b/docs/osf_wiki/missing-assets.md @@ -0,0 +1,23 @@ +# Missing Assets + +Some OSF-hosted assets referenced by the wiki could not be downloaded. + +Common causes: + +- The asset belongs to a different OSF project you cannot access +- The asset is private or restricted + +## Details + +- `https://files.osf.io/v1/resources/2aj6t/providers/osfstorage/5c6b0c28737a510019aa3e15?mode=render` + - Error: `HTTP 404 fetching https://files.osf.io/v1/resources/2aj6t/providers/osfstorage/5c6b0c28737a510019aa3e15?action=download (from https://files.osf.io/v1/resources/2aj6t/providers/osfstorage/5c6b0c28737a510019aa3e15?mode=render): '{"message_short": "Page not found", "message_long": "The requested resource could not be found. If this should not have occurred and the issue persists, please report it to
]*\bsrc=")([^"]+)(")', re.IGNORECASE) +_OSF_EMBED_RE = re.compile(r"@\[(osf)\]\(([^)]+)\)", re.IGNORECASE) +_OSF_WIKI_URL_RE = re.compile(r"https://osf\.io/([^/]+)/wiki/([^\s)\"]+)", re.IGNORECASE) +_OSF_MANIFEST_CACHE = None +_OSF_MANIFEST_LOADED = False +_OSF_MISSING_CACHE = None +_OSF_MISSING_LOADED = False +_OSF_PLACEHOLDER = "assets/osf/osf_asset_unavailable.svg" + +# Map OSF wiki page names (decoded from URL) to local docs filenames. +_OSF_WIKI_PAGE_TO_DOC = { + "home": "index.md", + "1. installation - python": "Installation-Python.md", + "2. installation - r": "Installation-R.md", + "3. plotting substitutions": "Plotting-Substitutions.md", + "4. plotting indels": "Plotting-Indels.md", + "5. plotting dinucleotides": "Plotting-Dinucleotides.md", + "6. plotting a sample portrait": "Plotting-a-Sample-Portrait.md", + "7. example program": "Example-Program.md", + # Historical/non-numbered variants. + "installation - python": "Installation-Python.md", + "installation - r": "Installation-R.md", + "plotting substitutions": "Plotting-Substitutions.md", + "plotting indels": "Plotting-Indels.md", + "plotting dinucleotides": "Plotting-Dinucleotides.md", + "plotting a sample portrait": "Plotting-a-Sample-Portrait.md", + "example program": "Example-Program.md", +} + + +def on_page_markdown(markdown: str, page, config, files): + if not markdown: + return markdown + + lines = markdown.splitlines(keepends=True) + filtered_lines = [ + line for line in lines if not _TOC_MARKER_LINE_RE.match(line.strip("\n")) + ] + cleaned = "".join(filtered_lines) + + # OSF Wiki sometimes appends non-standard size hints like " =50%x" inside + # Markdown image links, which breaks rendering in MkDocs/Markdown. + cleaned = _OSF_IMAGE_SIZE_SUFFIX_RE.sub(r"\1\2", cleaned) + + # Convert OSF embed markers (e.g. "@[osf](abcde)") into plain links. + cleaned = _OSF_EMBED_RE.sub(r"[OSF](https://osf.io/\2/)", cleaned) + + prefix = _page_relative_prefix(page) + + # Rewrite OSF wiki links to local pages (prevents navigation to downloaded HTML stubs). + cleaned = _rewrite_osf_wiki_links(cleaned, prefix=prefix) + + manifest = _load_osf_manifest(config) + if manifest: + for url, rel_path in manifest.items(): + if _is_osf_wiki_url(url): + continue + cleaned = cleaned.replace(url, prefix + rel_path) + + missing = _load_osf_missing(config) + if missing: + cleaned = _replace_blocked_osf_images(cleaned, missing, prefix=prefix) + + return cleaned + + +def _load_osf_manifest(config): + global _OSF_MANIFEST_CACHE + global _OSF_MANIFEST_LOADED + + if _OSF_MANIFEST_LOADED: + return _OSF_MANIFEST_CACHE + + _OSF_MANIFEST_LOADED = True + docs_dir = config.get("docs_dir") or "docs" + manifest_path = ( + Path(os.path.abspath(docs_dir)) / "assets" / "osf" / "manifest.json" + ) + if not manifest_path.exists(): + _OSF_MANIFEST_CACHE = None + return None + + try: + _OSF_MANIFEST_CACHE = json.loads(manifest_path.read_text(encoding="utf-8")) + except Exception: + _OSF_MANIFEST_CACHE = None + return _OSF_MANIFEST_CACHE + + +def _is_osf_url(url: str) -> bool: + return url.startswith("https://files.osf.io/") or url.startswith("https://osf.io/") + + +def _is_osf_wiki_url(url: str) -> bool: + return url.startswith("https://osf.io/") and "/wiki/" in url + + +def _page_relative_prefix(page) -> str: + try: + src_path = getattr(page.file, "src_path", "") or "" + except Exception: + src_path = "" + page_dir = os.path.dirname(src_path).strip("/\\") + if not page_dir: + return "" + depth = len([p for p in re.split(r"[\\/]+", page_dir) if p and p != "."]) + return "../" * depth + + +def _load_osf_missing(config): + global _OSF_MISSING_CACHE + global _OSF_MISSING_LOADED + + if _OSF_MISSING_LOADED: + return _OSF_MISSING_CACHE + + _OSF_MISSING_LOADED = True + docs_dir = config.get("docs_dir") or "docs" + missing_path = ( + Path(os.path.abspath(docs_dir)) / "assets" / "osf" / "missing_assets.json" + ) + if not missing_path.exists(): + _OSF_MISSING_CACHE = None + return None + + try: + payload = json.loads(missing_path.read_text(encoding="utf-8")) + # File is a dict keyed by URL. + if isinstance(payload, dict): + _OSF_MISSING_CACHE = set(payload.keys()) + else: + _OSF_MISSING_CACHE = None + except Exception: + _OSF_MISSING_CACHE = None + return _OSF_MISSING_CACHE + + +def _replace_blocked_osf_images(markdown: str, blocked_urls: set, *, prefix: str) -> str: + dir_prefix = prefix + + def md_repl(m): + img_prefix, url, suffix = m.group(1), m.group(2), m.group(3) + if url in blocked_urls: + return f"{img_prefix}{dir_prefix + _OSF_PLACEHOLDER}{suffix}" + return m.group(0) + + def html_repl(m): + img_prefix, url, suffix = m.group(1), m.group(2), m.group(3) + if url in blocked_urls: + return f"{img_prefix}{dir_prefix + _OSF_PLACEHOLDER}{suffix}" + return m.group(0) + + out = _OSF_URL_IN_MD_IMAGE_RE.sub(md_repl, markdown) + out = _OSF_URL_IN_HTML_IMG_RE.sub(html_repl, out) + return out + + +def _rewrite_osf_wiki_links(markdown: str, *, prefix: str) -> str: + """ + Rewrite links like: + https://osf.io/2aj6t/wiki/4.%20Plotting%20Indels/ + to local MkDocs pages. + """ + + def repl(m): + tail = m.group(2) # e.g. "4.%20Using%20the%20Tool%20-%20Output/" + decoded = urllib.parse.unquote(tail).rstrip("/") + key = decoded.lower() + doc = _OSF_WIKI_PAGE_TO_DOC.get(key) + if not doc: + return m.group(0) + return prefix + doc + + return _OSF_WIKI_URL_RE.sub(repl, markdown) diff --git a/tools/mirror_osf_wiki.py b/tools/mirror_osf_wiki.py new file mode 100644 index 0000000..d220d7f --- /dev/null +++ b/tools/mirror_osf_wiki.py @@ -0,0 +1,519 @@ +import argparse +import json +import mimetypes +import os +import re +import urllib.parse +import urllib.request +import urllib.error +from pathlib import Path +from typing import Optional, Tuple, Dict, Set + + +_OSF_API = "https://api.osf.io/v2" +_OSF_FILES_RE = re.compile(r"https://files\.osf\.io/[^\s)\"']+") +_OSF_SHORT_RE = re.compile(r"https://osf\.io/[^\s)\"']+") +_OSF_IMAGE_SIZE_SUFFIX_RE = re.compile( + r"(https://files\.osf\.io/[^\s)\"']+)\s+=\d+(?:%x|x)$" +) +_BROWSER_UA = ( + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) " + "AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15" +) + + +def _headers(*, accept: str, token: Optional[str], extra: Optional[dict] = None) -> dict: + headers = { + "User-Agent": _BROWSER_UA, + "Accept": accept, + } + if token: + headers["Authorization"] = f"Bearer {token}" + if extra: + headers.update(extra) + return headers + + +def _fetch(url: str, accept: str, token: Optional[str]) -> Tuple[int, Optional[str], bytes]: + req = urllib.request.Request( + url, + headers=_headers(accept=accept, token=token), + ) + with urllib.request.urlopen(req, timeout=60) as r: + payload = r.read() + return r.status, r.headers.get("content-type"), payload + + +def _fetch_json(url: str, token: Optional[str]) -> dict: + status, content_type, payload = _fetch(url, "application/json", token) + if not payload or not payload.strip(): + raise RuntimeError( + f"Expected JSON but got empty response (status={status}, content-type={content_type}) from {url}" + ) + + try: + return json.loads(payload.decode("utf-8")) + except json.JSONDecodeError: + snippet = payload[:200].decode("utf-8", "replace") + raise RuntimeError( + f"Expected JSON but got non-JSON response (status={status}, content-type={content_type}) from {url}: {snippet!r}" + ) + + +def _iter_osf_collection(first_url: str, token: Optional[str]): + url = first_url + while url: + # OSF node wiki listing is usually public, but allow auth for private projects. + data = _fetch_json(url, token=token) + for item in data.get("data", []): + yield item + url = (data.get("links") or {}).get("next") + + +def _safe_filename(name: str) -> str: + # OSF wiki names typically don't contain path separators, but guard anyway. + return name.replace("/", "-").replace("\\", "-") + + +def _guess_ext(content_type: Optional[str]) -> str: + if not content_type: + return "" + mime = content_type.split(";", 1)[0].strip().lower() + if mime == "image/jpeg": + return ".jpg" + if mime == "image/svg+xml": + return ".svg" + return mimetypes.guess_extension(mime) or "" + + +def _sniff_ext(data: bytes) -> str: + if not data: + return "" + if data.startswith(b"\x89PNG\r\n\x1a\n"): + return ".png" + if data.startswith(b"\xff\xd8\xff"): + return ".jpg" + if data.startswith(b"GIF87a") or data.startswith(b"GIF89a"): + return ".gif" + if data.startswith(b"%PDF-"): + return ".pdf" + if data.startswith(b"PK\x03\x04"): + return ".zip" + if data.startswith(b"\x1f\x8b"): + return ".gz" + head = data[:512].lstrip() + if head.startswith(b" Tuple[Optional[str], Optional[str], Optional[str]]: + """ + Parse files.osf.io v1 URLs: + /v1/resources//providers//?... + Returns (node_id, provider, file_id) or (None, None, None) if not recognized. + """ + parsed = urllib.parse.urlparse(url) + if parsed.netloc != "files.osf.io": + return None, None, None + + parts = parsed.path.strip("/").split("/") + node_id = None + provider = None + file_id = None + try: + r = parts.index("resources") + node_id = parts[r + 1] + except Exception: + node_id = None + try: + p = parts.index("providers") + provider = parts[p + 1] + file_id = parts[p + 2] + except Exception: + provider = None + file_id = None + return node_id, provider, file_id + + +def _download(url: str, out_path: Path, token: Optional[str]) -> Path: + download_url = url + parsed = urllib.parse.urlparse(url) + if parsed.netloc == "osf.io": + # osf.io shortlinks often require /download to yield the file bytes. + if not parsed.path.rstrip("/").endswith("/download"): + download_url = urllib.parse.urljoin( + url if url.endswith("/") else url + "/", "download" + ) + + candidate_urls = [download_url] + if parsed.netloc == "osf.io": + short_parts = [p for p in parsed.path.strip("/").split("/") if p] + if len(short_parts) == 1 and short_parts[0] != "download": + candidate_urls.append(f"https://osf.io/download/{short_parts[0]}/") + + # Some OSF file URLs are easier to fetch as downloads than as "render". + if parsed.netloc == "files.osf.io": + # Prefer an API-resolved download URL when authenticated. This often yields a + # signed URL and avoids 403s from direct files.osf.io access. + if token: + node_id, provider, file_id = _parse_files_osf_url(url) + if provider and file_id: + api_download = _resolve_osf_file_download_url( + provider=provider, file_id=file_id, token=token, node_id=node_id + ) + if api_download: + candidate_urls.insert(0, api_download) + + q = urllib.parse.parse_qs(parsed.query, keep_blank_values=True) + if q.get("mode") == ["render"]: + q.pop("mode", None) + q["action"] = ["download"] + new_query = urllib.parse.urlencode(q, doseq=True) + candidate_urls.append(parsed._replace(query=new_query).geturl()) + + last_err = None + for candidate in candidate_urls: + req = urllib.request.Request( + candidate, + headers=_headers( + accept="*/*", + token=token, + extra={ + "Referer": "https://osf.io/", + }, + ), + ) + try: + with urllib.request.urlopen(req, timeout=60) as r: + content_type = r.headers.get("content-type") + data = r.read() + last_err = None + break + except urllib.error.HTTPError as e: + if e.code in (301, 302, 303, 307, 308): + location = e.headers.get("Location") + if location: + redirected = urllib.parse.urljoin(candidate, location) + if redirected not in candidate_urls: + candidate_urls.append(redirected) + continue + # Capture a small snippet for debugging; continue to next candidate. + try: + snippet = e.read(200).decode("utf-8", "replace") + except Exception: + snippet = "" + # If this looks like an OSF Storage file id, try to resolve a signed/alternate + # download URL via the OSF API (often works better than files.osf.io URLs). + # If we didn't already add an API URL (or it failed), attempt it on-demand. + if e.code in (401, 403) and parsed.netloc == "files.osf.io" and token: + node_id, provider, file_id = _parse_files_osf_url(url) + if provider and file_id: + api_download = _resolve_osf_file_download_url( + provider=provider, + file_id=file_id, + token=token, + node_id=node_id, + ) + if api_download and api_download not in candidate_urls: + candidate_urls.append(api_download) + continue + + last_err = RuntimeError( + f"HTTP {e.code} fetching {candidate} (from {url})" + + (f": {snippet!r}" if snippet else "") + ) + continue + except Exception as e: + last_err = e + continue + + if last_err is not None: + raise last_err + + ext = _guess_ext(content_type) + sniffed_ext = _sniff_ext(data) + if not ext or ext == ".bin": + ext = sniffed_ext or ext + final_path = out_path.with_suffix(ext) if ext else out_path + final_path.parent.mkdir(parents=True, exist_ok=True) + final_path.write_bytes(data) + return final_path + + +def _resolve_osf_file_download_url( + *, provider: str, file_id: str, token: str, node_id: Optional[str] +) -> Optional[str]: + """ + Best-effort: ask OSF API for a download link for a file. + Some OSF instances return an authenticated/signed URL here. + """ + endpoints = [ + f"{_OSF_API}/files/{provider}/{file_id}/", + f"{_OSF_API}/files/{file_id}/", # older/alternate shape on some deployments + ] + if node_id: + endpoints.append(f"{_OSF_API}/nodes/{node_id}/files/{provider}/{file_id}/") + + payload = None + for ep in endpoints: + try: + payload = _fetch_json(ep, token=token) + break + except Exception: + continue + if not payload: + return None + + data = payload.get("data") or {} + links = data.get("links") or {} + for key in ("download", "render"): + val = links.get(key) + if isinstance(val, str) and val.startswith("http"): + return val + return None + + +def _extract_osf_file_urls(markdown: str) -> list[str]: + urls = [] + for raw in _OSF_FILES_RE.findall(markdown) + _OSF_SHORT_RE.findall(markdown): + url = raw.rstrip(").,") + url = _OSF_IMAGE_SIZE_SUFFIX_RE.sub(r"\1", url) + parsed = urllib.parse.urlparse(url) + if parsed.netloc == "osf.io": + parts = parsed.path.strip("/").split("/") + # Do not treat OSF wiki navigation links as downloadable "assets". + if len(parts) >= 2 and parts[1] == "wiki": + continue + urls.append(url) + return sorted(set(urls)) + + +def _write_text_exact(path: Path, content: str) -> None: + # Preserve content as provided by OSF. Add a trailing newline only when non-empty. + if content and not content.endswith("\n"): + content += "\n" + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(content, encoding="utf-8") + + +def _fetch_wiki_markdown(wiki_id: str, token: Optional[str]) -> str: + # OSF has historically returned either JSON or raw markdown from this endpoint. + url = f"{_OSF_API}/wikis/{wiki_id}/content/" + status, content_type, payload = _fetch( + url, "application/json, text/plain, */*", token=token + ) + if not payload or not payload.strip(): + raise RuntimeError( + f"Empty wiki content response (status={status}, content-type={content_type}) from {url}" + ) + + # Try JSON first when it looks like JSON. + looks_like_json = payload[:1] in (b"{", b"[") + if looks_like_json or (content_type and "json" in content_type.lower()): + try: + content_payload = json.loads(payload.decode("utf-8")) + data = content_payload.get("data") or {} + attrs = data.get("attributes") or {} + # Common OSF field. + if isinstance(attrs.get("content"), str): + return attrs["content"] + except Exception: + # Fall back to treating it as text. + pass + + return payload.decode("utf-8", "replace") + + +def main() -> int: + parser = argparse.ArgumentParser( + description="Mirror OSF wiki pages and referenced OSF-hosted assets into docs/ for local MkDocs rendering.", + ) + parser.add_argument( + "--node", + default="2aj6t", + help="OSF node GUID (default: 2aj6t).", + ) + parser.add_argument( + "--docs-dir", + default="docs", + help="MkDocs docs_dir (default: docs).", + ) + parser.add_argument( + "--wiki-out", + default="docs/osf_wiki", + help="Output directory for mirrored wiki pages (default: docs/osf_wiki).", + ) + parser.add_argument( + "--assets-out", + default="docs/assets/osf", + help="Output directory for downloaded assets (default: docs/assets/osf).", + ) + parser.add_argument( + "--page-size", + default=100, + type=int, + help="OSF API page size (default: 100).", + ) + parser.add_argument( + "--token", + default=os.environ.get("OSF_TOKEN"), + help="OSF personal access token (or set env var OSF_TOKEN). Needed for private assets/projects.", + ) + parser.add_argument( + "--clean", + action="store_true", + help="Remove previously-mirrored wiki pages and downloaded assets (keeps placeholder SVG if present).", + ) + parser.add_argument( + "--skip-assets", + action="store_true", + help="Mirror wiki pages but skip downloading referenced assets.", + ) + parser.add_argument( + "--continue-on-asset-error", + action="store_true", + help="Continue mirroring even if some assets fail to download.", + ) + args = parser.parse_args() + + docs_dir = Path(args.docs_dir) + wiki_out = Path(args.wiki_out) + assets_out = Path(args.assets_out) + + if args.clean: + # Remove old mirrored pages. + if wiki_out.exists(): + for p in wiki_out.rglob("*.md"): + try: + p.unlink() + except Exception: + pass + # Remove old downloaded assets (but keep the committed placeholder if present). + if assets_out.exists(): + for p in assets_out.rglob("*"): + if p.is_dir(): + continue + if p.name in {"osf_asset_unavailable.svg"}: + continue + try: + p.unlink() + except Exception: + pass + + wikis_url = f"{_OSF_API}/nodes/{args.node}/wikis/?page[size]={args.page_size}" + wiki_items = list(_iter_osf_collection(wikis_url, token=args.token)) + + pages = [] + all_asset_urls: set[str] = set() + asset_sources: Dict[str, Set[str]] = {} + asset_failures: Dict[str, dict] = {} + for item in wiki_items: + wiki_id = item.get("id") + attrs = item.get("attributes") or {} + name = attrs.get("name") or wiki_id + + markdown = _fetch_wiki_markdown(wiki_id, token=args.token) + + filename = _safe_filename(name) + ".md" + out_path = wiki_out / filename + _write_text_exact(out_path, markdown) + + # Paths in index.md are relative to docs/osf_wiki/index.md. + pages.append((name, filename)) + urls = _extract_osf_file_urls(markdown) + all_asset_urls.update(urls) + for u in urls: + asset_sources.setdefault(u, set()).add(f"osf_wiki/{filename}") + + # Download assets and write manifest for mkdocs_hooks.py rewrite. + manifest: dict[str, str] = {} + if not args.skip_assets: + for url in sorted(all_asset_urls): + parsed = urllib.parse.urlparse(url) + file_id = parsed.path.rstrip("/").split("/")[-1] or "osf_file" + base_out = assets_out / file_id + try: + final_path = _download(url, base_out, token=args.token) + except Exception as e: + if args.continue_on_asset_error: + refs = sorted(asset_sources.get(url, set())) + ref_msg = f" (referenced by: {', '.join(refs)})" if refs else "" + print(f"[warn] Failed to download asset {url}{ref_msg}: {e}") + asset_failures[url] = { + "error": str(e), + "referenced_by": refs, + } + continue + raise + rel = os.path.relpath(final_path, docs_dir) + manifest[url] = rel.replace(os.sep, "/") + + assets_out.mkdir(parents=True, exist_ok=True) + (assets_out / "manifest.json").write_text( + json.dumps(manifest, indent=2, sort_keys=True) + "\n", encoding="utf-8" + ) + (assets_out / "missing_assets.json").write_text( + json.dumps(asset_failures, indent=2, sort_keys=True) + "\n", encoding="utf-8" + ) + + # Generate a browsable index for MkDocs (without editing mirrored pages). + pages_md_lines = [ + "# OSF Wiki (Mirrored)\n", + "\n", + "These pages are mirrored from the OSF wiki and stored in-repo for local viewing.\n", + "\n", + "To regenerate the mirror:\n", + "\n", + "```bash\n", + f"python3 tools/mirror_osf_wiki.py --node {args.node} --continue-on-asset-error\n", + "```\n", + "\n", + ] + if asset_failures: + pages_md_lines.append( + f"Some OSF-hosted assets could not be downloaded (e.g. HTTP 403). " + f"See [Missing Assets](missing-assets.md).\n" + ) + pages_md_lines.append("\n") + pages_md_lines.append("## Pages\n\n") + for name, rel in sorted(pages, key=lambda x: x[0].lower()): + pages_md_lines.append(f"- [{name}]({rel})\n") + _write_text_exact(wiki_out / "index.md", "".join(pages_md_lines)) + + # Missing assets report (human-readable). + missing_lines = ["# Missing Assets\n\n"] + if not asset_failures: + missing_lines.append("All referenced OSF assets were downloaded successfully.\n") + else: + missing_lines.append( + "Some OSF-hosted assets referenced by the wiki could not be downloaded.\n\n" + ) + missing_lines.append( + "Common causes:\n\n- The asset belongs to a different OSF project you cannot access\n" + "- The asset is private or restricted\n\n" + ) + missing_lines.append("## Details\n\n") + for url, info in sorted(asset_failures.items(), key=lambda x: x[0]): + missing_lines.append(f"- `{url}`\n") + missing_lines.append(f" - Error: `{info.get('error','')}`\n") + refs = info.get("referenced_by") or [] + if refs: + missing_lines.append(f" - Referenced by: {', '.join(f'`{r}`' for r in refs)}\n") + _write_text_exact(wiki_out / "missing-assets.md", "".join(missing_lines)) + + print(f"Mirrored {len(pages)} wiki pages to: {wiki_out}") + print(f"Downloaded {len(manifest)} assets to: {assets_out}") + print(f"Wrote manifest: {assets_out / 'manifest.json'}") + if asset_failures: + print(f"Wrote missing assets: {assets_out / 'missing_assets.json'}") + print(f"Wrote missing report: {wiki_out / 'missing-assets.md'}") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tools/promote_osf_wiki_to_docs.py b/tools/promote_osf_wiki_to_docs.py new file mode 100644 index 0000000..10d880b --- /dev/null +++ b/tools/promote_osf_wiki_to_docs.py @@ -0,0 +1,88 @@ +import argparse +from pathlib import Path + + +def _write_text_exact(path: Path, content: str) -> None: + if content and not content.endswith("\n"): + content += "\n" + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(content, encoding="utf-8") + + +def main() -> int: + parser = argparse.ArgumentParser( + description="Copy mirrored OSF wiki pages from docs/osf_wiki into the main docs/*.md files used by mkdocs.yml nav.", + ) + parser.add_argument( + "--docs-dir", + default="docs", + help="Docs directory (default: docs).", + ) + parser.add_argument( + "--osf-wiki-dir", + default="docs/osf_wiki", + help="Mirrored OSF wiki directory (default: docs/osf_wiki).", + ) + parser.add_argument( + "--dry-run", + action="store_true", + help="Print what would change without writing files.", + ) + args = parser.parse_args() + + docs_dir = Path(args.docs_dir) + osf_dir = Path(args.osf_wiki_dir) + if not docs_dir.exists(): + raise SystemExit(f"docs dir not found: {docs_dir}") + if not osf_dir.exists(): + raise SystemExit( + f"OSF wiki dir not found: {osf_dir}. Run tools/mirror_osf_wiki.py first." + ) + + mapping = { + # Home + "home.md": "index.md", + # Installation + "1. Installation - Python.md": "Installation-Python.md", + "2. Installation - R.md": "Installation-R.md", + # Usage + "3. Plotting Substitutions.md": "Plotting-Substitutions.md", + "4. Plotting Indels.md": "Plotting-Indels.md", + "5. Plotting Dinucleotides.md": "Plotting-Dinucleotides.md", + "6. Plotting a Sample Portrait.md": "Plotting-a-Sample-Portrait.md", + "7. Example Program.md": "Example-Program.md", + } + + missing_sources = [] + for src_name in mapping: + src_path = osf_dir / src_name + if not src_path.exists(): + missing_sources.append(src_name) + if missing_sources: + raise SystemExit( + "Missing expected OSF wiki pages:\n" + + "\n".join(f"- {name}" for name in missing_sources) + ) + + changed = 0 + for src_name, dst_name in mapping.items(): + src_path = osf_dir / src_name + dst_path = docs_dir / dst_name + content = src_path.read_text(encoding="utf-8") + + if args.dry_run: + print(f"{src_path} -> {dst_path}") + continue + + _write_text_exact(dst_path, content) + changed += 1 + + if not args.dry_run: + print(f"Updated {changed} docs pages from {osf_dir}") + print("Preview with: python3 -m mkdocs serve") + + return 0 + + +if __name__ == "__main__": + raise SystemExit(main())