diff --git a/products/jbrowse-web/src/Loader.tsx b/products/jbrowse-web/src/Loader.tsx index 51e67fe180..42aac4c64d 100644 --- a/products/jbrowse-web/src/Loader.tsx +++ b/products/jbrowse-web/src/Loader.tsx @@ -53,14 +53,6 @@ function NoConfigMessage() { Configuration not found. You may have arrived here if you requested a config that does not exist or you have not set up your JBrowse yet. - -

- If you want to complete your setup, visit our{' '} - - Quick start guide - -

- {inDevelopment ? ( <>
Sample JBrowse configs:
@@ -192,9 +184,10 @@ const ErrMessage = ({ err }: { err: unknown }) => { > No config.json found. If you want to learn how to complete your setup, visit our{' '} - - Quick start guide + + quick start guide + . ) : ( Loading...}> diff --git a/website/docs/Makefile b/website/docs/Makefile index f8be5806c9..909ab4a3be 100755 --- a/website/docs/Makefile +++ b/website/docs/Makefile @@ -25,7 +25,7 @@ cli.md: ../../products/jbrowse-cli/README.md cp $^ $@ combined.md: $(SRC_FILES) - (echo '---\ntitle: JBrowse 2 combined guide\nid: combined\n---\n\nThis document is a collection of all our documentation. It includes our quick start guide, user guide, configuration guide, CLI guide, developer guide, and FAQ. You can browse the other documents individually, but this page is to help simple ctrl+f searching and easy browsing. You can also download a pdf version of these same docs located at https://jbrowse.org/jb2/jbrowse2.pdf\n\nimport Figure from "./figure"' && for f in $^; do cat $$f | node md_parser.js; done) > $@ + (echo '---\ntitle: Consolidated docs\nid: combined\n---\n\nThis document is a collection of all our documentation. It includes our quick start guides, user guides, configuration guides, CLI guides, developer guides, and FAQ.\n:::info Note\nYou can browse the other documents individually using the sidebar on the left. **This page is to help simplify `ctrl+f` searching and easy browsing.**\n:::\nYou can also download a pdf version of these same docs located at https://jbrowse.org/jb2/jbrowse2.pdf.\n\nimport Figure from "./figure"\nimport config from "../docusaurus.config.json"' && for f in $^; do cat $$f | node md_parser.js; done) > $@ clean: git clean -fdx . diff --git a/website/docs/api_guide.md b/website/docs/api_guide.md index b83f3d922e..b5e1a23e2c 100644 --- a/website/docs/api_guide.md +++ b/website/docs/api_guide.md @@ -1,13 +1,13 @@ --- id: api_guide -title: API guide +title: API toplevel: true --- import Figure from './figure' -In this guide, will cover API level documentation e.g. methods that can be -called on different objects and data model formats +This guide will cover the API level documentation for methods and tools +useful to developers looking to enhance JBrowse or write plugins. ## MenuItems objects @@ -108,7 +108,7 @@ As an example, the here is an array of MenuItems and the resulting menu: Users can customize the top-level menu items using these functions that are available on the rootModel: -#### appendMenu +#### `appendMenu` Add a top-level menu @@ -122,7 +122,7 @@ Add a top-level menu The new length of the top-level menus array -#### insertMenu +#### `insertMenu` Insert a top-level menu @@ -137,7 +137,7 @@ Insert a top-level menu The new length of the top-level menus array -#### appendToMenu +#### `appendToMenu` Add a menu item to a top-level menu @@ -152,7 +152,7 @@ Add a menu item to a top-level menu The new length of the menu -#### insertInMenu +#### `insertInMenu` Insert a menu item into a top-level menu @@ -168,7 +168,7 @@ Insert a menu item into a top-level menu The new length of the menu -#### appendToSubMenu +#### `appendToSubMenu` Add a menu item to a sub-menu @@ -183,7 +183,7 @@ Add a menu item to a sub-menu The new length of the sub-menu -#### insertInSubMenu +#### `insertInSubMenu` Insert a menu item into a sub-menu @@ -202,7 +202,7 @@ The new length of the sub-menu ## Extension points In the core codebase, we have the concept of extension points that users can -call or add to +call or add to. The API is @@ -210,22 +210,20 @@ The API is pluginManager.evaluateExtensionPoint(extensionPointName, args) ``` -There is also an async version +There is also an async method: ```js pluginManager.evaluateAsyncExtensionPoint(extensionPointName, args) ``` -Users can additionall add to extension points, so that when they are evaluated, -it runs a chain of callbacks that are registered to that extension point - -This looks like +Users can additionally add to extension points, so that when they are evaluated, +it runs a chain of callbacks that are registered to that extension point: ```js pluginManager.addToExtensionPoint(extensionPointName, callback => newArgs) ``` -Here are the extension points in the core codebase +Here are the extension points in the core codebase: ### Core-extendPluggableElement @@ -268,4 +266,4 @@ hierarchical track menu when tracks are added to the selection Users that want to add further extension points can do so. The naming system, "Core-" just refers to the fact that these extension points are from our core -codebase. Plugin developers may choose their own prefix to avoid collisions +codebase. Plugin developers may choose their own prefix to avoid collisions. diff --git a/website/docs/config_guide.md b/website/docs/config_guide.md index 2ef097c809..1487b89c55 100644 --- a/website/docs/config_guide.md +++ b/website/docs/config_guide.md @@ -6,6 +6,12 @@ toplevel: true import Figure from './figure' +The following guide provides comprehensive information regarding the anatomy and usage of the `config.json` file that is critical for running a JBrowse 2 session. + +:::info +To learn how to configure JBrowse with assemblies and tracks using the [CLI](./tutorials/config_cli) or the [GUI](./tutorials/config_gui) checkout those respective tutorials. +::: + ## Intro to the config.json A JBrowse 2 configuration file, a config.json, is structured as follows @@ -31,7 +37,7 @@ A JBrowse 2 configuration file, a config.json, is structured as follows } ``` -The most important thing to configure are your assemblies and your tracks +The most important thing to configure are your assemblies and your tracks. ### Configuring assemblies @@ -39,9 +45,9 @@ An assembly configuration includes the "name" of your assembly, any "aliases" that might be associated with that assembly e.g. GRCh37 is sometimes seen as an alias for hg19, and then a "sequence" configuration containing a reference sequence track config. This is provides a special "track" that is outside the -normal track config +normal track config. -Here is a complete config.json file containing only a hg19 +Here is a complete config.json file containing only an hg19 assembly: ```json { @@ -88,9 +94,9 @@ Here is a complete config.json file containing only a hg19 ## Configuring reference name aliasing Reference name aliasing is a process to make chromosomes that are named slightly -differently but which refer to the same thing render properly +differently but which refer to the same thing render properly. -The refNameAliases in the above config provides this functionality +The refNameAliases in the above config provides this functionality: ```json "refNameAliases": { @@ -104,10 +110,8 @@ The refNameAliases in the above config provides this functionality } ``` -The hg19_aliases then is a tab delimited file that looks like this - -The first column should be the names that are in your FASTA sequence, and the -rest of the columns are aliases +The hg19_aliases then is a tab delimited file that looks like the following; the first column should be the names that are in your FASTA sequence, and the +rest of the columns are aliases: ``` 1 chr1 @@ -137,15 +141,15 @@ Y chrY M chrM MT ``` -Note that "chromAliases" files from UCSC match this format - -https://hgdownload.soe.ucsc.edu/goldenPath/canFam6/bigZips/canFam6.chromAlias.txt +:::note +"chromAliases" files [from UCSC](https://hgdownload.soe.ucsc.edu/goldenPath/canFam6/bigZips/canFam6.chromAlias.txt) match this format. +::: ## Adding an assembly with the CLI -Generally we add a new assembly with the CLI using something like +Generally we add a new assembly with the CLI using something like: -```sh +```bash # use samtools to make a fasta index for your reference genome samtools faidx myfile.fa @@ -157,12 +161,13 @@ myfile.fa and myfile.fa.fai to your data folder at /var/www/html/jbrowse2 jbrowse add-assembly myfile.fa --load copy --out /var/www/html/jbrowse2 ``` -See our CLI docs for the add-assembly for more details here -- -[add-assembly](../cli#jbrowse-add-assembly-sequence) +See our [configure JBrowse using the cli](../tutorials/config_cli/#adding-a-genome-assembly) tutorial for more in-depth instructions, or more +information on the `add-assembly` command through our [CLI tools guide](../cli/#jbrowse-add-assembly-sequence). -Note: assemblies can also be added graphically using the assembly manager when -you are using the admin-server. See the [quickstart -guide](../quickstart_gui#adding-an-assembly) for more details. +:::note +Assemblies can also be added graphically using the assembly manager when +you are using the `admin-server`. See how to [configure JBrowse using the GUI](../tutorials/config_gui/#adding-a-genome-assembly) for more details. +::: ## Assembly config @@ -170,11 +175,11 @@ Because JBrowse 2 can potentially have multiple assemblies loaded at once, it needs to make sure each track is associated with an assembly. To do this, we make assemblies a special part of the config, and make sure each -track refers to which genome assembly it uses +track refers to which genome assembly it uses. ### Example config with hg19 genome assembly loaded -Here is a complete config.json that has the hg19 genome loaded +Here is a complete config.json that has the hg19 genome loaded: ```json { @@ -218,9 +223,7 @@ Here is a complete config.json that has the hg19 genome loaded } ``` -The top level config is an array of assemblies - -Each assembly contains +The top level config is an array of assemblies; each assembly contains: - `name` - a name to refer to the assembly by. each track that is related to this assembly references this name @@ -241,7 +244,7 @@ Each assembly contains ### ReferenceSequenceTrack Example ReferenceSequenceTrack config, which as above, is specified as the -child of the assembly section of the config +child of the assembly section of the config: ```json { @@ -272,7 +275,7 @@ child of the assembly section of the config A bgzip FASTA format file is generated by -```sh +```bash bgzip -i sequence.fa samtools faidx sequence.fa.gz @@ -306,7 +309,7 @@ These are loaded into a BgzipFastaAdapter as follows An indexed FASTA file is similar to the above, but the sequence is not compressed -```sh +```bash samtools faidx sequence.fa ## above commands generate the .fa and .fai files @@ -380,16 +383,16 @@ Optionally you can specify a .chrom.sizes file which will speed up loading the 2 ## Track configurations -All tracks can contain +All tracks can contain: -- trackId - internal track ID, must be unique -- name - displayed track name -- assemblyNames - an array of assembly names a track is associated with, often +- `trackId` - internal track ID, must be unique +- `name` - displayed track name +- `assemblyNames` - an array of assembly names a track is associated with, often just a single assemblyName -- category - (optional) array of categories to display in a hierarchical track +- `category` - (optional) array of categories to display in a hierarchical track selector -Example config.json containing a track config +Example `config.json` containing a track config: ```json { @@ -439,7 +442,7 @@ Example config.json containing a track config ### AlignmentsTrack config -Example AlignmentsTrack config +Example AlignmentsTrack config: ```json { @@ -465,12 +468,12 @@ Example AlignmentsTrack config #### BamAdapter configuration options -- bamLocation - a 'file location' for the BAM -- index: a subconfiguration schema containing +- `bamLocation` - a 'file location' for the BAM +- `index` - a subconfiguration schema containing - indexType: options BAI or CSI. default: BAI - location: a 'file location' of the index -Example BamAdapter config +Example BamAdapter config: ```json { @@ -490,10 +493,10 @@ Example BamAdapter config #### CramAdapter configuration options -- cramLocation - a 'file location' for the CRAM -- craiLocation - a 'file location' for the CRAI +- `cramLocation` - a 'file location' for the CRAM +- `craiLocation` - a 'file location' for the CRAI -Example CramAdapter config +Example CramAdapter config: ```json { @@ -511,7 +514,7 @@ Example CramAdapter config ### HicTrack config -Example Hi-C track config +Example Hi-C track config: ```json { @@ -531,7 +534,7 @@ Example Hi-C track config #### HicAdapter config -We just simply supply a hicLocation currently for the HicAdapter +We just simply supply a `hicLocation` currently for the HicAdapter: ```json { @@ -556,10 +559,10 @@ We just simply supply a hicLocation currently for the HicAdapter ### VariantTrack config -- defaultRendering - options: 'pileup' or 'svg'. default 'svg' -- adapter - a variant type adapter config e.g. a VcfTabixAdapter +- `defaultRendering` - options: 'pileup' or 'svg'. default 'svg' +- `adapter` - a variant type adapter config e.g. a VcfTabixAdapter -Example config +Example config: ```json { @@ -585,12 +588,12 @@ Example config #### VcfTabixAdapter configuration options -- vcfGzLocation - a 'file location' for the BigWig -- index: a subconfiguration schema containing +- `vcfGzLocation` - a 'file location' for the BigWig +- `index` - a subconfiguration schema containing - indexType: options TBI or CSI. default TBI - location: the location of the index -Example VcfTabixAdapter adapter config +Example VcfTabixAdapter adapter config: ```json { @@ -610,7 +613,7 @@ Example VcfTabixAdapter adapter config ### MultiQuantitativeTrack config -Example MultiQuantitativeTrack config +Example MultiQuantitativeTrack config: ```json { @@ -654,9 +657,9 @@ You can pass an array of urls for bigWig files to the "bigWigs" slot for MultiWiggleAdapter, or an array of complete subtrack adapter configs to the "subadapters" slot for MultiWiggleAdapter. The subadapters slot can contain extra fields such as color, which is interpreted as the subtrack color, and any -accessory fields like "group" that might help end users organize the subtracks +accessory fields like "group" that might help end users organize the subtracks. -Example with group field +Example with group field: ```json { @@ -694,7 +697,7 @@ label (where, "source" will be given priority over "name" if specified) ### QuantitativeTrack config -Example QuantitativeTrack config +Example QuantitativeTrack config: ```json { @@ -714,49 +717,49 @@ Example QuantitativeTrack config #### General QuantitativeTrack options -- scaleType - options: linear, log, to display the coverage data. default: linear -- adapter - an adapter that returns numeric signal data, e.g. feature.get('score') +- `scaleType` - options: linear, log, to display the coverage data. default: linear +- `adapter` - an adapter that returns numeric signal data, e.g. feature.get('score') #### Autoscale options for QuantitativeTrack -Options for autoscale +Options for autoscale: -- local - min/max values of what is visible on the screen -- global - min/max values in the entire dataset -- localsd - mean value +- N stddevs of what is visible on screen -- globalsd - mean value +/- N stddevs of everything in the dataset +- `local` - min/max values of what is visible on the screen +- `global` - min/max values in the entire dataset +- `localsd` - mean value +- N stddevs of what is visible on screen +- `globalsd` - mean value +/- N stddevs of everything in the dataset #### Score min/max for QuantitativeTrack These options overrides the autoscale options and provides a minimum or maximum -value for the autoscale bar +value for the autoscale bar: - minScore - maxScore #### QuantitativeTrack drawing options -- inverted - draws upside down -- defaultRendering - can be density, xyplot, or line -- summaryScoreMode - options: min, max, whiskers +- `inverted` - draws upside down +- `defaultRendering` - can be density, xyplot, or line +- `summaryScoreMode` - options: min, max, whiskers #### QuantitativeTrack renderer options -- filled - fills in the XYPlot histogram -- bicolorPivot - options: numeric, mean, none. default: numeric -- bicolorPivotValue - number at which the color switches from posColor to +- `filled` - fills in the XYPlot histogram +- `bicolorPivot` - options: numeric, mean, none. default: numeric +- `bicolorPivotValue` - number at which the color switches from posColor to negColor. default: 0 -- color - color or color callback for drawing the values. overrides +- `color` - color or color callback for drawing the values. overrides posColor/negColor. default: none -- posColor - color to draw "positive" values. default: red -- negColor - color to draw "negative" values. default: blue -- clipColor - color to draw "clip" indicator. default: red +- `posColor` - color to draw "positive" values. default: red +- `negColor` - color to draw "negative" values. default: blue +- `clipColor` - color to draw "clip" indicator. default: red #### BigWigAdapter options -- bigWigLocation - a 'file location' for the bigwig +- `bigWigLocation` - a 'file location' for the bigwig -Example BigWig adapter config +Example BigWig adapter config: ```json { @@ -770,7 +773,7 @@ Example BigWig adapter config ### SyntenyTrack config -Example SyntenyTrack config +Example SyntenyTrack config: ```json { @@ -788,22 +791,22 @@ Example SyntenyTrack config } ``` -We can load a SyntenyTrack from PAF with the CLI e.g. with +We can load a SyntenyTrack from PAF with the CLI e.g. with: -```sh +```bash jbrowse add-track myfile.paf --type SyntenyTrack --assemblyNames \ grape,peach --load copy --out /var/www/html/jbrowse2 ``` -The first assembly is the "target" and the second assembly is the "query" +The first assembly is the "target" and the second assembly is the "query." -See the [super quickstart guide](../superquickstart_web) for more recipes on -loading synteny tracks with the CLI. +See how to [configure JBrowse using the CLI](../tutorials/config_cli/#adding-a-synteny-track) for more ways to +load synteny tracks with the CLI. ### PAFAdapter config The PAF adapter reflects a pairwise alignment, and is outputted by tools like -minimap2. It can be used for SyntenyTracks +minimap2. It can be used for SyntenyTracks: ```json { @@ -817,20 +820,20 @@ minimap2. It can be used for SyntenyTracks Slots -- pafLocation - the location of the PAF file. The pafLocation can refer to a +- `pafLocation` - the location of the PAF file. The pafLocation can refer to a gzipped or unzipped delta file. It will be read into memory entirely as it is not an indexed file format. -- assemblyNames - list of assembly names, typically two (first in list is +- `assemblyNames` - list of assembly names, typically two (first in list is target, second is query) -- queryAssembly - alternative to assemblyNames: just the assemblyName of the +- `queryAssembly` - alternative to assemblyNames: just the assemblyName of the query -- targetAssembly - alternative to assemblyNames: just the assemblyName of the +- `targetAssembly` - alternative to assemblyNames: just the assemblyName of the target ### DeltaAdapter config The DeltaAdapter is used to load .delta files from MUMmer/nucmer. It can be -used for SyntenyTracks +used for SyntenyTracks: ```json { @@ -844,20 +847,20 @@ used for SyntenyTracks Slots -- deltaLocation - the location of the delta file. The deltaLocation can refer to a +- `deltaLocation` - the location of the delta file. The deltaLocation can refer to a gzipped or unzipped delta file. It will be read into memory entirely as it is not an indexed file format. -- assemblyNames - list of assembly names, typically two (first in list is +- `assemblyNames` - list of assembly names, typically two (first in list is target, second is query) -- queryAssembly - alternative to assemblyNames: just the assemblyName of the +- `queryAssembly` - alternative to assemblyNames: just the assemblyName of the query -- targetAssembly - alternative to assemblyNames: just the assemblyName of the +- `targetAssembly` - alternative to assemblyNames: just the assemblyName of the target ### ChainAdapter config The ChainAdapter is used to load .chain files from MUMmer/nucmer. It can be -used for SyntenyTracks +used for SyntenyTracks: ```json { @@ -871,19 +874,19 @@ used for SyntenyTracks Slots -- chainLocation - the location of the UCSC chain file. The chainLocation can +- `chainLocation` - the location of the UCSC chain file. The chainLocation can refer to a gzipped or unzipped delta file. It will be read into memory entirely as it is not an indexed file format. -- assemblyNames - list of assembly names, typically two (first in list is +- `assemblyNames` - list of assembly names, typically two (first in list is target, second is query) -- queryAssembly - alternative to assemblyNames: just the assemblyName of the +- `queryAssembly` - alternative to assemblyNames: just the assemblyName of the query -- targetAssembly - alternative to assemblyNames: just the assemblyName of the +- `targetAssembly` - alternative to assemblyNames: just the assemblyName of the target ### MCScanAnchorsAdapter -The .anchors file from MCScan refers to pairs of homologous genes and can be loaded into synteny tracks in jbrowse 2 +The .anchors file from MCScan refers to pairs of homologous genes and can be loaded into synteny tracks in JBrowse 2: ```json { @@ -901,20 +904,20 @@ The .anchors file from MCScan refers to pairs of homologous genes and can be loa } ``` -The guide at https://github.com/tanghaibao/jcvi/wiki/MCscan-(Python-version) +[This guide]() shows a demonstration of how to create the anchors and bed files (the .bed files are intermediate steps in creating the anchors files and are required by -the MCScanAnchorsAdapter) +the MCScanAnchorsAdapter). -Slots +Slots: -- mcscanAnchorsLocation - the location of the .anchors file from the MCScan +- `mcscanAnchorsLocation` - the location of the .anchors file from the MCScan workflow. The .anchors file has three columns. It can be gzipped or ungzipped, and is read into memory whole -- bed1Location - the location of the first assemblies .bed file from the MCScan +- `bed1Location` - the location of the first assemblies .bed file from the MCScan workflow. It can be gzipped or ungzipped, and is read into memory whole. This would refer to the gene names on the "left" side of the .anchors file. -- bed2Location - the location of the second assemblies .bed file from the +- `bed2Location` - the location of the second assemblies .bed file from the MCScan workflow. It can be gzipped or ungzipped, and is read into memory whole. This would refer to the gene names on the "right" side of the .anchors file. @@ -922,7 +925,7 @@ Slots ### MCScanSimpleAnchorsAdapter The "simple" .anchors.simple file from MCScan refers to pairs of homologous -genes and can be loaded into synteny tracks in jbrowse 2 +genes and can be loaded into synteny tracks in JBrowse 2: ```json { @@ -940,12 +943,12 @@ genes and can be loaded into synteny tracks in jbrowse 2 } ``` -The guide at https://github.com/tanghaibao/jcvi/wiki/MCscan-(Python-version) +[This guide]() shows a demonstration of how to create the anchors and bed files (the .bed files are intermediate steps in creating the anchors.simple files and are required by the MCScanSimpleAnchorsAdapter) -Slots +Slots: - `mcscanSimpleAnchorsLocation` - the location of the .anchors.simple file from the MCScan workflow (this file has 5 columns, start and end gene from bed1, @@ -971,7 +974,7 @@ the `FromConfigAdapter` and `FromConfigSequenceAdapter`. They can be used as the This adapter can be used to generate features directly from values stored in the configuration. -Example `FromConfigAdapter` +Example `FromConfigAdapter`: ```json { @@ -996,7 +999,7 @@ Example `FromConfigAdapter` Similar behavior to `FromConfigAdapter`, with a specific emphasis on performance when the features are sequences. -Example `FromConfigSequenceAdapter` +Example `FromConfigSequenceAdapter`: ```json { @@ -1022,12 +1025,10 @@ Example `FromConfigSequenceAdapter` ## Text searching -Text searching is now available on JBrowse 2. - Text searching appears in two forms: per-track indexes and aggregate indexes -which search across multiple tracks +which search across multiple tracks. -Aggregate indexes may look like this +Aggregate indexes may look like this: ```json { @@ -1052,7 +1053,7 @@ Aggregate indexes may look like this } ``` -An example per-track config may look like this +An example per-track config may look like this: ```json { @@ -1089,20 +1090,20 @@ An example per-track config may look like this } ``` -Information on generating trix indexes via the cli can be found -[here](../cli#jbrowse-text-index) +Information on generating trix indexes via the CLI can be found +[here](../cli#jbrowse-text-index). ### TrixTextSearchAdapter config -The trix search index is the current file format for name searching +The trix search index is the current file format for name searching. It is based on the UCSC trix file format described here -https://genome.ucsc.edu/goldenPath/help/trix.html +https://genome.ucsc.edu/goldenPath/help/trix.html. -To create trix indexes you can use our command line tools. More info found at +To create trix indexes you can use our command line tools. More info can be found at our [jbrowse text-index guide](../cli#jbrowse-text-index). This tool will automatically generate a config like this. The config slots are described below -for details +for details: ```json { @@ -1125,14 +1126,14 @@ for details } ``` -- ixFilePath - the location of the trix ix file -- ixxFilePath - the location of the trix ixx file -- metaFilePath - the location of the metadata json file for the trix index +- `ixFilePath` - the location of the trix ix file +- `ixxFilePath` - the location of the trix ixx file +- `metaFilePath` - the location of the metadata json file for the trix index ### JBrowse1TextSearchAdapter config -This is more uncommon, but allows back compatibility with a jbrowse 1 names -index created by generate-names.pl +This is more uncommon, but allows back compatibility with a JBrowse1 names +index created by `generate-names.pl`: ```json { @@ -1147,7 +1148,7 @@ index created by generate-names.pl } ``` -- namesIndexLocation - the location of the JBrowse1 names index data directory +- `namesIndexLocation` - the location of the JBrowse1 names index data directory ## DotplotView config @@ -1157,7 +1158,7 @@ initialize a dotplot view. ## LinearSyntenyView config It is recommended to use the LinearSyntenyView's importform or a session spec -to initialize a dotplot view. +to initialize a linear synteny view. ## Configuring the theme @@ -1187,7 +1188,7 @@ theme:
-The customized theme screenshot uses the below configuration +The customized theme screenshot uses the below configuration: | | Color code | Color | | ---------- | ---------- | ----------- | @@ -1259,7 +1260,7 @@ options you could pass to Material-UI's [`createMuiTheme`](https://material-ui.com/customization/theming/#createmuitheme-options-args-theme) should work in the theme configuration. -## Disabling analytics +## Disabiling analytics This is done via adding a field in the global configuration in the config file. For example: @@ -1272,102 +1273,95 @@ For example: } ``` -### Configuration callbacks +## Configuration callbacks -We use Jexl (see https://github.com/TomFrost/Jexl) for defining configuration +We use [Jexl](https://github.com/TomFrost/Jexl) for defining configuration callbacks. -An example of a Jexl configuration callback might look like this +An example of a Jexl configuration callback might look like this: "color": "jexl:get(feature,'strand')==-1?'red':'blue'" -The notation get(feature,'strand') is the same as feature.get('strand') in +The notation `get(feature,'strand')` is the same as `feature.get('strand')` in javascript code. -We have a number of other functions such as +We have a number of other functions, such as: -Feature operations - get - -``` - -jexl:get(feature,'start') // start coordinate, 0-based half open -jexl:get(feature,'end') // end coordinate, 0-based half open -jexl:get(feature,'refName') // chromosome or reference sequence name -jexl:get(feature,'CIGAR') // BAM or CRAM feature CIGAR string -jexl:get(feature,'seq') // BAM or CRAM feature sequence -jexl:get(feature,'type') // feature type e.g. mRNA or gene +**Feature operations - get** +```js +jexl: get(feature, 'start') // start coordinate, 0-based half open +jexl: get(feature, 'end') // end coordinate, 0-based half open +jexl: get(feature, 'refName') // chromosome or reference sequence name +jexl: get(feature, 'CIGAR') // BAM or CRAM feature CIGAR string +jexl: get(feature, 'seq') // BAM or CRAM feature sequence +jexl: get(feature, 'type') // feature type e.g. mRNA or gene ``` -Feature operations - getTag +**Feature operations - getTag** The getTag function smooths over slight differences in BAM and CRAM features to access their tags -``` -jexl:getTag(feature, 'MD') // fetches MD string from BAM or CRAM feature -jexl:getTag(feature, 'HP') // fetches haplotype tag from BAM or CRAM feature - -``` - -String functions - -``` -jexl:charAt('abc',2) // c -jexl:charCodeAt(' ',0) // 32 -jexl:codePointAt(' ',0) // 32 -jexl:startsWith('kittycat','kit') // true -jexl:endsWith('kittycat','cat') // true -jexl:padStart('cat', 8, 'kitty') // kittycat -jexl:padEnd('kitty', 8, 'cat') // kittycat -jexl:replace('kittycat','cat','') // kitty -jexl:replaceAll('kittycatcat','cat','') // kitty -jexl:slice('kittycat',5) // cat -jexl:substring('kittycat',0,5) // kitty -jexl:trim(' kitty ') // kitty, whitespace trimmed -jexl:trimStart(' kitty ') // kitty, starting whitespace trimmed -jexl:trimEnd(' kitty ') // kitty, ending whitespace trimmed -jexl:toUpperCase('kitty') // KITTY -jexl:toLowerCase('KITTY') // kitty -jexl:split('KITTY KITTY', ' ') // ['KITTY', 'KITTY'] -``` - -Math functions - +```js +jexl: getTag(feature, 'MD') // fetches MD string from BAM or CRAM feature +jexl: getTag(feature, 'HP') // fetches haplotype tag from BAM or CRAM feature ``` -jexl:max(0,2) -jexl:min(0,2) -jexl:sqrt(4) -jexl:ceil(0.5) -jexl:floor(0.5) -jexl:round(0.5) -jexl:abs(-0.5) -jexl:log10(50000) -jexl:parseInt('2') -jexl:parseFloat('2.054') +**String functions** +```js +jexl: charAt('abc', 2) // c +jexl: charCodeAt(' ', 0) // 32 +jexl: codePointAt(' ', 0) // 32 +jexl: startsWith('kittycat', 'kit') // true +jexl: endsWith('kittycat', 'cat') // true +jexl: padStart('cat', 8, 'kitty') // kittycat +jexl: padEnd('kitty', 8, 'cat') // kittycat +jexl: replace('kittycat', 'cat', '') // kitty +jexl: replaceAll('kittycatcat', 'cat', '') // kitty +jexl: slice('kittycat', 5) // cat +jexl: substring('kittycat', 0, 5) // kitty +jexl: trim(' kitty ') // kitty, whitespace trimmed +jexl: trimStart(' kitty ') // kitty, starting whitespace trimmed +jexl: trimEnd(' kitty ') // kitty, ending whitespace trimmed +jexl: toUpperCase('kitty') // KITTY +jexl: toLowerCase('KITTY') // kitty +jexl: split('KITTY KITTY', ' ') // ['KITTY', 'KITTY'] ``` -Console logging +**Math functions** +```js +jexl: max(0, 2) +jexl: min(0, 2) +jexl: sqrt(4) +jexl: ceil(0.5) +jexl: floor(0.5) +jexl: round(0.5) +jexl: abs(-0.5) +jexl: log10(50000) +jexl: parseInt('2') +jexl: parseFloat('2.054') ``` -jexl:log(feature) // console.logs output and returns value -jexl:cast({'mRNA':'green','pseudogene':'purple'})[get(feature,'type')] // returns either green or purple depending on feature type +**Console logging** +```js +jexl: log(feature) // console.logs output and returns value +jexl: cast({ mRNA: 'green', pseudogene: 'purple' })[get(feature, 'type')] // returns either green or purple depending on feature type ``` -Binary operators +**Binary operators** -``` -jexl:get(feature,'flags')&2 // bitwise and to check if BAM or CRAM feature flags has 2 set +```js +jexl: get(feature, 'flags') & 2 // bitwise and to check if BAM or CRAM feature flags has 2 set ``` -## Customizing feature details panels +## Customizing the feature details panel -Every track has a configuration called `formatDetails` +Every track has a configuration called `formatDetails`. -Here is an example track with a formatter +Here is an example track with a formatter: ```json { @@ -1401,7 +1395,7 @@ link to gene pages for example as well. In addition, this example also adds a custom field called `"newfield"` and removes e.g. `"type"` from being displayed. -The schema for `formatDetails` is +The schema for `formatDetails` is: - `feature` - customizes the top-level feature - `subfeatures` - customizes the subfeatures, recursively up to `depth` @@ -1410,7 +1404,7 @@ The schema for `formatDetails` is The general way this is done is by making a jexl callback either or both of `feature` and `subfeatures` (if you want both feature and subfeatures, you can copy the same thing to both config slots). -The callback returns an object where the keys of the object are what you want to replace +The callback returns an object where the keys of the object are what you want to replace. In the example above we return an object with: @@ -1447,3 +1441,41 @@ Then you can use the custom jexl function in your config callbacks as follows: ... } ``` + +See our [developer guides](../developer_guide/) for more information regarding plugin development. + +## Configuring plugins + +External published plugins can be added to the configuration like so: + +```json +{ + "plugins": [ + { + "name": "GDC", + "url": "https://unpkg.com/jbrowse-plugin-gdc/dist/jbrowse-plugin-gdc.umd.production.min.js" + } + ] +} +``` + +Published plugins are typically hosted on unpkg and can be referenced as above. + +Any tools that are available via that plugin will then be added to JBrowse. You can verify the plugin is installed properly by checking the Plugin Store: + +
+ +If you have an unpublished plugin running locally, you can add that plugin to your configuration using the localhost the plugin is running on: + +```json +{ + "plugins": [ + { + "name": "GDC", + "url": "http://localhost:9000/dist/jbrowse-plugin-gdc.umd.development.js" + } + ] +} +``` + +Checkout our [developer guide](../developer_guide/) for more information on developing plugins, or our [plugins page](/plugins) to browse currently published plugins. diff --git a/website/docs/developer_guide.md b/website/docs/developer_guide.md index 4c8f007133..d08fe49c29 100644 --- a/website/docs/developer_guide.md +++ b/website/docs/developer_guide.md @@ -1,12 +1,12 @@ --- id: developer_guide -title: Developer guide +title: Core concepts and intro to pluggable elements toplevel: true --- import Figure from './figure' -In this guide, will introduce the JBrowse 2 ecosystem from the developer's +This guide will introduce the JBrowse 2 ecosystem from the developer's point of view. We'll examine the core concepts of how code is packaged and structured, and then go over how to create new plugins and pluggable elements. @@ -16,7 +16,7 @@ Let's get a high-level view of the JBrowse 2 ecosystem. ## Products and plugins -The JBrowse 2 ecosystem has two main type of top-level artifacts that are +The JBrowse 2 ecosystem has two main types of top-level artifacts that are published on their own: products and plugins.
@@ -31,7 +31,7 @@ by anyone, not just the JBrowse core team. Not all of the products use plugins, but most of them do. Also, most of the products are pretty standard in the way they are constructed. -For example, jbrowse-web is a React web application that is made with [Create +For example, `jbrowse-web` is a React web application that is made with [Create React App (CRA)](https://create-react-app.dev/), and jbrowse-cli is a command-line tool implemented with [OCLIF](https://oclif.io/). @@ -40,12 +40,12 @@ command-line tool implemented with [OCLIF](https://oclif.io/). ## Example plugins You can follow this guide for developing plugins, but you might also want to -refer to working versions of plugins on the web now +refer to working versions of plugins on the web now. This repo contains a template for creating new plugins https://github.com/GMOD/jbrowse-plugin-template. -Here are some examples of working plugins. +Here are some examples of working plugins: - [jbrowse-plugin-ucsc-api](https://github.com/cmdcolin/jbrowse-plugin-ucsc-api) probably the simplest plugin example, it demonstrates accessing data from @@ -78,9 +78,12 @@ A plugin is an independently distributed package of code that is designed to It's implemented as a class that extends `@jbrowse/core/Plugin`. It gets instantiated by the application that it plugs into, and it has an `install` -method and a `configure` method that the application calls. This class is -distributed as a webpack bundle that exports it to a namespace on the browser's -`window` object specifically for JBrowse plugins[^1]. +method and a `configure` method that the application calls. + +This class is distributed as a webpack bundle that exports it to a namespace on the browser's +`window` object specifically for JBrowse plugins. **This means it is only possible +to have one version of a particular plugin loaded on any given webpage, even if multiple +products are loaded and using it on the same page.** It's common for a plugin to use its `configure` method to set up [mobx autoruns or reactions](https://mobx.js.org/refguide/autorun.html) that react to @@ -90,7 +93,12 @@ Plugins often also have their `install` method add "pluggable elements" into the host JBrowse application. This is how plugins can add new kinds of views, tracks, renderers, and so forth. -[^1]: This means it's only possible to have one version of a particular plugin loaded on any given webpage, even if multiple products are loaded and using it on the same page. +:::info Note +Many of the plugins referenced in the following section are found in [the JBrowse Github repo](https://github.com/gmod/jbrowse-components). + +We encourage you to reference and review the concepts presented here using the functinal +and up-to-date plugin code found there. +::: ## Pluggable elements @@ -112,21 +120,40 @@ Pluggable elements are pieces of functionality that plugins can add to JBrowse. In additional to creating plugins that create new adapters, track types, etc. note that you can also wrap the behavior of another track so these -elements are composable +elements are composable. -For example we can have adapters that perform calculations on the results of +For example, we can have adapters that perform calculations on the results of another adapter, views that contains other subviews, and tracks that contain -other tracks, leading to a lot of interesting behavior. Details and examples -below +other tracks, leading to a lot of interesting behavior. + +Let's dive further into these details, and look at some examples. + +### View types + +Creating view types is one of the most powerful features of JBrowse 2, because +it allows us to put entirely different visualizations in the same context as +the standard linear-genome-view. + +We have demonstrated a couple new view types in JBrowse 2 already, including: + +- `LinearGenomeView` - the classic linear view of a genome +- `CircularView` - a Circos-like circular whole genome view +- `DotplotView` - a comparative 2-D genome view +- `SvInspectorView` - superview containing `CircularView` and `SpreadsheetView` + subviews +- And more! + +We think the boundaries for this are just your imagination, and there can also +be interplay between view types e.g. popup dotplot from a linear view, etc. ### Adapters -Adapters basically are parsers for a given data format. We will review +Adapters are parsers for a given data format. We will review what adapters the alignments plugin has (to write your own adapter, -see [creating adapters](#creating-adapters)) +see [creating adapters](../devguide_pluggable_elements/#creating-adapters)). Example adapters: the `@jbrowse/plugin-alignments` plugin creates -multiple adapter types +multiple adapter types: - `BamAdapter` - This adapter uses the `@gmod/bam` NPM module, and adapts it for use by the browser. @@ -139,7 +166,7 @@ multiple adapter types ### Track types Track types are a high level type that controls how features are drawn. In most -cases, a track combines a renderer and an adapter, and can do additional things like +cases, a track combines a renderer and an adapter, and can do additional things like: - Control what widget pops up on feature click - Add extra menu items to the track menu @@ -148,7 +175,7 @@ cases, a track combines a renderer and an adapter, and can do additional things the user scrolls, or "dynamic-blocks" that update on each scroll Example tracks: the `@jbrowse/plugin-alignments` exports multiple track -types +types: - `SNPCoverageTrack` - this track type actually derives from the WiggleTrack type - `PileupTrack` - a track type that draws alignment pileup results @@ -156,10 +183,10 @@ types ### Displays -A display is a method for displaying a particular track in a particular view +A _display_ is a method for displaying a particular track in a particular view. For example, we have a notion of a synteny track type, and the synteny track -type has two display models +type has two display models: - `DotplotDisplay`, which is used in the dotplot view - `LinearSyntenyDisplay`, which is used in the linear synteny view @@ -167,7 +194,7 @@ type has two display models This enables a single track entry to be used in multiple view types e.g. if I run `jbrowse add-track myfile.paf`, this automatically creates a `SyntenyTrack` entry in the tracklist, and when this track is opened in the dotplot view, the -`DotplotDisplay` is used for rendering +`DotplotDisplay` is used for rendering. Another example of a track type with multiple display types is `VariantTrack`, which has two display methods @@ -181,10 +208,10 @@ Renderers are a new concept in JBrowse 2, and are related to the concept of server side rendering (SSR), but can be used not just on the server but also in contexts like the web worker (e.g. the webworker can draw the features to an OffscreenCanvas). For more info see [creating -renderers](#creating-custom-renderers) +renderers](../devguide_pluggable_elements/#creating-renderers). -Example renderers: the `@jbrowse/plugin-alignments` exports several -renderer types +For example, the `@jbrowse/plugin-alignments` exports several +renderer types: - `PileupRenderer` - a renderer type that renders Pileup type display of alignments fetched from the `BamAdapter`/`CramAdapter` @@ -192,12 +219,24 @@ renderer types renderer derives from the wiggle renderer, but does the additional step of drawing the mismatches over the coverage track +:::info Views, tracks, displays, renderers? +If you're confused about what kind of pluggable element you might need to accomplish +your development goals, a way to remember the relationship between these four +pluggable elements is as follows: + +1. A view is a container for anything, views typically _have tracks_ (the linear genome view especially) +2. A track controls the _what_ (kind of data, data adapters used) and _how_ (displays, renderers) of the data you'd like to display, typically within a view +3. A display is a way you might want to display the data on a track, you might have multiple displays for a given view, for example, displays can determine if a feature is drawn with rectangles or with triangles; displays _may_ have renderers +4. A renderer controls how the display is presented, for example what might happen when you mouse over a feature + +::: + ### Widgets Widgets are custom info panels that can show up in side panels, modals, or other -places in an app +places in an app. -Widgets can do multiple types of things including +Widgets can do multiple types of things, including: - Configuration widget - Feature detail widget @@ -207,41 +246,23 @@ Widgets can do multiple types of things including These widgets can be extended via plugins, so for example, the `@jbrowse/plugin-alignments` extends the `BaseFeatureDetailWidget` to -have custom display of the alignments +have custom display of the alignments. - `AlignmentsFeatureDetailWidget` - this provides a custom widget for viewing the feature details of alignments features that customizes the basic feature detail widget -### View types - -Creating view types is one of the most powerful features of JBrowse 2, because -it allows us to put entirely different visualizations in the same context as -the standard linear-genome-view. - -We have demonstrated a couple new view types in JBrowse 2 already including - -- `LinearGenomeView` - the classic linear view of a genome -- `CircularView` - a Circos-like circular whole genome view -- `DotplotView` - a comparative 2-D genome view -- `SvInspectorView` - superview containing `CircularView` and `SpreadsheetView` - subviews -- And more! - -We think the boundaries for this are just your imagination, and there can also -be interplay between view types e.g. popup dotplot from a linear view, etc. - ### RPC methods Plugins can register their own RPC methods, which can allow them to offload custom behaviors to a web-worker or server side process. -The wiggle plugin, for example, registers two custom RPC method types +The wiggle plugin, for example, registers two custom RPC method types: - `WiggleGetGlobalStats` - `WiggleGetMultiRegionStats` -These methods can run in the webworker when available +These methods can run in the webworker when available. ### Add track workflows @@ -249,1199 +270,87 @@ Plugins can register their own React component to display in the "Add track" widget for adding tracks that require custom logic. The Multi-wiggle track is an example of this, it produces a textbox where you can paste a list of files. -### Extension points - -Extension points are a pluggable element type which allows users to add a -callback that is called at an appropriate time. - -See [example for adding context menu items](#adding-track-context-menu-items) -for an example of using extension points - -The basic API is that producers can say - -```js -const ret = pluginManager.evaluateExtensionPoint('ExtensionPointName', { - value: 1, -}) -``` - -And consumers can say - -```js -pluginManager.addToExtensionPoint('ExtensionPointName', arg => { - return arg.value + 1 -}) - -pluginManager.addToExtensionPoint('ExtensionPointName', arg => { - return arg.value + 1 -}) -``` - -In this case, arg that is passed in evaluateExtensionPoint calls all the -callbacks that have been registered by addToExtensionPoint. If multiple -extension points are registered, the return value of the first extension point -is passed as the new argument to the second and so on (they are chained together) - -So in the example above, ret would be `{value:3}` after evaluating the -extension point - -## Common plugin use cases - -### Adding a top-level menu - -These are the menus that appear in the top bar of JBrowse Web and JBrowse -Desktop. By default there are `File` and `Help` menus. You can add your own -menu, or you can add menu items or sub-menus to the existing menus and -sub-menus. - -
- -You add menus in the `configure` method of your plugin. Not all JBrowse -products will have top-level menus, though. JBrowse Web and JBrowse Desktop -have them, but something like JBrowse Linear View (which is an just a single -view designed to be embedded in another page) does not. This means you need to -check whether or not menus are supported using `isAbstractMenuManager` in the -`configure` method. This way the rest of the plugin will still work if there is -not a menu. Here's an example that adds an "Open My View" item to the `File -> Add` menu. +A simple addition to the add track workflow: ```js -import Plugin from '@jbrowse/core/Plugin' -import { isAbstractMenuManager } from '@jbrowse/core/util' -import InfoIcon from '@mui/icons-material/Info' - -class MyPlugin extends Plugin { - name = 'MyPlugin' +// plugins/wiggle/MultiWiggleAddTrackWidget/index.jsx - install(pluginManager) { - // install MyView here - } +import PluginManager from '@jbrowse/core/PluginManager' +import { AddTrackWorkflowType } from '@jbrowse/core/pluggableElementTypes' +import { types } from 'mobx-state-tree' - configure(pluginManager) { - if (isAbstractMenuManager(pluginManager.rootModel)) { - pluginManager.rootModel.appendToSubMenu(['File', 'Add'], { - label: 'Open My View', - icon: InfoIcon, - onClick: session => { - session.addView('MyView', {}) - }, - }) - } - } +// locals +import MultiWiggleWidget from './AddTrackWorkflow' + +export default (pm: PluginManager) => { + pm.addAddTrackWorkflowType( + () => + new AddTrackWorkflowType({ + name: 'Multi-wiggle track', + /* in a separate file, export the react component to render within the track widget, + typically a form to collect relevant data for your track */ + ReactComponent: MultiWiggleWidget, + stateModel: types.model({}), + }), + ) } ``` -This example uses `rootModel.appendToSubMenu`. See [top-level menu -API](../api_guide#rootmodel-menu-api) for more details on available functions. - -### Adding menu items to a custom track - -If you create a custom track, you can populate the track menu items in it using -the `trackMenuItems` property in the track model. For example: - -```js -types - .model({ - // model - }) - .views(self => ({ - trackMenuItems() { - return [ - { - label: 'Menu Item', - icon: AddIcon, - onClick: () => {}, - }, - ] - }, - })) -``` - -Note that it is also common to use this scenario, because the base display may -implement track menu items so this is like getting the superclasses track menu -items +...and ensure you install this component into your larger plugin: ```js -types - .model({ - // model - }) - .views(self => { - const { trackMenuItems: superTrackMenuItems } = self - return { - get trackMenuItems() { - return [ - ...superTrackMenuItems(), - { - label: 'Menu Item', - icon: AddIcon, - onClick: () => {}, - }, - ] - }, - } - }) -``` +// plugins/wiggle/index.jsx -### Adding track context-menu items +// ... -When you right-click in a linear track, a context menu will appear if there are -any menu items defined for it. It's possible to add items to that menu, and you -can also have different menu items based on if the click was on a feature or -not, and based on what feature is clicked. This is done by extending the -`contextMenuItems` view of the display model. Here is an example: +export default class WigglePlugin extends Plugin { + name = 'WigglePlugin' -```js -class SomePlugin extends Plugin { - name = 'SomePlugin' - - install(pluginManager) { - pluginManager.addToExtensionPoint( - 'Core-extendPluggableElement', - pluggableElement => { - if (pluggableElement.name === 'LinearPileupDisplay') { - const { stateModel } = pluggableElement - const newStateModel = stateModel.extend(self => { - const superContextMenuItems = self.contextMenuItems - return { - views: { - contextMenuItems() { - const feature = self.contextMenuFeature - if (!feature) { - // we're not adding any menu items since the click was not - // on a feature - return superContextMenuItems() - } - return [ - ...superContextMenuItems(), - { - label: 'Some menu item', - icon: SomeIcon, - onClick: () => { - // do some stuff - }, - }, - ] - }, - }, - } - }) - - pluggableElement.stateModel = newStateModel - } - return pluggableElement - }, - ) + install(pm: PluginManager) { + // ... + MultiWiggleAddTrackWidgetF(pm) + // ... } } ``` -## Configuration model concepts - -### Configuration slot types - -Our configuration system is "typed" to facilitate graphical editing of the -configuration. Each configuration has a "schema" that lists what -"configuration slots" it has. Each configuration slot has a name, description, -a type, and a value. - -Here is a mostly comprehensive list of config types - -- `stringEnum` - allows assigning one of a limited set of entries, becomes a - dropdown box in the GUI -- `color` - allows selecting a color, becomes a color picker in the GUI -- `number` - allows entering any numeric value -- `string` - allows entering any string -- `integer` - allows entering a integer value -- `boolean -- `frozen` - an arbitrary JSON can be specified in this config slot, becomes - textarea in the GUI -- `fileLocation` - refers to a URL, local file path on desktop, or file blob - object in the browser -- `text` - allows entering a string, becomes textarea in the GUI -- `stringArray` - allows entering a list of strings, becomes a "todolist" style - editor in the GUI where you can add or delete things -- `stringArrayMap` - allows entering a list of key-value entries +### Extension points -Let's examine the `PileupRenderer` configuration as an example. +Extension points are a pluggable element type which allows users to add a +callback that is called at an appropriate time. -### Example config with multiple slot types +Checkout the [full extension point API](../api_guide/#extension-points) or an [example for adding context menu items](../devguide_pluggable_elements/#adding-track-context-menu-items) for more detailed information. -This `PileupRenderer` config contains an example of several different slot types +The basic API is that producers can say: ```js -import { types } from 'mobx-state-tree' -export default ConfigurationSchema('PileupRenderer', { - color: { - type: 'color', - description: 'the color of each feature in a pileup alignment', - defaultValue: `jexl:get(feature,'strand') == - 1 ? '#8F8FD8' : '#EC8B8B'`, - contextVariable: ['feature'], - }, - displayMode: { - type: 'stringEnum', - model: types.enumeration('displayMode', ['normal', 'compact', 'collapse']), - description: 'Alternative display modes', - defaultValue: 'normal', - }, - minSubfeatureWidth: { - type: 'number', - description: `the minimum width in px for a pileup mismatch feature. use for - increasing mismatch marker widths when zoomed out to e.g. 1px or - 0.5px`, - defaultValue: 0, - }, - maxHeight: { - type: 'integer', - description: 'the maximum height to be used in a pileup rendering', - defaultValue: 600, - }, +const ret = pluginManager.evaluateExtensionPoint('ExtensionPointName', { + value: 1, }) ``` -### Accessing config values - -So instead of accessing `config.displayMode`, we say - -```js -readConfObject(config, 'displayMode') -``` - -You might also see in the code like this - -```js -getConf(track, 'maxHeight') -``` - -Which would be equivalent to calling - -```js -readConfObject(track.configuration, 'maxHeight')` -``` - -### Using config callbacks - -Config callbacks allow you to have a dynamic color based on some function logic -you provide. All config slots can actually become config callback. The -arguments that are given to the callback are listed by the 'contextVariable' -but must be provided by the calling code (the code reading the config slot). To -pass arguments to the a callback we say - -```js -readConfObject(config, 'color', { feature }) -``` - -That implies the color configuration callback will be passed a feature, so the -config callback can be a complex function determining the color to use based on -various feature attributes - -### Example of a config callback - -We use Jexl to express callbacks. See https://github.com/TomFrost/Jexl for more details. - -If you had an variant track in your config, and wanted to make a custom config -callback for color, it might look like this - -```json -{ - "type": "VariantTrack", - "trackId": "variant_colors", - "name": "volvox filtered vcf (green snp, purple indel)", - "category": ["VCF"], - "assemblyNames": ["volvox"], - "adapter": { - "type": "VcfTabixAdapter", - "vcfGzLocation": { - "uri": "volvox.filtered.vcf.gz", - "locationType": "UriLocation" - }, - "index": { - "location": { - "uri": "volvox.filtered.vcf.gz.tbi", - "locationType": "UriLocation" - } - } - }, - "displays": [ - { - "type": "LinearVariantDisplay", - "displayId": "volvox_filtered_vcf_color-LinearVariantDisplay", - "renderer": { - "type": "SvgFeatureRenderer", - "color1": "jexl:get(feature,'type')=='SNV'?'green':'purple'" - } - } - ] -} -``` - -This draws all SNV (single nucleotide variants) as green, and other types as -purple (insertion, deletion, other structural variant). - -### Configuration internals - -A configuration is a type of mobx-state-tree model, in which leaf nodes are -ConfigSlot types, and other nodes are ConfigurationSchema types. - -``` - Schema - / | \ - Slot Schema Slot - | \ - Slot Slot -``` - -Configurations are all descendants of a single root configuration, which is -`root.configuration`. - -Configuration types should always be created by the `ConfigurationSchema` -factory, e.g. +And consumers can say: ```js -import { ConfigurationSchema } from '@jbrowse/core/utils/configuration' -const ThingStateModel = types.model('MyThingsState', { - foo: 42, - configuration: ConfigurationSchema('MyThing', { - backgroundColor: { - defaultValue: 'white', - type: 'string', - }, - }), +pluginManager.addToExtensionPoint('ExtensionPointName', arg => { + return arg.value + 1 }) -``` - -An example of a config schema with a sub-config schema is the `BamAdapter`, with -the index sub-config schema - -```js -ConfigurationSchema( - 'BamAdapter', - { - bamLocation: { - type: 'fileLocation', - defaultValue: { uri: '/path/to/my.bam', locationType: 'UriLocation' }, - }, - // this is a sub-config schema - index: ConfigurationSchema('BamIndex', { - indexType: { - model: types.enumeration('IndexType', ['BAI', 'CSI']), - type: 'stringEnum', - defaultValue: 'BAI', - }, - location: { - type: 'fileLocation', - defaultValue: { - uri: '/path/to/my.bam.bai', - locationType: 'UriLocation', - }, - }, - }), - }, - { explicitlyTyped: true }, -) -``` - -Reading the sub-config schema is as follows - -```js -const indexType = readConfObject(config, ['index', 'indexType']) -``` - -Alternatively can use - -```js -const indexConf = readConfObject(config, ['index']) -indexConf.indexType -``` - -However, this may miss default values from the slot, the readConfObject has -special logic to fill in the default value - -## Creating adapters - -### What is an adapter - -An adapter is essentially a class that fetches and parses your data and returns -it in a format JBrowse understands. - -For example, if you have some data source that contains genes, and you want to -display those genes using JBrowse's existing gene displays, you can write a -custom adapter to do so. If you want to do a custom display of your data, -though, you'll probably need to create a custom display and/or renderer along -with your adapter. - -### What types of adapters are there - -- **Feature adapter** - This is the most common type of adapter. Essentially, - it takes a request for a _region_ (a chromosome, starting position, and ending - position) and returns the _features_ (e.g. genes, reads, variants, etc.) that - are in that region. Examples of this in JBrowse include adapters for - [BAM](https://samtools.github.io/hts-specs/SAMv1.pdf) and - [VCF](https://samtools.github.io/hts-specs/VCFv4.3.pdf) file formats. -- **Regions adapter** - This type of adapter is used to define what regions are - in an assembly. It returns a list of chromosomes/contigs/scaffolds and their - sizes. An example of this in JBrowse is an adapter for a - [chrome.sizes](https://software.broadinstitute.org/software/igv/chromSizes) - file. -- **Sequence adapter** - This is basically a combination of a regions adapter - and a feature adapter. It can give the list of regions in an assembly, and - can also return the sequence of a queried region. Examples of this in JBrowse - include adapters for - [FASTA](https://blast.ncbi.nlm.nih.gov/Blast.cgi?CMD=Web&PAGE_TYPE=BlastDocs&DOC_TYPE=BlastHelp) - and [.2bit](https://genome.ucsc.edu/FAQ/FAQformat.html#format7) file formats. -- **RefName alias adapter** - This type of adapter is used to return data about - aliases for reference sequence names, for example to define that "chr1" is an - alias for "1". An example of this in JBrowse is an adapter for - (alias files)[http://software.broadinstitute.org/software/igv/LoadData/#aliasfile] -- **Text search adapter** - This type of adapter is used to search through text search indexes. Returns list of search results. An example of this in JBrowse is the trix text search adapter. - -Note about refname alias adapter: the first column must match what is seen in -your FASTA file - -### Skeleton of a feature adapter - -A basic feature adapter might look like this (with implementation omitted for -simplicity): - -```js -class MyAdapter extends BaseFeatureDataAdapter { - constructor(config) { - // config - } - async getRefNames() { - // return refNames used in your adapter, used for refName renaming - } - - getFeatures(region, opts) { - // region: { - // refName:string, e.g. chr1 - // start:number, 0-based half open start coord - // end:number, 0-based half open end coord - // assemblyName:string, assembly name - // originalRefName:string the name of the refName from the fasta file, e.g. 1 instead of chr1 - // } - // opts: { - // signal?: AbortSignal - // ...rest: all the renderProps() object from the display type - // } - } - - freeResources(region) { - // can be empty - } -} -``` - -So to make a feature adapter, you implement the getRefNames function -(optional), the getFeatures function (returns an rxjs observable stream of -features, discussed below) and freeResources (optional) - -### Example feature adapter - -To take this a little slow let's look at each function individually -This is a more complete description of the class interface that you can implement - -```js -import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter' -import SimpleFeature from '@jbrowse/core/util/simpleFeature' -import { readConfObject } from '@jbrowse/core/configuration' -import { ObservableCreate } from '@jbrowse/core/util/rxjs' - -class MyAdapter extends BaseFeatureDataAdapter { - // your constructor gets a config object that you can read with readConfObject - // if you use "subadapters" then you can initialize those with getSubAdapter - constructor(config, getSubAdapter) { - const fileLocation = readConfObject(config, 'fileLocation') - const subadapter = readConfObject(config, 'sequenceAdapter') - const sequenceAdapter = getSubAdapter(subadapter) - } - - // use rxjs observer.next(new SimpleFeature(...your feature data....) for each - // feature you want to return - getFeatures(region, options) { - return ObservableCreate(async observer => { - try { - const { refName, start, end } = region - const response = await fetch( - 'http://myservice/genes/${refName}/${start}-${end}', - options, - ) - if (response.ok) { - const features = await result.json() - features.forEach(feature => { - observer.next( - new SimpleFeature({ - uniqueID: `${feature.refName}-${feature.start}-${feature.end}`, - refName: feature.refName, - start: feature.start, - end: feature.end, - }), - ) - }) - observer.complete() - } else { - throw new Error(`${response.status} - ${response.statusText}`) - } - } catch (e) { - observer.error(e) - } - }) - } - - async getRefNames() { - // returns the list of refseq names in the file, used for refseq renaming - // you can hardcode this if you know it ahead of time e.g. for your own - // remote data API or fetch this from your data file e.g. from the bam header - return ['chr1', 'chr2', 'chr3'] /// etc - } - - freeResources(region) { - // optionally remove cache resources for a region - // can just be an empty function - } -} -``` - -### What is needed from a feature adapter - -#### getRefNames - -Returns the refNames that are contained in the file, this is -used for "refname renaming" and is optional but highly useful in scenarios -like human chromosomes which have, for example, chr1 vs 1. - -Returning the refNames used by a given file or resource allows JBrowse to -automatically smooth these small naming disparities over. See [reference -renaming](../config_guide#configuring-reference-renaming) - -#### getFeatures - -A function that returns features from the file given a genomic -range query e.g. - -`getFeatures(region, options)` - -The region parameter contains - -```typescript -interface Region { - refName: string - start: number - end: number - originalRefName: string - assemblyName: string -} -``` - -The refName, start, end specify a simple genomic range. The "assemblyName" is -used to query a specific assembly if your adapter responds to multiple -assemblies e.g. for a synteny data file or a REST API that queries a backend -with multiple assemblies. - -The "originalRefName" are also passed, where originalRefName is the queried -refname before ref renaming e.g. in BamAdapter, if the BAM file uses chr1, and -your reference genome file uses 1, then originalRefName will be 1 and refName -will be chr1 - -The options parameter to getFeatures can contain any number of things - -```typescript -interface Options { - bpPerPx: number - signal: AbortSignal - statusCallback: Function - headers: Record -} -``` - -- `bpPerPx` - number: resolution of the genome browser when the features were - fetched -- `signal` - can be used to abort a fetch request when it is no longer needed, - from AbortController -- `statusCallback` - not implemented yet but in the future may allow you to - report the status of your loading operations -- `headers` - set of HTTP headers as a JSON object - -We return an rxjs Observable from getFeatures. This is similar to a JBrowse 1 -getFeatures call, where we pass each feature to a featureCallback, tell it when -we are done with finishCallback, and send errors to errorCallback, except we do -all those things with the Observable - -Here is a "conversion" of JBrowse 1 getFeatures callbacks to JBrowse 2 -observable calls - -- `featureCallback(new SimpleFeature(...))` -> `observer.next(new SimpleFeature(...))` -- `finishCallback()` -> `observer.complete()` -- `errorCallback(error)` -> `observer.error(error)` - -#### freeResources - -This is uncommonly used, so most adapters make this an empty function - -Most adapters in fact use an LRU cache to make resources go away over time -instead of manually cleaning up resources - -## Writing your own plugin - -JBrowse 2 plugins can be used to add new pluggable elements (views, tracks, -adapters, etc), and to modify behavior of the application by adding code that -watches the application's state. For the full list of what kinds of pluggable -element types plugins can add, see the [pluggable -elements](#pluggable-elements) page. - -The first thing that we have is a `src/index.js` which exports a default class -containing the plugin registration code - -src/index.js - -```js -import AdapterType from '@jbrowse/core/pluggableElementTypes/AdapterType' -import Plugin from '@jbrowse/core/Plugin' -import { AdapterClass, configSchema } from './UCSCAdapter' - -export default class UCSCPlugin extends Plugin { - name = 'UCSCPlugin' - install(pluginManager) { - pluginManager.addAdapterType( - () => - new AdapterType({ - name: 'UCSCAdapter', - configSchema, - AdapterClass, - }), - ) - } -} -``` - -src/UCSCAdapter/index.ts - -```js -import { - ConfigurationSchema, - readConfObject, -} from '@jbrowse/core/configuration' -import { ObservableCreate } from '@jbrowse/core/util/rxjs' -import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter' -import SimpleFeature from '@jbrowse/core/util/simpleFeature' -import stringify from 'json-stable-stringify' - -export const configSchema = ConfigurationSchema( - 'UCSCAdapter', - { - base: { - type: 'fileLocation', - description: 'base URL for the UCSC API', - defaultValue: { - uri: 'https://cors-anywhere.herokuapp.com/https://api.genome.ucsc.edu/', - locationType: 'UriLocation', - }, - }, - track: { - type: 'string', - description: 'the track to select data from', - defaultValue: '', - }, - }, - { explicitlyTyped: true }, -) - -export class AdapterClass extends BaseFeatureDataAdapter { - constructor(config) { - super(config) - this.config = config - } - - getFeatures(region) { - const { assemblyName, start, end, refName } = region - return ObservableCreate(async observer => { - const { uri } = readConfObject(this.config, 'base') - const track = readConfObject(this.config, 'track') - try { - const result = await fetch( - `${uri}/getData/track?` + - `genome=${assemblyName};track=${track};` + - `chrom=${refName};start=${start};end=${end}`, - ) - if (result.ok) { - const data = await result.json() - data[track].forEach(feature => { - observer.next( - new SimpleFeature({ - ...feature, - start: feature.chromStart, - end: feature.chromEnd, - refName: feature.chrom, - uniqueId: stringify(feature), - }), - ) - }) - observer.complete() - } - } catch (e) { - observer.error(e) - } - }) - } - - async getRefNames() { - const arr = [] - for (let i = 0; i < 23; i++) { - arr.push(`chr${i}`) - } - return arr - } - - freeResources() {} -} -``` - -### Adding this track to our configuration - -We can create a track.json like this - -track.json - -```json -{ - "type": "FeatureTrack", - "trackId": "genehancer_ucsc", - "name": "UCSC GeneHancer", - "assemblyNames": ["hg38"], - "adapter": { - "type": "UCSCAdapter", - "track": "geneHancerInteractionsDoubleElite" - } -} -``` - -Then use the jbrowse CLI tool add-track-json - -```sh -jbrowse add-track-json file.json -``` - -This will automatically add this track to the tracks array of our config.json - -Alternatively, we can manually edit this JSON into the config.json. - -When we open this track, we should see the GeneHancer regions are drawn as -orange blocks. - -### Creating a custom renderer type - -Let's say we want to create a track that connects a gene to it's enhancer. On -UCSC the GeneHancer tracks do exactly this. An instance of the UCSC with the -GeneHancer tracks is [here](https://genome.ucsc.edu/cgi-bin/hgTracks?db=hg38&lastVirtModeType=default&lastVirtModeExtraState=&virtModeType=default&virtMode=0&nonVirtPosition=&position=chrX%3A15568963%2D15611770&hgsid=858794487_a0hr9rIWlxlrERnwnX2RjVOEl7rJ). - -We can see data that we can get for the GeneHancer interactions from the UCSC -API like this - -```sh -curl 'https://api.genome.ucsc.edu/getData/track?genome=hg19;\ -track=geneHancerInteractionsDoubleElite;chrom=chr1;start=750000;\ -end=505700000'|less -``` - -Given that the functionality of rendering arcs is so distinct from UCSC API -adaptation, we can actually make this a new plugin. Let's imagine starting a -new plugin from scratch again - -src/index.js - -```js -import Plugin from '@jbrowse/core/Plugin' -import PluginManager from '@jbrowse/core/PluginManager' - -import ArcRenderer, { - configSchema as ArcRendererConfigSchema, - ReactComponent as ArcRendererReactComponent, -} from './ArcRenderer' - -export default class ArcRendererPlugin extends Plugin { - name = 'ArcPlugin' - install(pluginManager) { - pluginManager.addRendererType( - () => - new ArcRenderer({ - name: 'ArcRenderer', - ReactComponent: ArcRendererReactComponent, - configSchema: ArcRendererConfigSchema, - pluginManager, - }), - ) - } -} -``` - -src/ArcRenderer/index.js - -```js -import React from 'react' -// prettier-ignore -import { - ServerSideRendererType -} from '@jbrowse/core/pluggableElementTypes/renderers/ServerSideRendererType' -import { - ConfigurationSchema, - readConfObject, -} from '@jbrowse/core/configuration' - -import { PrerenderedCanvas } from '@jbrowse/core/ui' -import { bpSpanPx } from '@jbrowse/core/util' -import { - createCanvas, - createImageBitmap, -} from '@jbrowse/core/util/offscreenCanvasPonyfill' - -// Our config schema for arc track will be basic, include just a color -export const configSchema = ConfigurationSchema( - 'ArcRenderer', - { - color: { - type: 'color', - description: 'color for the arcs', - defaultValue: 'darkblue', - }, - }, - { explicitlyTyped: true }, -) - -// This ReactComponent is the so called "rendering" which is the component -// that contains the contents of what was rendered. -export const ReactComponent = props => { - return ( -
- -
- ) -} - -// Our ArcRenderer class does the main work in it's render method -// which draws to a canvas and returns the results in a React component -export default class ArcRenderer extends ServerSideRendererType { - async render(renderProps) { - const { features, config, regions, bpPerPx, highResolutionScaling } = - renderProps - const region = regions[0] - const width = (region.end - region.start) / bpPerPx - const height = 500 - const canvas = createCanvas( - width * highResolutionScaling, - height * highResolutionScaling, - ) - const ctx = canvas.getContext('2d') - ctx.scale(highResolutionScaling, highResolutionScaling) - for (const feature of features.values()) { - const [left, right] = bpSpanPx( - feature.get('start'), - feature.get('end'), - region, - bpPerPx, - ) - - ctx.beginPath() - ctx.strokeStyle = readConfObject(config, 'color', { feature }) - ctx.lineWidth = 3 - ctx.moveTo(left, 0) - ctx.bezierCurveTo(left, 200, right, 200, right, 0) - ctx.stroke() - } - const imageData = await createImageBitmap(canvas) - const reactElement = React.createElement( - this.ReactComponent, - { - ...renderProps, - width, - height, - imageData, - }, - null, - ) - return { reactElement, imageData, width, height } - } -} -``` - -The above code is relatively simple but it is fairly quirky. Here are some notes: - -- renderers can be run in offscreen or even a node.js canvas, so we do not - assume the `document.createElement` exists to create our canvas, instead - using a utility function that makes a OffscreenCanvas or node-canvas (depends - on context, e.g. webworker or node.js) -- the "rendering" component contains the results of our renderer. in this case - it delegates to the `PrerenderedCanvas` component, a component we use in other - places throughout the codebase - -### Bringing the two together - -We can bring these two contexts together with a new track in our config.json. -Remember our previous track.json? Now we can edit it to use our own `ArcRenderer` - -track.json - -```json -{ - "type": "BasicTrack", - "trackId": "genehancer_ucsc", - "name": "UCSC GeneHancer", - "assemblyNames": ["hg38"], - "adapter": { - "type": "UCSCAdapter", - "track": "geneHancerInteractionsDoubleElite" - }, - "renderer": { - "type": "ArcRenderer" - } -} -``` - -Then add the track - -```sh -jbrowse add-track-json track.json --update -``` - -## Creating custom renderers - -### What is a renderer - -In JBrowse 1, a track type typically would directly call the data parser and do -it's own rendering. In JBrowse 2, the data parsing and rendering is offloaded -to a web-worker or other RPC. This allows things to be faster in many cases. -This is conceptually related to "server side rendering" or SSR in React terms. - -
- -Important note: you can make custom tracks types that do not use this workflow, -but it is a built in workflow that works well for the core track types in -JBrowse 2. - -### How to create a new renderer - -The fundamental aspect of creating a new renderer is creating a class that -implements the "render" function. A renderer is actually a pair of a React -component that contains the renderer's output, which we call the "rendering" -and the renderer itself - -```js -class MyRenderer implements ServerSideRendererType { - render(props) { - const { width, height, regions, features } = props - const canvas = createCanvas(width, height) - const ctx = canvas.getContext('2d') - ctx.fillStyle = 'red' - ctx.drawRect(0, 0, 100, 100) - const imageData = createImageBitmap(canvas) - return { - reactElement: React.createElement(this.ReactComponent, { ...props }), - imageData, - height, - width, - } - } -} -``` - -In the above simplified example, our renderer creates a canvas using width and -height that are supplied via arguments, and draw a rectangle. We then return a -`React.createElement` call which creates a "rendering" component that will -contain the output - -Note that the above canvas operations use an `OffscreenCanvas` for Chrome, or in -other browsers serialize the drawing commands to be drawn in the main thread - -### What are the props passed to the renderer - -The typical props that a renderer receives - -```typescript -export interface PileupRenderProps { - features: Map - layout: { addRect: (featureId, leftBp, rightBp, height) => number } - config: AnyConfigurationModel - regions: Region[] - bpPerPx: number - height: number - width: number - highResolutionScaling: number -} -``` - -The layout is available on BoxRendererType renderers so that it can layout -things in pileup format, and has an addRect function to get the y-coordinate to -render your data at - -The features argument is a map of feature ID to the feature itself. To iterate -over the features Map, we can use an iterator or convert to an array - -```js -class MyRenderer extends ServerSideRendererType { - render(props) { - const { features, width, height } = props - // iterate over the ES6 map of features - for (const feature in features.values()) { - // render each feature to canvas or output SVG - } - - // alternatively - const feats = Array.from(features.values()) - feats.forEach(feat => {}) - } -} -``` - -### Adding custom props to the renderer - -Note that track models themselves can extend this using their renderProps function - -For example the `WiggleTrack` has code similar to this, which adds a scaleOpts -prop that gets passed to the renderer - -```js -const model = types - .compose( - 'WiggleTrack', - blockBasedTrack, - types.model({ - type: types.literal('WiggleTrack'), - }), - ) - .views(self => { - const { renderProps: superRenderProps } = self - return { - renderProps() { - return { - ...superRenderProps(), - scaleOpts: { - domain: this.domain, - stats: self.stats, - autoscaleType: getConf(self, 'autoscale'), - scaleType: getConf(self, 'scaleType'), - inverted: getConf(self, 'inverted'), - }, - } - }, - } - }) -``` - -### Rendering SVG - -Our SVG renderer is an example, where it extends the existing built in renderer -type with a custom ReactComponent only - -```js -export default class SVGPlugin extends Plugin { - install(pluginManager: PluginManager) { - pluginManager.addRendererType( - () => - new BoxRendererType({ - name: 'SvgFeatureRenderer', - ReactComponent: SvgFeatureRendererReactComponent, - configSchema: svgFeatureRendererConfigSchema, - pluginManager, - }), - ) - } -} -``` - -Then, we have our Rendering component just be plain React code. This is a -highly simplified SVG renderer just to illustrate - -```jsx -export default function SvgFeatureRendering(props) { - const { width, features, regions, layout, bpPerPx } = props - const region = regions[0] - - const feats = Array.from(features.values()) - const height = readConfObject(config, 'height', { feature }) - return ( - - {feats.map(feature => { - // our layout determines at what y-coordinate to - // plot our feature, given all the other features - const top = layout.addRect( - feature.id(), - feature.get('start'), - feature.get('end'), - height, - ) - const [left, right] = bpSpanPx( - feature.get('start'), - feature.get('end'), - region, - bpPerPx, - ) - return - })} - - ) -} +pluginManager.addToExtensionPoint('ExtensionPointName', arg => { + return arg.value + 1 +}) ``` -Notes: - -- The above SVG renderer is highly simplified but serves an example, but it - shows that you can have a simple React component that leverages the existing - `BoxRendererType`, so that you do not have to necessarily create your own - renderer class -- The renderers receive an array of regions to render, but if they are only - equipped to handle one region at a time then they can select only rendering - to `regions[0]` - -### Overriding the renderer's getFeatures method - -Normally, it is sufficient to override the `getFeatures` function in your -dataAdapter +In this case, `arg` that is passed in evaluateExtensionPoint calls all the +callbacks that have been registered by `addToExtensionPoint`. If multiple +extension points are registered, the return value of the first extension point +is passed as the new argument to the second, and so on (they are chained together). -If you want to drastically modify the feature fetching behavior, you can modify -the renderer's getFeatures call +So in the example above, ret would be `{value:3}` after evaluating the +extension point. -The base `ServerSideRendererType` class has a built-in `getFeatures` function that, -in turn, calls your adapter's getFeatures function, but if you need -tighter control over how your adapter's getFeatures method is called then -your renderer. The Hi-C renderer type does not operate on conventional -features and instead works with contact matrices, so the Hi-C renderer has a -custom getFeatures function +## Next steps -```js -import { toArray } from 'rxjs/operators' -class HicRenderer extends ServerSideRendererType { - async getFeatures(args) { - const { dataAdapter, regions } = args - const features = await dataAdapter - .getFeatures(regions[0]) - .pipe(toArray()) - .toPromise() - return features - } -} -``` +Now that you have an overview of the different pluggable element types that are available to you, review your [understanding of the configuration model](../devguide_config), or checkout [creating your own pluggable elements](../devguide_pluggable_elements) for specific guides for making new adapters, tracks, and renderers. -## Creating custom track types - -At a high level the track types are just "ReactComponents" that contain -rendered track contents. Oftentimes, for custom drawing, we create a renderer -instead of a track, but here are some reasons you might want a custom track - -- Drawing custom things over the rendered content (e.g. drawing the Y-scale bar - in the wiggle track) -- Implementing custom track menu items (e.g. Show soft clipping in the - alignments track) -- Adding custom widgets (e.g. custom `VariantFeatureWidget` in - variant track) -- You want to bundle your renderer and adapter as a specific thing that is - automatically initialized rather than the `BasicTrack` (which combines any - adapter and renderer) - -For examples of custom track types, refer to things like - -- `HicTrack`, which uses a custom HicRenderer to draw contact matrix -- `GDCPlugin`, which has a custom track type that registers custom feature detail - widgets -- `VariantTrack`, which also registers custom widgets, and has - `ChordVariantDisplay` and `LinearVariantDisplay` -- `SyntenyTrack`, which can be displayed with `DotplotDisplay` or - `LinearSyntenyDisplay` +Also checkout the [guided tutorial](../tutorials/simple_plugin_tutorial/01_introduction) for writing a plugin, which will take you through everything from installation, creating a new pluggable element, and general development tips for working with JBrowse 2. diff --git a/website/docs/devguide_config.md b/website/docs/devguide_config.md new file mode 100644 index 0000000000..e7b89d0848 --- /dev/null +++ b/website/docs/devguide_config.md @@ -0,0 +1,243 @@ +--- +id: devguide_config +title: Understanding the configuration model +toplevel: true +--- + +import Figure from './figure' + +This guide will introduce some critical concepts to understanding the configuration model. The configuration model is used to structure the features and data available in a given JBrowse session, and each new pluggable element you create will need its own configuration schema. + +## Configuration slot types + +Our configuration system is "typed" to facilitate graphical editing of the +configuration. Each configuration has a "schema" that lists what +"configuration slots" it has. Each configuration slot has a name, description, +a type, and a value. + +Here is a mostly comprehensive list of config types: + +- `stringEnum` - allows assigning one of a limited set of entries, becomes a + dropdown box in the GUI +- `color` - allows selecting a color, becomes a color picker in the GUI +- `number` - allows entering any numeric value +- `string` - allows entering any string +- `integer` - allows entering a integer value +- `boolean +- `frozen` - an arbitrary JSON can be specified in this config slot, becomes + textarea in the GUI +- `fileLocation` - refers to a URL, local file path on desktop, or file blob + object in the browser +- `text` - allows entering a string, becomes textarea in the GUI +- `stringArray` - allows entering a list of strings, becomes a "todolist" style + editor in the GUI where you can add or delete things +- `stringArrayMap` - allows entering a list of key-value entries + +Let's examine the `PileupRenderer` configuration as an example. + +## Example config with multiple slot types + +This `PileupRenderer` config contains an example of several different slot types: + +```js +// plugins/alignments/src/PileupRenderer/configSchema.ts + +import { types } from 'mobx-state-tree' +export default ConfigurationSchema('PileupRenderer', { + color: { + type: 'color', + description: 'the color of each feature in a pileup alignment', + defaultValue: `jexl:get(feature,'strand') == - 1 ? '#8F8FD8' : '#EC8B8B'`, + contextVariable: ['feature'], + }, + displayMode: { + type: 'stringEnum', + model: types.enumeration('displayMode', ['normal', 'compact', 'collapse']), + description: 'Alternative display modes', + defaultValue: 'normal', + }, + minSubfeatureWidth: { + type: 'number', + description: `the minimum width in px for a pileup mismatch feature. use for + increasing mismatch marker widths when zoomed out to e.g. 1px or + 0.5px`, + defaultValue: 0, + }, + maxHeight: { + type: 'integer', + description: 'the maximum height to be used in a pileup rendering', + defaultValue: 600, + }, +}) +``` + +## Accessing config values + +So instead of accessing `config.displayMode`, we say, + +```js +readConfObject(config, 'displayMode') +``` + +You might also see in the code like this: + +```js +getConf(track, 'maxHeight') +``` + +Which would be equivalent to calling, + +```js +readConfObject(track.configuration, 'maxHeight')` +``` + +## Using config callbacks + +Config callbacks allow you to have a dynamic color based on some function logic +you provide. All config slots can actually become config callback. The +arguments that are given to the callback are listed by the 'contextVariable' +but must be provided by the calling code (the code reading the config slot). To +pass arguments to the a callback we say + +```js +readConfObject(config, 'color', { feature }) +``` + +That implies the color configuration callback will be passed a feature, so the +config callback can be a complex function determining the color to use based on +various feature attributes. + +## Example of a config callback + +We use Jexl to express callbacks. See https://github.com/TomFrost/Jexl for more details. + +There are also more examples and information in our [config guide](../config_guide/#configuration-callbacks). + +If you had a variant track in your config, and wanted to make a custom config +callback for color, it might look like this: + +```json +{ + "type": "VariantTrack", + "trackId": "variant_colors", + "name": "volvox filtered vcf (green snp, purple indel)", + "category": ["VCF"], + "assemblyNames": ["volvox"], + "adapter": { + "type": "VcfTabixAdapter", + "vcfGzLocation": { + "uri": "volvox.filtered.vcf.gz", + "locationType": "UriLocation" + }, + "index": { + "location": { + "uri": "volvox.filtered.vcf.gz.tbi", + "locationType": "UriLocation" + } + } + }, + "displays": [ + { + "type": "LinearVariantDisplay", + "displayId": "volvox_filtered_vcf_color-LinearVariantDisplay", + "renderer": { + "type": "SvgFeatureRenderer", + "color1": "jexl:get(feature,'type')=='SNV'?'green':'purple'" # here we call our jexl function + } + } + ] +} +``` + +This draws all SNV (single nucleotide variants) as green, and other types as +purple (insertion, deletion, other structural variant). + +You can also [write your own jexl function](../devguide_pluggable_elements) and call it in the same way in the configuration. + +:::info Note + +It can be extremely useful to utilize a custom jexl function in the default configuration for a pluggable element type, +as you can observe in [one of the examples above](#example-config-with-multiple-slot-types), the default value of the +`color` slot of the renderer is a jexl function. If you configure your plugin with a custom jexl function, you can use +that function as a default value in your various pluggable elements. + +::: + +## Configuration internals + +A configuration is a type of mobx-state-tree model, in which leaf nodes are +ConfigSlot types, and other nodes are ConfigurationSchema types. + +``` + Schema + / | \ + Slot Schema Slot + | \ + Slot Slot +``` + +Configurations are all descendants of a single root configuration, which is +`root.configuration`. + +Configuration types should always be created by the `ConfigurationSchema` +factory, e.g.: + +```js +import { ConfigurationSchema } from '@jbrowse/core/utils/configuration' +const ThingStateModel = types.model('MyThingsState', { + foo: 42, + configuration: ConfigurationSchema('MyThing', { + backgroundColor: { + defaultValue: 'white', + type: 'string', + }, + }), +}) +``` + +An example of a config schema with a sub-config schema is the `BamAdapter`, with +the index sub-config schema: + +```js +ConfigurationSchema( + 'BamAdapter', + { + bamLocation: { + type: 'fileLocation', + defaultValue: { uri: '/path/to/my.bam', locationType: 'UriLocation' }, + }, + // this is a sub-config schema + index: ConfigurationSchema('BamIndex', { + indexType: { + model: types.enumeration('IndexType', ['BAI', 'CSI']), + type: 'stringEnum', + defaultValue: 'BAI', + }, + location: { + type: 'fileLocation', + defaultValue: { + uri: '/path/to/my.bam.bai', + locationType: 'UriLocation', + }, + }, + }), + }, + { explicitlyTyped: true }, +) +``` + +Reading the sub-config schema is as follows + +```js +const indexType = readConfObject(config, ['index', 'indexType']) +``` + +Alternatively can use + +```js +const indexConf = readConfObject(config, ['index']) +indexConf.indexType +``` + +However, this may miss default values from the slot, the `readConfObject` has +special logic to fill in the default value. diff --git a/website/docs/devguide_pluggable_elements.md b/website/docs/devguide_pluggable_elements.md new file mode 100644 index 0000000000..4d33817eb9 --- /dev/null +++ b/website/docs/devguide_pluggable_elements.md @@ -0,0 +1,641 @@ +--- +id: devguide_pluggable_elements +title: Creating your own pluggable elements +toplevel: true +--- + +import Figure from './figure' + +This guide will walk you through the concepts necessary for creating your own of some of the most common pluggable element types, including **adapters**, **tracks**, and **renderers**. + +## Simple additions to JBrowse using plugins + +### Adding a top-level menu + +These are the menus that appear in the top bar of JBrowse Web and JBrowse +Desktop. By default, there are `File`, `Add`, `Tools`, and `Help` menus. + +You can add your own menu, or you can add menu items or sub-menus to the existing menus and +sub-menus. Sub-menus can be arbitrarily deep. + +
+ +You add menus in the `configure` method of your plugin. Not all JBrowse +products will have top-level menus, though. JBrowse Web and JBrowse Desktop +have them, but something like JBrowse Linear View (which is an just a single +view designed to be embedded in another page) does not. This means you need to +check whether or not menus are supported using `isAbstractMenuManager` in the +`configure` method. This way the rest of the plugin will still work if there is +not a menu. Here's an example that adds an "Open My View" item to the `Add` menu. + +```js +import Plugin from '@jbrowse/core/Plugin' +import { isAbstractMenuManager } from '@jbrowse/core/util' +import InfoIcon from '@mui/icons-material/Info' + +class MyPlugin extends Plugin { + name = 'MyPlugin' + + install(pluginManager) { + // install MyView here + } + + configure(pluginManager) { + if (isAbstractMenuManager(pluginManager.rootModel)) { + pluginManager.rootModel.appendToMenu('Add', { + label: 'Open My View', + icon: InfoIcon, + onClick: session => { + session.addView('MyView', {}) + }, + }) + } + } +} +``` + +This example uses `rootModel.appendToMenu`. See [top-level menu +API](../api_guide#rootmodel-menu-api) for more details on available functions. + +### Adding menu items to a custom track + +If you create a custom track, you can populate the track menu items in it using +the `trackMenuItems` property in the track model. For example: + +```js +types + .model({ + // model + }) + .views(self => ({ + trackMenuItems() { + return [ + { + label: 'Menu Item', + icon: AddIcon, + onClick: () => {}, + }, + ] + }, + })) +``` + +If you'd prefer to append your track menu items onto menu items available from the +base display, you can grab the `trackMenuItems` property from the extended model +and redefine trackMenuItems with your new Menu Item appended at the end, like so: + +```js +types + .model({ + // model + }) + .views(self => { + const { trackMenuItems: superTrackMenuItems } = self + return { + get trackMenuItems() { + return [ + ...superTrackMenuItems(), + { + label: 'Menu Item', + icon: AddIcon, + onClick: () => {}, + }, + ] + }, + } + }) +``` + +### Adding track context-menu items + +When you right-click in a linear track, a context menu will appear if there are +any menu items defined for it. + +
+ +It's possible to add items to that menu, and you +can also have different menu items based on if the click was on a feature or +not, and based on what feature is clicked. This is done by extending the +`contextMenuItems` view of the display model. Here is an example: + +```js +class SomePlugin extends Plugin { + name = 'SomePlugin' + + install(pluginManager) { + pluginManager.addToExtensionPoint( + 'Core-extendPluggableElement', + pluggableElement => { + if (pluggableElement.name === 'LinearPileupDisplay') { + const { stateModel } = pluggableElement + const newStateModel = stateModel.extend(self => { + const superContextMenuItems = self.contextMenuItems + return { + views: { + contextMenuItems() { + const feature = self.contextMenuFeature + if (!feature) { + // we're not adding any menu items since the click was not + // on a feature + return superContextMenuItems() + } + return [ + ...superContextMenuItems(), + { + label: 'Some menu item', + icon: SomeIcon, + onClick: () => { + // do some stuff + }, + }, + ] + }, + }, + } + }) + + pluggableElement.stateModel = newStateModel + } + return pluggableElement + }, + ) + } +} +``` + +## Creating adapters + +### What is an adapter + +An adapter is essentially a class that fetches and parses your data and returns +it in a format JBrowse understands. + +For example, if you have some data source that contains genes, and you want to +display those genes using JBrowse's existing gene displays, you can write a +custom adapter to do so. If you want to do a custom display of your data, +though, you'll probably need to create a custom display and/or renderer along +with your adapter. + +### What types of adapters are there + +- **Feature adapter** - This is the most common type of adapter. Essentially, + it takes a request for a _region_ (a chromosome, starting position, and ending + position) and returns the _features_ (e.g. genes, reads, variants, etc.) that + are in that region. Examples of this in JBrowse include adapters for + [BAM](https://samtools.github.io/hts-specs/SAMv1.pdf) and + [VCF](https://samtools.github.io/hts-specs/VCFv4.3.pdf) file formats. +- **Regions adapter** - This type of adapter is used to define what regions are + in an assembly. It returns a list of chromosomes/contigs/scaffolds and their + sizes. An example of this in JBrowse is an adapter for a + [chrome.sizes](https://software.broadinstitute.org/software/igv/chromSizes) + file. +- **Sequence adapter** - This is basically a combination of a regions adapter + and a feature adapter. It can give the list of regions in an assembly, and + can also return the sequence of a queried region. Examples of this in JBrowse + include adapters for + [FASTA](https://blast.ncbi.nlm.nih.gov/Blast.cgi?CMD=Web&PAGE_TYPE=BlastDocs&DOC_TYPE=BlastHelp) + and [.2bit](https://genome.ucsc.edu/FAQ/FAQformat.html#format7) file formats. +- **RefName alias adapter** - This type of adapter is used to return data about + aliases for reference sequence names, for example to define that "chr1" is an + alias for "1". An example of this in JBrowse is an adapter for + (alias files)[http://software.broadinstitute.org/software/igv/LoadData/#aliasfile] +- **Text search adapter** - This type of adapter is used to search through text search indexes. Returns list of search results. An example of this in JBrowse is the trix text search adapter. + +:::info Note +When using the refName alias adapter, it's important that the first column match what is seen in your FASTA file. +::: + +### Skeleton of a feature adapter + +A basic feature adapter might look like this (with implementation omitted for +simplicity): + +```js +class MyAdapter extends BaseFeatureDataAdapter { + constructor(config) { + // config + } + async getRefNames() { + // return refNames used in your adapter, used for refName renaming + } + + getFeatures(region, opts) { + // region: { + // refName:string, e.g. chr1 + // start:number, 0-based half open start coord + // end:number, 0-based half open end coord + // assemblyName:string, assembly name + // originalRefName:string the name of the refName from the fasta file, e.g. 1 instead of chr1 + // } + // opts: { + // signal?: AbortSignal + // ...rest: all the renderProps() object from the display type + // } + } + + freeResources(region) { + // can be empty + } +} +``` + +So to make a feature adapter, you implement the `getRefNames` function +(optional), the `getFeatures` function (returns an rxjs observable stream of +features, discussed below) and `freeResources` (optional). + +### Example feature adapter + +To take this a little slow, let's look at each function individually. + +This is a more complete description of the class interface that you can implement: + +```js +import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter' +import SimpleFeature from '@jbrowse/core/util/simpleFeature' +import { readConfObject } from '@jbrowse/core/configuration' +import { ObservableCreate } from '@jbrowse/core/util/rxjs' + +class MyAdapter extends BaseFeatureDataAdapter { + // your constructor gets a config object that you can read with readConfObject + // if you use "subadapters" then you can initialize those with getSubAdapter + constructor(config, getSubAdapter) { + const fileLocation = readConfObject(config, 'fileLocation') + const subadapter = readConfObject(config, 'sequenceAdapter') + const sequenceAdapter = getSubAdapter(subadapter) + } + + // use rxjs observer.next(new SimpleFeature(...your feature data....) for each + // feature you want to return + getFeatures(region, options) { + return ObservableCreate(async observer => { + try { + const { refName, start, end } = region + const response = await fetch( + 'http://myservice/genes/${refName}/${start}-${end}', + options, + ) + if (response.ok) { + const features = await result.json() + features.forEach(feature => { + observer.next( + new SimpleFeature({ + uniqueID: `${feature.refName}-${feature.start}-${feature.end}`, + refName: feature.refName, + start: feature.start, + end: feature.end, + }), + ) + }) + observer.complete() + } else { + throw new Error(`${response.status} - ${response.statusText}`) + } + } catch (e) { + observer.error(e) + } + }) + } + + async getRefNames() { + // returns the list of refseq names in the file, used for refseq renaming + // you can hardcode this if you know it ahead of time e.g. for your own + // remote data API or fetch this from your data file e.g. from the bam header + return ['chr1', 'chr2', 'chr3'] /// etc + } + + freeResources(region) { + // optionally remove cache resources for a region + // can just be an empty function + } +} +``` + +### What is needed from a feature adapter + +#### getRefNames + +Returns the refNames that are contained in the file. This is +used for "refname renaming" and is optional, but highly useful in scenarios +like human chromosomes which have, for example, chr1 vs 1. + +Returning the refNames used by a given file or resource allows JBrowse to +automatically smooth these small naming disparities over. +See [reference renaming](../config_guide/#configuring-reference-name-aliasing). + +#### getFeatures + +A function that returns features from the file given a genomic +range query e.g., + +`getFeatures(region, options)` + +The region parameter contains: + +```typescript +interface Region { + refName: string + start: number + end: number + originalRefName: string + assemblyName: string +} +``` + +The `refName`, `start`, `end` specify a simple genomic range. The `assemblyName` is +used to query a specific assembly if your adapter responds to multiple +assemblies, e.g. for a synteny data file or a REST API that queries a backend +with multiple assemblies. + +The `originalRefName` are also passed, where `originalRefName` is the queried +refname before ref renaming e.g. in BamAdapter, if the BAM file uses chr1, and +your reference genome file uses 1, then originalRefName will be 1 and refName +will be chr1. + +The options parameter to getFeatures can contain any number of things: + +```typescript +interface Options { + bpPerPx: number + signal: AbortSignal + statusCallback: Function + headers: Record +} +``` + +- `bpPerPx` - number: resolution of the genome browser when the features were + fetched +- `signal` - can be used to abort a fetch request when it is no longer needed, + from AbortController +- `statusCallback` - not implemented yet but in the future may allow you to + report the status of your loading operations +- `headers` - set of HTTP headers as a JSON object + +We return an rxjs Observable from getFeatures. This is similar to a JBrowse 1 +getFeatures call, where we pass each feature to a featureCallback, tell it when +we are done with finishCallback, and send errors to errorCallback, except we do +all those things with the Observable + +Here is a "conversion" of JBrowse 1 getFeatures callbacks to JBrowse 2 +observable calls + +- `featureCallback(new SimpleFeature(...))` -> `observer.next(new SimpleFeature(...))` +- `finishCallback()` -> `observer.complete()` +- `errorCallback(error)` -> `observer.error(error)` + +#### freeResources + +This is uncommonly used, so most adapters make this an empty function + +Most adapters in fact use an LRU cache to make resources go away over time +instead of manually cleaning up resources + +## Creating custom renderers + +### What is a renderer + +In JBrowse 1, a track type typically would directly call the data parser and do +it's own rendering. In JBrowse 2, the data parsing and rendering is offloaded +to a web-worker or other RPC. This allows things to be faster in many cases. +This is conceptually related to "server side rendering" or SSR in React terms. + +
+ +:::warning Note +You can make custom track types that do not use this workflow, but it is a built-in workflow that functions well for the core track types in JBrowse 2, and is recommended. +::: + +### How to create a new renderer + +The fundamental aspect of creating a new renderer is creating a class that +implements the "render" function. A renderer is actually a pair of a React +component that contains the renderer's output, which we call the "rendering", +and the renderer itself. + +```js +class MyRenderer implements ServerSideRendererType { + render(props) { + const { width, height, regions, features } = props + const canvas = createCanvas(width, height) + const ctx = canvas.getContext('2d') + ctx.fillStyle = 'red' + ctx.drawRect(0, 0, 100, 100) + const imageData = createImageBitmap(canvas) + return { + reactElement: React.createElement(this.ReactComponent, { ...props }), + imageData, + height, + width, + } + } +} +``` + +In the above simplified example, our renderer creates a canvas using width and +height that are supplied via arguments, and draw a rectangle. We then return a +`React.createElement` call which creates a "rendering" component that will +contain the output. + +:::info Note +The above canvas operations use an `OffscreenCanvas` for Chrome, or in +other browsers serialize the drawing commands to be drawn in the main thread. +::: + +### What are the props passed to the renderer + +The typical props that a renderer receives: + +```typescript +export interface PileupRenderProps { + features: Map + layout: { addRect: (featureId, leftBp, rightBp, height) => number } + config: AnyConfigurationModel + regions: Region[] + bpPerPx: number + height: number + width: number + highResolutionScaling: number +} +``` + +The layout is available on BoxRendererType renderers so that it can layout +things in pileup format, and has an addRect function to get the y-coordinate at which to +render your data. + +The features argument is a map of feature ID to the feature itself. To iterate +over the features Map, we can use an iterator or convert to an array: + +```js +class MyRenderer extends ServerSideRendererType { + render(props) { + const { features, width, height } = props + // iterate over the ES6 map of features + for (const feature in features.values()) { + // render each feature to canvas or output SVG + } + + // alternatively + const feats = Array.from(features.values()) + feats.forEach(feat => {}) + } +} +``` + +### Adding custom props to the renderer + +Track models themselves can extend this using their `renderProps` function. + +For example, the `WiggleTrack` has code similar to this, which adds a scaleOpts +prop that gets passed to the renderer: + +```js +const model = types + .compose( + 'WiggleTrack', + blockBasedTrack, + types.model({ + type: types.literal('WiggleTrack'), + }), + ) + .views(self => { + const { renderProps: superRenderProps } = self + return { + renderProps() { + return { + ...superRenderProps(), + scaleOpts: { + domain: this.domain, + stats: self.stats, + autoscaleType: getConf(self, 'autoscale'), + scaleType: getConf(self, 'scaleType'), + inverted: getConf(self, 'inverted'), + }, + } + }, + } + }) +``` + +### Rendering SVG + +Our SVG renderer is an example, where it extends the existing built in renderer +type with a custom ReactComponent only: + +```js +export default class SVGPlugin extends Plugin { + install(pluginManager: PluginManager) { + pluginManager.addRendererType( + () => + new BoxRendererType({ + name: 'SvgFeatureRenderer', + ReactComponent: SvgFeatureRendererReactComponent, + configSchema: svgFeatureRendererConfigSchema, + pluginManager, + }), + ) + } +} +``` + +Then, we have our Rendering component just be plain React code. This is a +highly simplified SVG renderer just to illustrate: + +```jsx +export default function SvgFeatureRendering(props) { + const { width, features, regions, layout, bpPerPx } = props + const region = regions[0] + + const feats = Array.from(features.values()) + const height = readConfObject(config, 'height', { feature }) + return ( + + {feats.map(feature => { + // our layout determines at what y-coordinate to + // plot our feature, given all the other features + const top = layout.addRect( + feature.id(), + feature.get('start'), + feature.get('end'), + height, + ) + const [left, right] = bpSpanPx( + feature.get('start'), + feature.get('end'), + region, + bpPerPx, + ) + return + })} + + ) +} +``` + +:::info Note + +1.The above SVG renderer is highly simplified, but it +shows that you can have a simple React component that leverages the existing +`BoxRendererType`, so that you do not have to necessarily create your own +renderer class + +2.The renderers receive an array of regions to render, but if they are only +equipped to handle one region at a time then they can select only rendering +to `regions[0]` +::: + +### Overriding the renderer's getFeatures method + +Normally, it is sufficient to override the `getFeatures` function in your +dataAdapter. + +If you want to drastically modify the feature fetching behavior, you can modify +the renderer's `getFeatures` call. + +The base `ServerSideRendererType` class has a built-in `getFeatures` function that, +in turn, calls your adapter's `getFeatures` function, but if you need +tighter control over how your adapter's `getFeatures` method is called, then +your renderer. + +The Hi-C renderer type does not operate on conventional +features and instead works with contact matrices, so the Hi-C renderer has a +custom `getFeatures` function: + +```js +import { toArray } from 'rxjs/operators' +class HicRenderer extends ServerSideRendererType { + async getFeatures(args) { + const { dataAdapter, regions } = args + const features = await dataAdapter + .getFeatures(regions[0]) + .pipe(toArray()) + .toPromise() + return features + } +} +``` + +## Creating custom track types + +At a high level, the track types are just "ReactComponents" that contain +rendered track contents. Oftentimes, for custom drawing, we create a renderer +instead of a track, but here are some reasons you might want a custom track: + +- Drawing custom things over the rendered content (e.g. drawing the Y-scale bar + in the wiggle track) +- Implementing custom track menu items (e.g. Show soft clipping in the + alignments track) +- Adding custom widgets (e.g. custom `VariantFeatureWidget` in + variant track) +- You want to bundle your renderer and adapter as a specific thing that is + automatically initialized rather than the `BasicTrack` (which combines any + adapter and renderer) + +For examples of custom track types, refer to things like: + +- `HicTrack`, which uses a custom HicRenderer to draw contact matrix +- `GDCPlugin`, which has a custom track type that registers custom feature detail + widgets +- `VariantTrack`, which also registers custom widgets, and has + `ChordVariantDisplay` and `LinearVariantDisplay` +- `SyntenyTrack`, which can be displayed with `DotplotDisplay` or + `LinearSyntenyDisplay` diff --git a/website/docs/faq.md b/website/docs/faq.md index 9c1a3394e0..b8abdcba0f 100644 --- a/website/docs/faq.md +++ b/website/docs/faq.md @@ -8,43 +8,47 @@ toplevel: true #### How can I start the JBrowse 2 app as a developer -We recommend that you have the following +We recommend that you have the following: -- Node v12+ +- A stable and recent version of [node](https://nodejs.org/en/) - Git - [Yarn](https://classic.yarnpkg.com/en/docs/install/#debian-stable) Then you can follow steps from our -[README](https://github.com/gmod/jbrowse-components) +[README](https://github.com/gmod/jbrowse-components). -It basically boils down to +It basically boils down to: -- `git clone https://github.com/GMOD/jbrowse-components` -- `cd jbrowse-components` -- `yarn` -- `cd products/jbrowse-web` -- `yarn start` +```bash +git clone https://github.com/GMOD/jbrowse-components +cd jbrowse-components +yarn +cd products/jbrowse-web +yarn start +``` -This will boot up a development instance of `jbrowse-web` on port 3000 +This will boot up a development instance of `jbrowse-web` on port `3000`. -You can use `PORT=8080 yarn start` to manually specify a different port +You can use `PORT=8080 yarn start` to manually specify a different port. You can also instead go to the `products/jbrowse-desktop` directory to do this -on desktop +on desktop. For the embedded components e.g. `products/jbrowse-react-linear-genome-view`, -use `yarn storybook` instead of `yarn start` +use `yarn storybook` instead of `yarn start`. + +For a more extensive tutorial, see [Developing with JBrowse web and desktop](/docs/tutorials/dev/develop_web_and_desktop_tutorial). ### General #### What is special about JBrowse 2 One thing that makes JBrowse 2 special is that we can create new view types via -our plugin system, e.g. circular, dotplot, etc. Anything you want can be added -as a view, and can be shown alongside our other views +our plugin system, e.g. circular, dotplot, etc.. Anything you want can be added +as a view, and can be shown alongside our other views. -This makes JBrowse 2 more than just a genome browser-- it is really a platform -that can be built on. +This makes JBrowse 2 more than just a genome browser: it is really a platform +that can be built upon. #### What are new features in JBrowse 2 @@ -58,7 +62,7 @@ JBrowse 2 by itself is just a set of JS, CSS, and HTML files that can be statically hosted on a webserver without any backend services running. Therefore, running JBrowse 2 generally involves just copying the JBrowse 2 -folder to your web server html folder e.g. `/var/www/html/`. +folder to your web server html folder e.g. copy `/var/www/html/` to Amazon S3. If you use a different platform such as Django, you may want to put it in the static resources folder. @@ -78,69 +82,75 @@ this. #### How can I setup JBrowse 2 on my web server -We recommend following the steps in the [quickstart web](../quickstart_web) guide. +We recommend following the steps in the [quickstart web via CLI](../quickstart_cli/) guide. The general procedure is using the `jbrowse create /var/www/html/jb2` and this will download the latest version of jbrowse to your web folder e.g. in -/var/www/html +`/var/www/html`. -You can also use `jbrowse upgrade /var/www/html/jb2` to get the latest version +You can also use `jbrowse upgrade /var/www/html/jb2` to get the latest version. #### How do I install or update the @jbrowse/cli tool To install the @jbrowse/cli tool, you can use `npm install -g @jbrowse/cli` -You can use this same command to upgrade the tool too +You can use this same command to upgrade the tool too. This command will give you a command named `jbrowse` which should automatically be in your path if you have a standard installation of nodejs. We recommend using nodesource or nvm to get your nodejs for this. Also note that the @jbrowse/cli tool is just made for preparing your -config.json, it is not used to run any server-side code +config.json, it is **not used to run any server-side code**. #### How do I update my instance of jbrowse-web -You can use the command, after installing +You can use the command, after installing: ``` jbrowse upgrade /path/to/your/jbrowse2 ``` This will download the latest release from github and overwrite it onto your -jbrowse-web instance +jbrowse-web instance. + +If you've manually downloaded jbrowse-web, the newest releases can be found [here](https://github.com/GMOD/jbrowse-components/releases). #### How can I setup JBrowse 2 without the CLI tools -The jbrowse CLI tools are basically a convenience, and are not strictly required +The jbrowse CLI tools are basically a convenience, and are not strictly required. -Simple tasks can be done without it +Simple tasks can be done without it. -For example, for jbrowse create, you can visit the [blog](/jb2/blog) and +For example, for jbrowse create, you can visit the [releases page](https://github.com/GMOD/jbrowse-components/releases) and download the latest jbrowse-web release tag, and unzip it into your web -directory +directory. + +Checkout our [quickstart web](../quickstart_web/) guide for a speedy start to using a manually downloaded JBrowse instance. For other things, like add-assembly and add-track, you can manually edit the -config.json, reviewing the config docs and sample configs will be valuable +`config.json`; reviewing the [config docs](../config_guide) and sample configs will be valuable. + +To configure JBrowse using the GUI, checkout our [tutorial](../tutorials/config_gui). -Understanding the [config basics](../config_guide#intro-to-the-configjson) will +Understanding the [config basics](../config_guide/#intro-to-the-configjson) will come in handy also because you can manually edit in advanced configs after your -tracks are loaded however be careful because corrupt configs can produce hard -to understand errors, because our config system is strongly typed +tracks are loaded; however be careful:s corrupt configs can produce hard +to understand errors, because our config system is strongly typed. -Feel free to message the team if you encounter these +Reach out to the team [on gitter](https://gitter.im/GMOD/jbrowse2) or in the [discussions](https://github.com/GMOD/jbrowse-components/discussions) if you have any complex configuration issues. #### How do I load a track into JBrowse 2 -If you have followed the above steps and installed jbrowse 2 on your webserver -and loaded the assembly, and have the CLI tools installed +With the JBrowse CLI tools, you can easily add tracks with the `add-track` command, e.g.: jbrowse add-track myfile.bw -a hg19 -This will setup a bigwig track on the hg19 assembly in your config.json. Make -sure to run the command inside your current jbrowse2 folder e.g. +This will setup a bigwig track on the hg19 assembly in your config.json. + +Make sure to run the command inside your current jbrowse2 folder e.g. /var/www/html/jbrowse2 or wherever you are currently setting up a config.json -(you can have multiple configs) +(you can have multiple configs). Note that you can also use remote URLs @@ -148,23 +158,58 @@ Note that you can also use remote URLs The add-track command will do as much as possible to infer from the file extension how to configure this track, and automatically infer the index to be -myfile.bam.bai +myfile.bam.bai. + +As mentioned [above](#how-can-i-setup-jbrowse-2-without-the-cli-tools) you can also manually edit your config file, or use the GUI. + +#### How do I customize the color of the features displayed on my track + +We use [Jexl](https://github.com/TomFrost/Jexl) for defining configuration +callbacks, including feature coloration. + +An example of a Jexl configuration callback might look like this: + + "color": "jexl:get(feature,'strand')==-1?'red':'blue'" + +See our [configuration callbacks guide](../config_guide/#configuration-callbacks) for more information. + +##### Adding color callbacks in the GUI + +In brief, to add a configuration callback to a track using the GUI, perform the following steps: + +1. On the track you're meaning to color, click on the three vertical dots '...' on the right side of the track label +2. Click "Settings" (if this option is greyed out, copy the track with "Copy Track", then open up the track under "Session Tracks" and repeat steps 1-2) +3. Scroll down to the "display 1 renderer" heading (this is typically the display you want to edit, if not scroll to display 2) +4. Click on the circle to the right of the color you'd like to change +5. In this text box, enter in the [Jexl](https://github.com/TomFrost/Jexl) callback for the feature colouration, e.g. "get(feature,'strand') == -1 ? 'red' : 'blue'" + +##### Adding color callbacks via the command line + +Adding color callbacks via the command line can be a little tricky because the coloration property exists within the renderer. + +In brief, to add a configuration callback to a track using the CLI, your `add-track` is going to look something like this: + +```bash +jbrowse add-track somevariants.vcf --load copy --config '{"displays": [{"displayId": "my_BasicDisplay", "type": "LinearBasicDisplay", "renderer": {"color1": "jexl:get(feature, 'strand') == -1 ? 'red' : 'blue'" }}]}' +``` + +While adding the track to the `config.json`, you're adding additional configurations using the --config option. This additional configuration is a "renderer" on the display that your track will be using. In this case, this .vcf will be using the LinearBasicDisplay ### Curiosities #### Why do all the tracks need an assembly specified We require that all tracks have a specific genome assembly specified in their -config. This is because jbrowse 2 is a multi-genome-assembly browser (and can -compare genomes given the data). This may be different to using say jbrowse 1 -where it knows which genome assembly you are working with at any given time +config. This is because JBrowse 2 is a multi-genome-assembly browser (and can +compare genomes given the data). This may be different to using, say, JBrwose 1 +where it knows which genome assembly you are working with at any given time. #### How are the menus structured in the app In JBrowse 1, the app level menu operated on the single linear genome view, but with JBrowse 2, the top level menu only performs global operations and the -linear genome view has it's own hamburger menu. Note that each track also has -it's own track level menu. +linear genome view has its own hamburger menu. Note that each track also has +its own track level menu. #### Why do some of my reads not display soft clipping @@ -175,13 +220,13 @@ The soft clipping indicators on these reads will appear black. #### Do you have any tips for learning React and mobx-state-tree -Here is a short guide to React and mobx-state-tree that could help get you oriented +Here is a short guide to React and mobx-state-tree that could help get you oriented: https://gist.github.com/cmdcolin/94d1cbc285e6319cc3af4b9a8556f03f #### What technologies does JBrowse 2 use -We build on a lot of great open source technology, some main ones include +We build on a lot of great open source technology, some main ones include: - React - mobx-state-tree @@ -219,7 +264,7 @@ the "display" section of your config - `maxFeatureScreenDensity` - number of features times bpPerPx - `fetchSizeLimit` - this config variable exists on the adapters (can increase size limit) -Example config with a small feature screen density +Example config with a small feature screen density: ```json { @@ -248,7 +293,7 @@ Example config with a small feature screen density } ``` -Example config for a CRAM file with a small fetchSizeLimit configured +Example config for a CRAM file with a small fetchSizeLimit configured: ```json { @@ -288,18 +333,18 @@ alternative temporary directory using the environment variable The `jbrowse text-index` command creates text searching indexes using trix. The trix indexes are based on the format described by UCSC here -https://genome.ucsc.edu/goldenPath/help/trix.html but we reimplemented the code +https://genome.ucsc.edu/goldenPath/help/trix.html, but we re-implemented the code the create these index formats in the JBrowse CLI so you do not have to install the UCSC tools. -The main idea is that you give trix +The main idea is that you give trix: ``` GENEID001 Wnt signalling GENEID002 ey Pax6 ``` -Then this will generate a new file, the .ix file, sorted in alphabetical order +Then this will generate a new file, the .ix file, sorted in alphabetical order: ``` ey GENE002 @@ -309,7 +354,7 @@ Wnt GENE001 ``` Then a second file, the .ixx file, tells us at what byte offset certain lines -in the file are e.g. +in the file are e.g.: ``` signa000000435 @@ -328,15 +373,15 @@ bar, so instead, we store it in localStorage and only keep the key to the localStorage entry in the URL var. This is because otherwise URLs can get prohibitively long, and break server side navigations, intermediate caches, etc. Therefore, we make "sharing a session" a manual step that generates a -shortened URL by default +shortened URL by default. -Note 1: user's of @jbrowse/react-linear-genome-view have to re-implement any +Note 1: users of @jbrowse/react-linear-genome-view have to re-implement any URL query param logic themselves, as this component makes no attempt to access -URL query params +URL query params. Note 2: You can copy and paste your URL bar and put it in another tab on your own computer, and JBrowse will restore the session using BroadcastChannel -(supported on Firefox and Chrome) +(supported on Firefox and Chrome). #### How does the session sharing work with shortened URLs work in JBrowse Web @@ -346,7 +391,7 @@ session snapshots that users create when they use the "Share" button. The &password= component of the share URL), encrypts the session client side, and sends the encrypted session without the key to the AWS dynamoDB. -This process, generates a URL with the format +This process, generates a URL with the format: &session=share-<DYNAMODBID>&password=<DECODEKEY> @@ -374,7 +419,7 @@ If for any reason the session sharing system isn't working, e.g. you are behind a firewall or you are not able to connect to the central share server, you can click the "Gear" icon in the "Share" button pop-up, and it will give you the option to use "Long URL" instead of "Short URL" which let's you create share -links without the central server +links without the central server. Also, if you are implementing JBrowse Web on your own server and would like to create your own URL shortener, you can use the shareURL parameter in the diff --git a/website/docs/introduction.md b/website/docs/introduction.md index 4edc8a3e6e..b2e4a6ff48 100644 --- a/website/docs/introduction.md +++ b/website/docs/introduction.md @@ -7,27 +7,36 @@ toplevel: true Welcome to the JBrowse 2 documentation. -- [Quick-start for JBrowse desktop](quickstart_desktop) - a quick-start guide +- [Quick start for JBrowse desktop](quickstart_desktop) - a quick start guide to getting JBrowse desktop running on your machine -- [Quick-start for JBrowse web](quickstart_web) - a quick-start guide to help - admins setting up JBrowse 2 on their website -- [Super quick-start guide for JBrowse web](superquickstart_web) - list of - helpful commands for admins familiar with the CLI -- [Configuration guide](config_guide) - for detailed configuration settings -- [Developer guide](developer_guide) - for developers of plugins -- [User guide](user_guide) - screenshots of the app and general usage +- [Quick start for JBrowse web](quickstart_web) - a quick start guide to running JBrowse 2 in a browser +- [Quick start for JBrowse web via CLI](quickstart_cli) - a quick start guide to intalling the JBrowse 2 CLI and getting JBrowse web running locally on a browser -Other resources +### User and developer guides -- [FAQ](faq) - Some Q&A for troubleshooting or other topics +- [User guide](user_guide) - for general usage, guided by screenshots and descriptions +- [Comprehensive config guide](config_guide) - for detailed configuration settings +- [Core concepts and pluggable elements for developers](developer_guide) - for developers of plugins + +#### Tutorials + +- [Config editing via graphical interface](./tutorials/config_gui) - a guide for configuring JBrowse via the GUI +- [Config editing via command-line interface](./tutorials/config_cli) - a guide for configuring JBrowse via CLI +- [Writing a simple plugin for JBrowse 2](./tutorials/simple_plugin_tutorial/01_introduction/) +- [Developing with JBrowse web and desktop](./tutorials/develop_web_and_desktop_tutorial/) + +...and more! Use the left panel to browse some of the other guide docs available. + +### Other resources + +- [FAQ](faq) - some Q&A for troubleshooting or other topics - [@jbrowse/cli](cli) - docs for our CLI tools for loading tracks, assemblies, text indexing, and more -- [@jbrowse/img](https://www.npmjs.com/package/@jbrowse/img) - Docs for our +- [@jbrowse/img](https://www.npmjs.com/package/@jbrowse/img) - docs for our command line image generator -- [Embedded components](embedded_components) - Docs for our reusable React +- [Embedded components](embedded_components) - docs for our reusable React components - -We also keep a log of our previous training classes in the sidebar +- [JBrowse Jupyter](jbrowse_jupyter) - docs for JBrowse Jupyter ### Contact information diff --git a/website/docs/jbrowse_jupyter.md b/website/docs/jbrowse_jupyter.md new file mode 100644 index 0000000000..1251d4e725 --- /dev/null +++ b/website/docs/jbrowse_jupyter.md @@ -0,0 +1,9 @@ +--- +id: jbrowse_jupyter +title: JBrowse Jupyter +toplevel: true +--- + +Comprehensive documentation for JBrowse Jupyter is found off-site, [here](https://gmod.github.io/jbrowse-jupyter/docs/html/index.html). + +Also check out the JBrowse Jupyter [Github repo](https://github.com/GMOD/jbrowse-jupyter). diff --git a/website/docs/md_parser.js b/website/docs/md_parser.js index fd7e57f377..87a9b6c793 100755 --- a/website/docs/md_parser.js +++ b/website/docs/md_parser.js @@ -14,6 +14,9 @@ let topLevel = false if (line.startsWith('import Figure')) { continue } + if (line.startsWith('import config')) { + continue + } if (!readingHeader && line === '---') { readingHeader = true continue diff --git a/website/docs/quickstart_cli.md b/website/docs/quickstart_cli.md index 2151afc3a4..1de045bb58 100644 --- a/website/docs/quickstart_cli.md +++ b/website/docs/quickstart_cli.md @@ -1,281 +1,123 @@ --- id: quickstart_cli -title: Config editing quick start — command-line interface +title: JBrowse web quick start via CLI toplevel: true --- import Figure from './figure' -In order to display your data, JBrowse 2 needs to know about the reference -genome for your organism of interest and needs to have tracks created that -reference your data sources. This guide will show you how to set those up using -the JBrowse CLI. +In this guide, we'll get an instance of JBrowse web running on your computer's browser. -:::note - -You can also do this configuration with graphical configuration editing -interface built into JBrowse 2. See that guide [here](../quickstart_gui). - -::: - -## Pre-requisites +Just want to download JBrowse web and get started? Follow our [JBrowse web quick start](../quickstart_web). -- [JBrowse CLI](../quickstart_web#installing-the-cli-tools) +Want JBrowse desktop? Follow our [JBrowse desktop quick start](../quickstart_desktop). -- [JBrowse 2 web application](../quickstart_web#using-jbrowse-create-to-download-jbrowse-2) +## Prerequisites -## Adding a genome assembly - -:::info - -For this step we configure JBrowse to use files being hosted at a URL. For an -example of how to use files located on your computer, see the -[adding a track](#adding-a-track) step. - -::: - -First we will configure an assembly, or reference genome, for for JBrowse 2. -This usually means providing a file that describes the reference sequence for -the organism, such as a FASTA or 2BIT file. - -You will want to use your own data for your organism, but for this example we -provide a small example reference sequence for a simulated organism, _volvox -mythicus_, that you can use. - -```sh-session -# Make sure you are in the directory where you have downloaded JBrowse 2 -jbrowse add-assembly http://jbrowse.org.s3.amazonaws.com/genomes/volvox/volvox.fa -``` +- Ability to run commands on the command line +- A stable and recent version of [node](https://nodejs.org/en/) :::caution -A FASTA must have an index to work in JBrowse 2. This command assumes that the -index file is the same as the FASTA but with `.fai` appended to the file name. +If you are using `apt` as your package manager, we recommend not using it to +install Node.js. Good alternatives include +[NodeSource](https://github.com/nodesource) or +[NVM](https://github.com/nvm-sh/nvm). ::: -This command will generate a config file if one does not exist yet and add an -assembly called "volvox" to the config file with the URLs of the FASTA and FASTA -index files. The name of the assembly was guessed from the file name, but you -can customize that and many other things with various flags passed to the -command. You can run `jbrowse add-assembly --help` to get a list of all the -options. +## Downloading JBrowse 2 using the JBrowse CLI -JBrowse 2 also supports other assembly file formats, such as bgzip-compressed -indexed FASTA (e.g. `.fa.gz`, `.fa.gz.fai`, and `.fa.gz.gzi` files) and 2BIT -files. See [configuring assemblies](../config_guide#assembly-config) for more info -on formats supported for the sequence file. +The JBrowse CLI can help perform many tasks to help you manage JBrowse 2, such +as: -:::note +- create a new instance of JBrowse 2 automatically +- update an existing instance of JBrowse 2 with the latest released version +- configure your JBrowse 2 instance -If your FASTA is not indexed, you can use the `samtools` tool to index it. +### Installing the CLI tools -```sh-session -samtools faidx volvox.fa -# generates volvox.fa.fai -``` - -Or if you want to compress your FASTA, you can use `bgzip` as well. +To globally install the JBrowse CLI, run ```sh-session -bgzip volvox.fa -samtools faidx volvox.fa.gz -# compresses volvox.fa to volvox.fa.gz and generates volvox.fa.gz.fai and volvox.fa.gz.gzi +npm install -g @jbrowse/cli ``` -For more info about `bgzip` and `samtools`, see https://www.htslib.org/. - -::: - -If you have your JBrowse 2 -[running as described](../quickstart_web#running-jbrowse-2) in the JBrowse web -quickstart, you can refresh the page and an add a linear genome view. You will -now see your config in the Assembly dropdown. - -
- -## Adding a track - -Now we will show you how to add an alignments track and a variant track to -JBrowse 2. - -:::info - -For this step we configure JBrowse to use files located on your computer. For an -example of how to use files hosted at a URL, see the -[adding a genome assembly](#adding-a-genome-assembly) step. - -::: - -### Adding an alignments track - -For this example we will use a BAM file to add an alignments track. Again, for -this example we provide a small example BAM, but for your data you will replace -the file name with the names of your data files. - -For this track we will assume the data is on your computer at the locations -`/data/volvox.bam` and `/data/volvox.bam.bai`. You can download these file here -if you want to run this example: -[BAM](https://jbrowse.org.s3.amazonaws.com/genomes/volvox/volvox.bam) and -[BAM index](https://jbrowse.org.s3.amazonaws.com/genomes/volvox/volvox.bam.bai). - -To add the track, run +After running this command you can then test the installation with ```sh-session -# Replace with the location of your BAM file -jbrowse add-track /data/volvox.bam --load copy +jbrowse --version ``` -This will copy the BAM and BAM index into the JBrowse 2 directory and add a -track pointing at those files to the config file. To see more options adding the -track, such as specifying a name, run `jbrowse add-track --help`. - -If you don't want to copy your BAM file, you can use `--move` to move the file -into the JBrowse 2 directory or `--symlink` to add a symlink to the file to the -JBrowse 2 directory. If you want more control over the location, you can use -`inPlace` to point the track at the file where it is, but be careful with this -option because on a traditional server you will need to ensure that the file is -in a place where the web server is serving it. +which will output the current version of the JBrowse CLI. :::note -If your BAM is not indexed, you can use the `samtools` tool to index it. +If you can't or don't want to globally install the JBrowse CLI, you can also use +the [npx](https://nodejs.dev/learn/the-npx-nodejs-package-runner) command, which +is included with Node.js, to run JBrowse CLI without installing it. Simply +replace `jbrowse` with `npx @jbrowse/cli` in any command, e.g. ```sh-session -samtools index volvox.bam -# generates volvox.bam.bai +npx @jbrowse/cli --version ``` -For more info about `samtools`, see https://www.htslib.org/. - ::: -If you have your JBrowse 2 -[running as described](../quickstart_web#running-jbrowse-2) in the JBrowse web -quickstart, you can refresh the page and an add a linear genome view of the -volvox assembly. Then open track selector, and you will see the alignments -track. - -
- -### Adding a variant track +### Using `jbrowse create` to download JBrowse 2 -Adding a variant track is similar to adding an alignments track. For this -example, we will use a VCF file for the track. JBrowse 2 expects VCFs to be -compressed with `bgzip` and indexed. Similar to the above example, we will -assume the files are at `/data/volvox.vcf.gz` and `/data/volvox.vcf.gz.tbi`. You -can download these file here: -[VCF](https://jbrowse.org.s3.amazonaws.com/genomes/volvox/volvox.vcf.gz) and -[VCF index](https://jbrowse.org.s3.amazonaws.com/genomes/volvox/volvox.vcf.gz.tbi). - -To add the track, run +In the directory where you would like to download JBrowse 2, run ```sh-session -jbrowse add-track /data/volvox.vcf.gz --load copy +jbrowse create jbrowse2 ``` -:::note +### Checking the download -If your VCF is not indexed, you can use the `bgzip` and `tabix` tools to -compress index it. +The directory where you downloaded JBrowse should look something like this: -```sh-session -bgzip yourfile.vcf -tabix yourfile.vcf.gz +```txt +jbrowse2/ +├── asset-manifest.json +├── favicon.ico +├── index.html +├── manifest.json +├── robots.txt +├── static/ +├── test_data/ +└── version.txt ``` -Alternatively, you can do the same thing with the `bcftools` tool. - -```sh-session -bcftools view volvox.vcf --output-type z > volvox.vcf.gz -rm volvox.vcf -bcftools index --tbi volvox.vcf.gz -``` +## Running JBrowse 2 -Note if you get errors about your VCF file not being sorted when using tabix, -you can use bcftools to sort your VCF. +JBrowse 2 requires a web server to run. It won't work if you try to directly +open the `index.html` in your web browser. We can use a simple server to check +that JBrowse 2 has been downloaded properly. Run ```sh-session -bcftools sort file.vcf > file.sorted.vcf -bgzip file.sorted.vcf -tabix file.sorted.vcf.gz +cd jbrowse2/ +npx serve . # use npx serve -S . if you want to refer to symlinked data later on ``` -For more info about `bgzip`, `tabix`, and `bcftools`, see -https://www.htslib.org/. +which will start a web server in our JBrowse 2 directory. -::: - -If you have your JBrowse 2 -[running as described](../quickstart_web#running-jbrowse-2) in the JBrowse web -quickstart, you can refresh the page and an add a linear genome view of the -volvox assembly. Then open track selector, and you will see the variant track. - -
- -### Adding a BigWig/BigBed track +Navigate to the location specified in the CLI's output (likely +`http://localhost:3000`). -Probably one of the most simple track types to load is a BigWig/BigBed file -since it does not have any external index file, it is just a single file - -An example file is here https://jbrowse.org.s3.amazonaws.com/genomes/volvox/volvox-sorted.bam.coverage.bw - -```sh-session -## Download bigwig or bigbed file -jbrowse add-track volvox-sorted.bam.coverage.bw --load copy -``` +Your page should look something like this: -### Adding a GFF3 file with GFF3Tabix - -To load a GFF3 file, we can sort and index it with tabix - -Sorting a GFF3 can be done with [GenomeTools](http://genometools.org/) (to -install can use `sudo apt install genometools`) - -```sh-session -gt gff3 -sortlines -tidy -retainids yourfile.gff > yourfile.sorted.gff -bgzip yourfile.sorted.gff -tabix yourfile.sorted.gff.gz -jbrowse add-track yourfile.sorted.gff.gz --load copy -``` - -Note: as an alternative to gt gff3 -sortlines is awk+GNU sort - -```sh-session -awk '$1 ~ /^#/ {print $0;next} {print $0 | "sort -t\"\t\" -k1,1 -k4,4n"}' file.gff > file.sorted.gff -bgzip file.sorted.gff -tabix file.sorted.gff.gz -``` - -The awk command is inspired by the method in the tabix documentation -http://www.htslib.org/doc/tabix.html but avoids subshells and properly sets the -tab delimiter for GNU sort in case there are spaces in the GFF - -## Indexing feature names for searching - -The final step of loading you jbrowse instance may include adding a "search -index" so that you can search by genes or other features by their name or ID - -To do this we can use the `jbrowse text-index` command - -```sh-session -jbrowse text-index -``` +
-This will index relevant track types e.g. any track with Gff3TabixAdapter (gene -names and IDs) or VcfTabixAdapter (e.g. variant IDs). The command will print -out a progress bar for each track that it is indexing. +Click on the sample config to see JBrowse 2 running with a demo +configuration. It should look like this: -This will also update your config.json so after it completes, you can type a -gene name into the "search box" in the linear genome view or other views and -quickly navigate to genes by gene name. +
-See the [text-index](../cli#jbrowse-text-index) command docs for more info. Also -see the [FAQ entries for text searching](../faq#text-searching) +Congratulations! You're running JBrowse 2. -## Conclusion +## Next steps -Now that you have JBrowse configured with an assembly and a couple of tracks, -you can start customizing it further. Check out the rest of the docs for more -information, especially the [JBrowse CLI](../cli) docs for more details on some of -the steps shown here. +Now that JBrowse 2 is set up, you can configure it with your own genomes and +tracks. There are two ways you can configure JBrowse 2: with the JBrowse CLI +(tutorial [here](../tutorials/config_cli)) or with JBrowse 2's built-in graphical +configuration editing (guide [here](../tutorials/config_gui)). diff --git a/website/docs/quickstart_desktop.md b/website/docs/quickstart_desktop.md index 7ad4549f1b..56cafa08ed 100644 --- a/website/docs/quickstart_desktop.md +++ b/website/docs/quickstart_desktop.md @@ -1,24 +1,40 @@ --- id: quickstart_desktop -title: Quick start for JBrowse desktop +title: JBrowse desktop quick start toplevel: true --- import Figure from './figure' +import config from '../docusaurus.config.json' import PlaylistAddIcon from '@mui/icons-material/PlaylistAdd' +const winDownloadLink = `https://github.com/GMOD/jbrowse-components/releases/download/${config.customFields.currentVersion}/jbrowse-desktop-${config.customFields.currentVersion}-win.exe` +const macDownloadLink = `https://github.com/GMOD/jbrowse-components/releases/download/${config.customFields.currentVersion}/jbrowse-desktop-${config.customFields.currentVersion}-mac.dmg` +const linDownloadLink = `https://github.com/GMOD/jbrowse-components/releases/download/${config.customFields.currentVersion}/jbrowse-desktop-${config.customFields.currentVersion}-linux.AppImage` + +In this guide, we'll get the JBrowse desktop application running on your computer. ## Installing JBrowse desktop -This guide will walk you through installing jbrowse 2 on the desktop +### Installing on Windows + +Click here to download the latest Windows installer executable. + +Double-click the downloaded installer and it will install and open JBrowse. +You can now open JBrowse like any other program. + +### Installing on MacOS + +Click here to download the latest MacOS release artifact. -JBrowse 2 desktop does not require any pre-requisites for your installation, so -we can jump right in +When the .dmg file is downloaded, double click, and drag JBrowse 2 into 'applications'. + +You can now open JBrowse 2 like any other application on your Mac. ### Installing on Linux -Visit http://github.com/gmod/jbrowse-components/releases/latest and find the -latest Linux AppImage release. Download that file to wherever you would like to -keep it and then start it in one of two ways: +Click here to download the latest Linux AppImage release. + +Start it in one of two ways: #### In the terminal @@ -43,59 +59,39 @@ follow these steps: You can now double-click the AppImage file to launch JBrowse. -### Installing on MacOS - -Visit http://github.com/gmod/jbrowse-components/releases/latest and find the -latest MacOS release artifact in our latest builds. - -Download the .dmg file for MacOS, double click, and drag JBrowse 2 into 'applications'. - -You can now open JBrowse 2 like any other application on your Mac. - -### Installing on Windows - -Visit http://github.com/gmod/jbrowse-components/releases/latest and download the -latest Windows installer executable (will end with `win.exe`). - -Double-click the downloaded installer and it will install and open JBrowse. -You can now open JBrowse like any other program. - ## JBrowse Desktop start screen After you have installed and started JBrowse Desktop you will see a start -screen like this +screen like this:
-The left hand panel, with "Launch new session" can quickly launch a new session +**On the left hand panel,** "Launch new session" can launch a new session using either your own custom genome (which you can load using an indexed FASTA -or a twobit file). Also on the left hand panel is the "Quickstart list". Users -can click the checkbox next to e.g. hg38 and hit Go. +or a twobit file via `open sequence file`) or a pre-loaded genome via the "Quickstart list". -On the right hand panel is the "Recently opened sessions". This includes -sessions that you have specifically saved, and sessions that were autosaved -(e.g. ones that you didn't explicitly use "Save as" on). You can re-open your -sessions by clicking on the link. +**On the right hand panel** is the "Recently opened sessions". This includes +sessions that you have explicitly saved, and sessions that were autosaved +(i.e. ones that you didn't explicitly use "Save as" on). You can re-open your +sessions by clicking on the session name. ### Special features on the start screen #### Converting a saved session into a quickstart entry If you study a rare species, you might find it useful to customize your -quickstart panel. We allow you to convert a session in the "Recently opened +quickstart panel. You can convert a session in the "Recently opened sessions" into an entry that appears in the quickstart list. -To do so: Click a checkbox next to a session in the "Recently opened sessions" +**To do this:** Click a checkbox next to a session in the "Recently opened sessions" table, and then hit the icon next to the trash can icon. -This is helpful if e.g. you want to make your own custom organism a template +This is helpful if you want to make your own custom organism a template for quickstarts in the future. #### Selecting multiple entries from the quickstart panel -Users can also hit -the checkbox for multiple species in the quickstart list, and then the sessions -are combined which is helpful if e.g. you are doing comparative genomics of -hg19 and mm10. +Users can also hit the checkbox for multiple species in the quickstart list, and then the sessions +are combined which can be helpful for comparative genomics. ### Next steps diff --git a/website/docs/quickstart_web.md b/website/docs/quickstart_web.md index 8bb1f30fc0..096edde8ee 100644 --- a/website/docs/quickstart_web.md +++ b/website/docs/quickstart_web.md @@ -5,104 +5,34 @@ toplevel: true --- import Figure from './figure' +import config from '../docusaurus.config.json' -In this guide, we'll get an instance of JBrowse running on your computer. +In this guide, we'll get an instance of JBrowse web running on your computer's browser. -## Pre-requisites +Are you an **administrator**, or want to install via CLI to get access to configuration tools? Follow our [CLI quick start](../quickstart_cli). -- Ability to run commands on the command line -- Node.js 12+ +Want JBrowse desktop? Follow our [JBrowse desktop quick start](../quickstart_desktop). -:::caution +## Downloading manually -If you are using `apt` as your package manager, we recommend not using it to -install Node.js. Good alternatives include -[NodeSource](https://github.com/nodesource) or -[NVM](https://github.com/nvm-sh/nvm). +Download JBrowse 2 manually here. -::: - -## Download - -You can download JBrowse 2 by using the JBrowse CLI or by downloading and -unpacking it manually. We recommend using the JBrowse CLI since it also includes -utilities to help you configure JBrowse 2 once it is set up. - -### Downloading using the JBrowse CLI - -The JBrowse CLI can help perform many tasks to help you manage JBrowse 2, such -as: - -- create a new instance of JBrowse 2 automatically -- update an existing instance of JBrowse 2 with the latest released version -- configure your JBrowse 2 instance - -#### Installing the CLI tools - -To install the JBrowse CLI, run - -```sh-session -npm install -g @jbrowse/cli -``` - -After running this command you can then test the installation with - -```sh-session -jbrowse --version -``` - -This will output the current version of the JBrowse CLI. - -:::note - -If you can't or don't want to globally install the JBrowse CLI, you can also use -the [npx](https://nodejs.dev/learn/the-npx-nodejs-package-runner) command, which -is included with Node.js, to run JBrowse CLI without installing it. Simply -replace `jbrowse` with `npx @jbrowse/cli` in any command, e.g. - -``` -npx @jbrowse/cli --version -``` - -::: - -#### Using `jbrowse create` to download JBrowse 2 - -In the directory where you would like to download JBrowse 2, run this command - -```sh-session -jbrowse create jbrowse2 -``` - -### Downloading manually - -You can also download JBrowse 2 manually. Go to the -[releases page](https://github.com/GMOD/jbrowse-components/releases/) of the -JBrowse 2 GitHub repository and find the latest release that is tagged -`@jbrowse/web`. Download the ZIP file from that release. Make sure it is the ZIP -file that starts with `jbrowse-web-` and not the "Source code" ZIP file. Once -you have downloaded the ZIP file, extract it to the location you would like to -have JBrowse 2. +Once you have downloaded the ZIP file, extract it to the directory where you would like to have JBrowse 2. ### Checking the download -Whether you used the JBrowse CLI or downloaded manually, the directory where you -downloaded JBrowse should look something like this: +The directory where you downloaded JBrowse should look something like this: ```txt jbrowse2/ -├── a586bb28a5bad4a3aba2.worker.js -├── a586bb28a5bad4a3aba2.worker.js.LICENSE.txt -├── a586bb28a5bad4a3aba2.worker.js.map ├── asset-manifest.json ├── favicon.ico ├── index.html ├── manifest.json -├── precache-manifest.52c8ba3337cf7ae812b37d874b2de030.js ├── robots.txt -├── service-worker.js ├── static/ -└── test_data/ +├── test_data/ +└── version.txt ``` ## Running JBrowse 2 @@ -116,15 +46,16 @@ cd jbrowse2/ npx serve . # use npx serve -S . if you want to refer to symlinked data later on ``` -This will start a web server in our JBrowse 2 directory. Navigate to the -location specified in the tool's output. It will look something like -`http://localhost:5000`. Once at that page, you should see a page that says that -the configuration is not found. That is expected, since we haven't configured -JBrowse 2 yet. It will look something like this: +which will start a web server in our JBrowse 2 directory. + +Navigate to the location specified in the CLI's output (likely +`http://localhost:3000`). + +Your page should look something like this:
-Go ahead an click on the sample config to see a JBrowse 2 running with a demo +Click on the sample config to see JBrowse 2 running with a demo configuration. It should look like this:
@@ -135,5 +66,5 @@ Congratulations! You're running JBrowse 2. Now that JBrowse 2 is set up, you can configure it with your own genomes and tracks. There are two ways you can configure JBrowse 2: with the JBrowse CLI -(guide [here](../quickstart_cli)) or with JBrowse 2's built-in graphical -configuration editing (guide [here](../quickstart_gui)). +(guide [here](../userguide_cli)) or with JBrowse 2's built-in graphical +configuration editing (guide [here](../userguide_gui)). diff --git a/website/docs/read_sidebar.js b/website/docs/read_sidebar.js index 4a703632b8..ba53973bc7 100755 --- a/website/docs/read_sidebar.js +++ b/website/docs/read_sidebar.js @@ -5,11 +5,7 @@ const sidebar = JSON.parse(fs.readFileSync('../sidebars.json')) function readTree(tree, res = []) { tree.forEach(subtree => { if (subtree.items) { - if ( - !['JBrowse educational courses', 'Developer tutorials'].includes( - subtree.label, - ) - ) { + if (!['User tutorials', 'Developer tutorials'].includes(subtree.label)) { readTree(subtree.items, res) } } else if (typeof subtree === 'string') { diff --git a/website/docs/superquickstart_web.md b/website/docs/superquickstart_web.md deleted file mode 100644 index f5e3e38dff..0000000000 --- a/website/docs/superquickstart_web.md +++ /dev/null @@ -1,179 +0,0 @@ ---- -id: superquickstart_web -title: Super-quick start guide for JBrowse web -toplevel: true ---- - -This is a quick overview to get started running JBrowse 2 from scratch using -the command line. It is helpful if you have some familiarity with the command -line, and with some bioinformatics tools like samtools in general. This guide -also assumes you have: - -- a web server that reads files from /var/www/html/ e.g. Apache or nginx (not - strictly necessary for jbrowse to run, see footnote) -- node 12+ installed -- genometools installed e.g. `sudo apt install genometools` or `brew install brewsci/bio/genometools`, used for sorting GFF3 for creating tabix GFF -- samtools installed e.g. `sudo apt install samtools` or `brew install samtools`, used for creating FASTA index and BAM/CRAM processing -- tabix installed e.g. `sudo apt install tabix` or `brew install htslib`, used - for created tabix indexes for BED/VCF/GFF files - -## Super-quick overview for CLI - -### Initial setup - -```bash -## Install JBrowse 2 CLI tools, note: if you want to use the jbrowse command -## under the sudo user, change this to `sudo npm install -g @jbrowse/cli`, but -## sometimes it is better to work under the principle of least priviledge and -## operate under a normal user so this guide does not use this -npm install -g @jbrowse/cli - - -## Use the `jbrowse create` command to download the latest release, and put it -## in a web server directory -jbrowse create /var/www/html/jbrowse2 - -## Alternatively, you may download to a directory, and then move it to the web -## directory -jbrowse create ~/mylocaljbrowse -mv ~/mylocaljbrowse /var/www/html/jbrowse2 - -``` - -### Loading a FASTA file - -``` - -## Create indexed FASTA file and load it using the add-assembly command -## Add your genome assembly to the config at /var/www/html/jbrowse2/config.json -## Also copies the files to this directory -samtools faidx genome.fa -jbrowse add-assembly genome.fa --out /var/www/html/jbrowse2 --load copy -``` - -### Loading a BAM file - -``` -## Copies file.bam and file.bam.bai to /var/www/html/jbrowse2 and adds track to -## the config at /var/www/html/jbrowse2/config.json. Assumes that file.bam and -## file.bam.bai exist -samtools index file.bam -jbrowse add-track file.bam --out /var/www/html/jbrowse2/ --load copy - -## Adds a url entry for a bam file to the config.json, the URL is stored in the -## config instead of downloading files, so no --load flag is needed -jbrowse add-track http://website.com/myfile.bam --out /var/www/html/jbrowse2 - -## If your BAM index (bai) is not filename+'.bai' then you can manually specify -## the --index flag. The --index flag also works with loading tabix tracks too -jbrowse add-track myfile.bam --index myfile.bai --out /var/www/html/jbrowse2 --load copy -``` - -### Loading GFF3 - -``` -## load gene annotations from a GFF, using "GenomeTools" (gt) to sort the gff -## and tabix to index the GFF3 -gt gff3 -sortlines -tidy -retainids myfile.gff > myfile.sorted.gff -bgzip myfile.sorted.gff -tabix myfile.sorted.gff.gz -jbrowse add-track myfile.sorted.gff.gz --out /var/www/html/jbrowse2 --load copy -``` - -Note: as an alternative to gt gff3 -sortlines is awk+GNU sort - -```sh-session -awk '$1 ~ /^#/ {print $0;next} {print $0 | "sort -t\"\t\" -k1,1 -k4,4n"}' file.gff > file.sorted.gff -bgzip file.sorted.gff -tabix file.sorted.gff.gz -``` - -The awk command is inspired by the method in the tabix documentation -http://www.htslib.org/doc/tabix.html but avoids subshells and properly sets the -tab delimiter for GNU sort in case there are spaces in the GFF - -### Miscellaneous tips - -``` -## Example of using --subDir to organize your data directory: -## copies myfile.bam and myfile.bam.bai to /var/www/html/jbrowse2/my_bams -## folder, which helps organize your data folder -jbrowse add-track myfile.bam --subDir my_bams --out /var/www/html/jbrowse2 --load copy - -## Example without using the --out parameter: -## If you are in a directory with a config.json file, you can omit the --out parameter -cd /var/www/html/jbrowse2 -jbrowse add-track /path/to/my/file.bam --load copy - -## After you've had jbrowse for a while, you can upgrade to our latest release -jbrowse upgrade /var/www/html/jbrowse2 - -## Outputting to a specific config file instead of a config directory -## Alternative loading syntax where I specify a config file, and then this can -## be loaded via http://localhost/jbrowse2/?config=alt_config.json -jbrowse add-assembly mygenome.fa --out /var/www/html/jbrowse2/alt_config.json --load copy - - -``` - -### Load a synteny track - -``` -## Demo for loading synteny data, both assemblies are outputted to a single -## config.json in /var/www/html/jbrowse2/config.json -minimap2 grape.fa peach.fa > peach_vs_grape.paf -jbrowse add-assembly grape.fa --load copy --out /var/www/html/jbrowse2/ -n grape -jbrowse add-assembly peach.fa --load copy --out /var/www/html/jbrowse2/ -n peach - -## Use gt gff3 to make sorted tabixed gffs for each assembly, and then load to -## their respective ## assembly -jbrowse add-track grape.sorted.gff.gz -a grape --load copy --out /var/www/html/jbrowse2 -jbrowse add-track peach.sorted.gff.gz -a peach --load copy --out /var/www/html/jbrowse2 - -## Load the synteny "track" from a PAF file. Note the order matters here for -## the --assemblyNames parameter. If minimap2 is run like `minimap2 grape.fa -## peach.fa` then you load --assemblyNames peach,grape. the order is reversed -## because the syntax is minimap2 ref.fa query.fa on the CLI and query (left side -## of PAF) and target (right hand side) in PAF output file -jbrowse add-track peach_vs_grape.paf --assemblyNames peach,grape --out /var/www/html/jbrowse2/ --load copy -``` - -### Create a text index to let users search for gene names - -``` -## Finally create a text-index for your genes. By default it will index all -## tracks with Gff3TabixAdapter and VcfTabixAdapter. A progress bar will show -## indexing progress -jbrowse text-index --out /var/www/html/jbrowse2 - -## Index only a specific assembly -jbrowse text-index --out /var/www/html/jbrowse2 -a hg19 - -### Index only some specific trackIds -jbrowse text-index --out /var/www/html/jbrowse2 --tracks=mygenes1,mygenes2 - -### Index each track individually -jbrowse text-index --out /var/www/html/jbrowse2 --tracks=mygenes1,mygenes2 --perTrack - -## If you already have a text-index, you have to use --force to overwrite the old one -jbrowse text-index --out /var/www/html/jbrowse2 --force - -``` - -## Conclusion - -You can now visit http://localhost/jbrowse2 and your genome should be ready! - -This guide is meant to be a super-quick conceptual overview for getting JBrowse -2 set up, but if you are new to the command line or to jbrowse in general, you -might want to start with the slightly longer quick-start guide -[here](../quickstart_cli). - -## Footnote - -JBrowse doesn't strictly need Apache or nginx, it is "static site -compatible" meaning it uses no server code and can run on any static -website hosting. For example, you can upload the jbrowse folder that we -prepared here in /var/www/html/jbrowse2 to Amazon S3, and it will work there -too. See the FAQ for [what webserver do I -need](../faq#what-web-server-do-i-need-to-run-jbrowse-2) for more info. diff --git a/website/docs/tex_parser.js b/website/docs/tex_parser.js index 2a1ccb11f9..cbe49a93d3 100755 --- a/website/docs/tex_parser.js +++ b/website/docs/tex_parser.js @@ -16,6 +16,9 @@ let topLevel = false if (line.startsWith('import Figure')) { continue } + if (line.startsWith('import config')) { + continue + } if (!readingHeader && line === '---') { readingHeader = true continue diff --git a/website/docs/bcc2020_embedding_jbrowse_01_getting_started.md b/website/docs/tutorials/archive/bcc2020_embedding_jbrowse_01_getting_started.md similarity index 97% rename from website/docs/bcc2020_embedding_jbrowse_01_getting_started.md rename to website/docs/tutorials/archive/bcc2020_embedding_jbrowse_01_getting_started.md index ddecdef9d6..811ee741a7 100644 --- a/website/docs/bcc2020_embedding_jbrowse_01_getting_started.md +++ b/website/docs/tutorials/archive/bcc2020_embedding_jbrowse_01_getting_started.md @@ -6,7 +6,7 @@ title: Getting started :::danger Out of date Please see the -[updated version of this tutorial](./tutorials/embed_linear_genome_view/01_introduction). +[updated version of this tutorial](../embed_linear_genome_view/01_introduction). ::: diff --git a/website/docs/bcc2020_embedding_jbrowse_02_introduction.md b/website/docs/tutorials/archive/bcc2020_embedding_jbrowse_02_introduction.md similarity index 94% rename from website/docs/bcc2020_embedding_jbrowse_02_introduction.md rename to website/docs/tutorials/archive/bcc2020_embedding_jbrowse_02_introduction.md index 67de193fab..72a230ff2c 100644 --- a/website/docs/bcc2020_embedding_jbrowse_02_introduction.md +++ b/website/docs/tutorials/archive/bcc2020_embedding_jbrowse_02_introduction.md @@ -6,7 +6,7 @@ title: Introduction :::danger Out of date Please see the -[updated version of this tutorial](./tutorials/embed_linear_genome_view/01_introduction). +[updated version of this tutorial](../embed_linear_genome_view/01_introduction). ::: diff --git a/website/docs/bcc2020_embedding_jbrowse_03_simple_site.md b/website/docs/tutorials/archive/bcc2020_embedding_jbrowse_03_simple_site.md similarity index 96% rename from website/docs/bcc2020_embedding_jbrowse_03_simple_site.md rename to website/docs/tutorials/archive/bcc2020_embedding_jbrowse_03_simple_site.md index 5e5c020edc..ba0c8bbf20 100644 --- a/website/docs/bcc2020_embedding_jbrowse_03_simple_site.md +++ b/website/docs/tutorials/archive/bcc2020_embedding_jbrowse_03_simple_site.md @@ -6,7 +6,7 @@ title: Beginnings of a simple site :::danger Out of date Please see the -[updated version of this tutorial](./tutorials/embed_linear_genome_view/01_introduction). +[updated version of this tutorial](../embed_linear_genome_view/01_introduction). ::: @@ -80,7 +80,7 @@ tools (You can use `F12` or `Ctrl-Shift-I` or right-click the page and select `Inspect`) and go to the "Network" tab. If you see something like the below with a status of 200 for "jbrowse-linear-view.js", then you are good to go! -![Network tab of developer tools showing that script has loaded correctly](./img/bcc2020_network_success.png) +![Network tab of developer tools showing that script has loaded correctly](../../../img/bcc2020_network_success.png) Now we need to actually instantiate a view. The code to do so looks like this: diff --git a/website/docs/bcc2020_embedding_jbrowse_04_assemblies.md b/website/docs/tutorials/archive/bcc2020_embedding_jbrowse_04_assemblies.md similarity index 97% rename from website/docs/bcc2020_embedding_jbrowse_04_assemblies.md rename to website/docs/tutorials/archive/bcc2020_embedding_jbrowse_04_assemblies.md index b2d624c5c0..a83c6974fb 100644 --- a/website/docs/bcc2020_embedding_jbrowse_04_assemblies.md +++ b/website/docs/tutorials/archive/bcc2020_embedding_jbrowse_04_assemblies.md @@ -6,7 +6,7 @@ title: About assemblies :::danger Out of date Please see the -[updated version of this tutorial](./tutorials/embed_linear_genome_view/01_introduction). +[updated version of this tutorial](../embed_linear_genome_view/01_introduction). ::: @@ -63,7 +63,7 @@ source ~/.bashrc Now if you run the command `jbrowse --help` in the terminal, you should see something like this: -![The output of `jbrowse --help` in a terminal](./img/bcc2020_jbrowse_help.png) +![The output of `jbrowse --help` in a terminal](../../../img/bcc2020_jbrowse_help.png) :::note If you're not using the VM You may already have `yarn` or `npm` set up to do global installations, so you diff --git a/website/docs/bcc2020_embedding_jbrowse_05_tracks.md b/website/docs/tutorials/archive/bcc2020_embedding_jbrowse_05_tracks.md similarity index 98% rename from website/docs/bcc2020_embedding_jbrowse_05_tracks.md rename to website/docs/tutorials/archive/bcc2020_embedding_jbrowse_05_tracks.md index 06ecdb994d..64f1ca5277 100644 --- a/website/docs/bcc2020_embedding_jbrowse_05_tracks.md +++ b/website/docs/tutorials/archive/bcc2020_embedding_jbrowse_05_tracks.md @@ -6,7 +6,7 @@ title: About tracks :::danger Out of date Please see the -[updated version of this tutorial](./tutorials/embed_linear_genome_view/01_introduction). +[updated version of this tutorial](../embed_linear_genome_view/01_introduction). ::: diff --git a/website/docs/bcc2020_embedding_jbrowse_06_other_options.md b/website/docs/tutorials/archive/bcc2020_embedding_jbrowse_06_other_options.md similarity index 93% rename from website/docs/bcc2020_embedding_jbrowse_06_other_options.md rename to website/docs/tutorials/archive/bcc2020_embedding_jbrowse_06_other_options.md index 39965810b1..3b8062916d 100644 --- a/website/docs/bcc2020_embedding_jbrowse_06_other_options.md +++ b/website/docs/tutorials/archive/bcc2020_embedding_jbrowse_06_other_options.md @@ -6,7 +6,7 @@ title: Other options :::danger Out of date Please see the -[updated version of this tutorial](./tutorials/embed_linear_genome_view/01_introduction). +[updated version of this tutorial](../embed_linear_genome_view/01_introduction). ::: diff --git a/website/docs/bcc2020_embedding_jbrowse_07_creating_the_view.md b/website/docs/tutorials/archive/bcc2020_embedding_jbrowse_07_creating_the_view.md similarity index 97% rename from website/docs/bcc2020_embedding_jbrowse_07_creating_the_view.md rename to website/docs/tutorials/archive/bcc2020_embedding_jbrowse_07_creating_the_view.md index 4b9d0e8403..d175ff36c1 100644 --- a/website/docs/bcc2020_embedding_jbrowse_07_creating_the_view.md +++ b/website/docs/tutorials/archive/bcc2020_embedding_jbrowse_07_creating_the_view.md @@ -6,7 +6,7 @@ title: Creating the view :::danger Out of date Please see the -[updated version of this tutorial](./tutorials/embed_linear_genome_view/01_introduction). +[updated version of this tutorial](../embed_linear_genome_view/01_introduction). ::: diff --git a/website/docs/bcc2020_embedding_jbrowse_08_default_session.md b/website/docs/tutorials/archive/bcc2020_embedding_jbrowse_08_default_session.md similarity index 97% rename from website/docs/bcc2020_embedding_jbrowse_08_default_session.md rename to website/docs/tutorials/archive/bcc2020_embedding_jbrowse_08_default_session.md index 3f4e0279eb..4f06f528bf 100644 --- a/website/docs/bcc2020_embedding_jbrowse_08_default_session.md +++ b/website/docs/tutorials/archive/bcc2020_embedding_jbrowse_08_default_session.md @@ -6,7 +6,7 @@ title: Creating a default session :::danger Out of date Please see the -[updated version of this tutorial](./tutorials/embed_linear_genome_view/01_introduction). +[updated version of this tutorial](../embed_linear_genome_view/01_introduction). ::: diff --git a/website/docs/bcc2020_embedding_jbrowse_09_reacting.md b/website/docs/tutorials/archive/bcc2020_embedding_jbrowse_09_reacting.md similarity index 96% rename from website/docs/bcc2020_embedding_jbrowse_09_reacting.md rename to website/docs/tutorials/archive/bcc2020_embedding_jbrowse_09_reacting.md index 2101fe47ab..bc2ffb92c7 100644 --- a/website/docs/bcc2020_embedding_jbrowse_09_reacting.md +++ b/website/docs/tutorials/archive/bcc2020_embedding_jbrowse_09_reacting.md @@ -6,7 +6,7 @@ title: Reacting to the view :::danger Out of date Please see the -[updated version of this tutorial](./tutorials/embed_linear_genome_view/01_introduction). +[updated version of this tutorial](../embed_linear_genome_view/01_introduction). ::: diff --git a/website/docs/bcc2020_embedding_jbrowse_10_conclusion.md b/website/docs/tutorials/archive/bcc2020_embedding_jbrowse_10_conclusion.md similarity index 87% rename from website/docs/bcc2020_embedding_jbrowse_10_conclusion.md rename to website/docs/tutorials/archive/bcc2020_embedding_jbrowse_10_conclusion.md index f3bb1a0a2f..8ac828433a 100644 --- a/website/docs/bcc2020_embedding_jbrowse_10_conclusion.md +++ b/website/docs/tutorials/archive/bcc2020_embedding_jbrowse_10_conclusion.md @@ -6,7 +6,7 @@ title: Conclusion :::danger Out of date Please see the -[updated version of this tutorial](./tutorials/embed_linear_genome_view/01_introduction). +[updated version of this tutorial](../embed_linear_genome_view/01_introduction). ::: diff --git a/website/docs/bcc2020_embedding_jbrowse_aliases.md b/website/docs/tutorials/archive/bcc2020_embedding_jbrowse_aliases.md similarity index 99% rename from website/docs/bcc2020_embedding_jbrowse_aliases.md rename to website/docs/tutorials/archive/bcc2020_embedding_jbrowse_aliases.md index c1ef7b8a99..098e6a557f 100644 --- a/website/docs/bcc2020_embedding_jbrowse_aliases.md +++ b/website/docs/tutorials/archive/bcc2020_embedding_jbrowse_aliases.md @@ -6,7 +6,7 @@ title: GRCh38 Reference Name Aliases :::danger Out of date Please see the -[updated version of this tutorial](./tutorials/embed_linear_genome_view/01_introduction). +[updated version of this tutorial](../embed_linear_genome_view/01_introduction). ::: diff --git a/website/docs/bcc2020_plugin_development.md b/website/docs/tutorials/archive/bcc2020_plugin_development.md similarity index 98% rename from website/docs/bcc2020_plugin_development.md rename to website/docs/tutorials/archive/bcc2020_plugin_development.md index 23bdc30f6c..903efc50eb 100644 --- a/website/docs/bcc2020_plugin_development.md +++ b/website/docs/tutorials/archive/bcc2020_plugin_development.md @@ -109,7 +109,7 @@ Notes about the plugin: - we run our plugin development server on a custom port. This is a webpack-dev-server for the plugin code - the config we are pointing at is here https://github.com/cmdcolin/jbrowse-plugin-ucsc-api/blob/master/assets/config_ucsc_api.json and we can see it is basically resolving to a plugin.js file at a CDN, which can be the final built output or the webpack-dev-server served version -![](./img/bcc2020_img1.png) +![](../../../img/bcc2020_img1.png) Screenshot of the UCSC REST API plugin displaying boxes for the interaction features ### Combining the UCSC API plugin with a custom renderer @@ -140,7 +140,7 @@ https://github.com/cmdcolin/jbrowse-plugin-arc-renderer/blob/master/assets/confi This loads both the UCSCPlugin and the ArcRendererPlugin at the same time, and renders the UCSC GeneHancer interactions as arcs -![](./img/bcc2020_img2.png) +![](../../../img/bcc2020_img2.png) ### Making custom view types with plugins @@ -163,7 +163,7 @@ have a gene expression heatmap, barchart, get charts dynamically from an R server side component, make a graph genome, etc. The ideas are endless! And we can make it interact with other views! -![](./img/bcc2020_img3.png) +![](../../../img/bcc2020_img3.png) ### Debugging your plugins diff --git a/website/docs/pag2022_synteny_visualization.md b/website/docs/tutorials/archive/pag2022_synteny_visualization.md similarity index 100% rename from website/docs/pag2022_synteny_visualization.md rename to website/docs/tutorials/archive/pag2022_synteny_visualization.md diff --git a/website/docs/tutorials/config_cli.md b/website/docs/tutorials/config_cli.md new file mode 100644 index 0000000000..2fe636c530 --- /dev/null +++ b/website/docs/tutorials/config_cli.md @@ -0,0 +1,317 @@ +--- +id: config_cli +title: Configure JBrowse using the CLI +toplevel: true +--- + +import Figure from '../figure' + +In order to display your data, JBrowse 2 needs to know about the reference +genome for your organism of interest and needs to have tracks created that +reference your data sources. This guide will show you how to set those up using +the JBrowse CLI. + +:::note +You can also do this configuration with graphical configuration editing +interface built into JBrowse 2. See that guide [here](../config_gui). +::: + +:::info For admins +If you are an administrator configuring JBrowse on a webserver, you must add the +`--out` command followed by your target directory, e.g. `--out /var/www/html/jbrowse2` +to write each jbrowse CLI configuration command to the `config.json` in that target +directory for your webserver to read from. + +See the FAQ for "[what web server do I need](../../faq#what-web-server-do-i-need-to-run-jbrowse-2)" for more information. +::: + +## Pre-requisites + +- Installed and created your JBrowse environment using the [quickstart CLI guide](../../quickstart_cli) +- Some bioinformatics tools: + - [Samtools](http://www.htslib.org/) installed e.g. `sudo apt install samtools` or `brew install samtools`, used for creating FASTA index and BAM/CRAM processing + - [Genometools](http://genometools.org/) installed e.g. `sudo apt install genometools` or `brew install genometools`, (further, `brew install brewsci` and `brew install bio`) used for sorting GFF3 for creating tabix GFF + - [tabix](http://www.htslib.org/doc/tabix.html) installed e.g. `sudo apt intall tabix` and `brew install htslib`, used for creating tabix indexes for BED/VCF/GFF files + +## Adding a genome assembly + +First we will configure an assembly, or reference genome, for for JBrowse 2. +This usually means providing a file that describes the reference sequence for +the organism, such as a FASTA or 2BIT file. + +You can add a reference to a remote file as follows, +this example uses an assembly for a simulated organism +_volvox mythicus_: + +```bash +## Make sure you are in the directory where you have downloaded JBrowse 2 +jbrowse add-assembly http://jbrowse.org.s3.amazonaws.com/genomes/volvox/volvox.fa +``` + +`add-assembly` will automatically create a `config.json` file in the present directory (if `--out` is not specified) and populate it with the assembly, in this example, "volvox". + +### Loading a local FASTA file + +To use your own local data (in the following, replace "genome.fa" with your FASTA file), you'll have to first create an index with samtools, then add it to the `config.json` using a local reference: + +```bash +## Create an indexed (.fai) FASTA file using samtools +samtools faidx genome.fa +## Then, load it using the add-assembly command +## and add your genome assembly to the config +jbrowse add-assembly genome.fa --load copy +``` + +:::info Note +Using `add-assembly` with a FASTA file assumes its index file is `.fai`. If you have an index file with a difference extension, you can manually specify it using the `--index` flag. + +You can run `jbrowse add-assembly --help` to get a list of all the options. +::: + +JBrowse 2 also supports other assembly file formats, such as bgzip-compressed +indexed FASTA (e.g. `.fa.gz`, `.fa.gz.fai`, and `.fa.gz.gzi` files) and 2BIT +files. See [configuring assemblies](../../config_guide#assembly-config) for more info +on formats supported for the sequence file. + +If you have your JBrowse 2 +[running as described](../../quickstart_cli/#running-jbrowse-2) in the JBrowse web +quickstart, you can refresh the page and an add a linear genome view. You will +now see your config in the Assembly dropdown. + +
+ +## Adding a track + +Now we will show you how to add an alignments track and a variant track to JBrowse 2. + +### Adding an alignments track + +For this example we will use a BAM file to add an alignments track. + +As with assemblies, you can add a track using local files or remote locations of your files. + +This example uses the following [BAM](https://jbrowse.org.s3.amazonaws.com/genomes/volvox/volvox.bam) and +[BAM index](https://jbrowse.org.s3.amazonaws.com/genomes/volvox/volvox.bam.bai) files downloaded locally as `/data/volvox.bam` and `/data/volvox.bam.bai` respectively: + +```bash +## Replace with the location of your BAM file +jbrowse add-track /data/volvox.bam --load copy +``` + +:::note +If you're using your own local BAM file and need to generate an index, use samtools as follows: + +```bash +## Create an indexed BAM file using samtools +samtools index file.bam +## Add the BAM and BAI files to the JBrowse config +jbrowse add-track file.bam --load copy +``` + +::: + +This will copy the BAM and BAM index into the JBrowse 2 directory and add a +track pointing at those files to the config file. To see more options adding the +track, such as specifying a name, run `jbrowse add-track --help`. + +If you don't want to copy your BAM file, you can use `--move` to move the file +into the JBrowse 2 directory or `--symlink` to add a symlink to the file to the +JBrowse 2 directory. If you want more control over the location, you can use +`inPlace` to point the track at the file where it is, but be careful with this +option because on a traditional server you will need to ensure that the file is +in a place where the web server is serving it. + +If you have your JBrowse 2 +[running as described](../../quickstart_cli/#running-jbrowse-2) in the JBrowse web +quickstart, you can refresh the page and an add a linear genome view of the +volvox assembly. Then open track selector, and you will see the alignments +track. + +
+ +### Adding a variant track + +Adding a variant track is similar to adding an alignments track. For this +example, we will use a VCF file for the track. JBrowse 2 expects VCFs to be +compressed with `bgzip` and indexed. Similar to the above example, we will +assume the files are at `/data/volvox.vcf.gz` and `/data/volvox.vcf.gz.tbi`. You +can download these file here: +[VCF](https://jbrowse.org.s3.amazonaws.com/genomes/volvox/volvox.vcf.gz) and +[VCF index](https://jbrowse.org.s3.amazonaws.com/genomes/volvox/volvox.vcf.gz.tbi). + +To add the track, run + +```bash +jbrowse add-track /data/volvox.vcf.gz --load copy +``` + +:::note + +If your VCF is not indexed, you can use the `bgzip` and `tabix` tools to +compress index it. + +```bash +bgzip yourfile.vcf +tabix yourfile.vcf.gz +``` + +Alternatively, you can do the same thing with the `bcftools` tool. + +```bash +bcftools view volvox.vcf --output-type z > volvox.vcf.gz +rm volvox.vcf +bcftools index --tbi volvox.vcf.gz +``` + +Note if you get errors about your VCF file not being sorted when using tabix, +you can use bcftools to sort your VCF. + +```bash +bcftools sort file.vcf > file.sorted.vcf +bgzip file.sorted.vcf +tabix file.sorted.vcf.gz +``` + +For more info about `bgzip`, `tabix`, and `bcftools`, see +https://www.htslib.org/. + +::: + +If you have your JBrowse 2 +[running as described](../../quickstart_cli/#running-jbrowse-2) in the JBrowse web +quickstart, you can refresh the page and an add a linear genome view of the +volvox assembly. Then open track selector, and you will see the variant track. + +
+ +### Adding a BigWig/BigBed track + +Probably one of the most simple track types to load is a BigWig/BigBed file +since it does not have any external index file, it is just a single file. + +Make use of this [example file](https://jbrowse.org.s3.amazonaws.com/genomes/volvox/volvox-sorted.bam.coverage.bw) if you do not currently have your own data to add. + +```bash +## Download bigwig or bigbed file +jbrowse add-track volvox-sorted.bam.coverage.bw --load copy +``` + +### Adding a GFF3 file with GFF3Tabix + +To load a GFF3 file, we can sort and index it with tabix, make sure you have [GenomeTools](http://genometools.org/) (to +install can use `sudo apt install genometools`). + +```bash +gt gff3 -sortlines -tidy -retainids yourfile.gff > yourfile.sorted.gff +bgzip yourfile.sorted.gff +tabix yourfile.sorted.gff.gz +jbrowse add-track yourfile.sorted.gff.gz --load copy +``` + +As an alternative to `gt gff3 -sortlines`, use `awk` and GNU `sort`, as follows: + +```bash +awk '$1 ~ /^#/ {print $0;next} {print $0 | "sort -t\"\t\" -k1,1 -k4,4n"}' file.gff > file.sorted.gff +bgzip file.sorted.gff +tabix file.sorted.gff.gz +``` + +The `awk` command is inspired by the method in the [tabix documentation](http://www.htslib.org/doc/tabix.html), but avoids subshells and properly sets the +tab delimiter for GNU sort in case there are spaces in the GFF. + +### Adding a synteny track + +Loading synteny data makes use of all the previous functions we've used so far in this guide. + +Here, we make use of the [grape](https://s3.amazonaws.com/jbrowse.org/genomes/grape/Vvinifera_145_Genoscope.12X.fa.gz) and [peach](https://s3.amazonaws.com/jbrowse.org/genomes/peach/Ppersica_298_v2.0.fa.gz) genome assemblies, but replace with your own data if applicable. + +Use [minimap2](https://github.com/lh3/minimap2) to create a PAF file from FASTA files: + +```bash +## Use minimap2 to create a PAF from your assemblies +minimap2 grape.fa.gz peach.fa.gz > peach_vs_grape.paf +## add each assembly to jbrowse config +## the -n flag names the assemblies explicitly +jbrowse add-assembly grape.fa.gz --load copy -n grape +jbrowse add-assembly peach.fa.gz --load copy -n peach +``` + +As we did [previously](#adding-a-gff3-file-with-gff3tabix) with GFF3 files: + +```bash +## -a establishes an alias for an assembly +jbrowse add-track grape.sorted.gff.gz -a grape --load copy +jbrowse add-track peach.sorted.gff.gz -a peach --load copy +``` + +Next, we'll load the synteny "track" from the PAF file. + +**Order matters here for the `--assemblyNames` parameter:** + +If minimap2 is run as `minimap2 grape.fa peach.fa`, then you need to load as `--assemblyNames peach,grape`. + +The order is reversed between the `minimap2` and `jbrowse` tools. + +```bash +jbrowse add-track peach_vs_grape.paf --assemblyNames peach,grape --load copy +``` + +## Indexing feature names for searching + +The final step of loading your JBrowse instance may include adding a "search +index" so that you can search by genes or other features by their name or ID. + +To do this we can use the `jbrowse text-index` command: + +```bash +jbrowse text-index +``` + +This will index relevant track types e.g. any track with Gff3TabixAdapter (gene +names and IDs) or VcfTabixAdapter (e.g. variant IDs). The command will print +out a progress bar for each track that it is indexing. + +This will also update your `config.json` so that after it completes, you can type a +gene name into the "search box" in the linear genome view or other views and +quickly navigate to genes by gene name. + +See the [text-index](../../cli#jbrowse-text-index) command docs for more info. Also +see the [FAQ entries for text searching](../../faq#text-searching) + +## Conclusion + +Now that you have JBrowse configured with an assembly and a couple of tracks, +you can start customizing it further. Check out the rest of the docs for more +information, especially the [JBrowse CLI](../cli) docs for more details on some of +the steps shown here. + +## Miscellaneous tips + +You can use `--subDir` to organize your data directory: + +```bash +mkdir my_bams +## Copies .bam and .bai files to my_bams folder +jbrowse add-track myfile.bam --subDir my_bams --load copy +``` + +If you are in a directory without a `config.json` file, you can add the `--out` paramter, and the +track or assembly will load into that `config.json` file, as follows: + +```bash +jbrowse add-track /path/to/my/file.bam --out /path/to/my/jbrowse2 --load copy +``` + +Make sure to upgrade your JBrowse release often: + +```bash +jbrowse upgrade +``` + +If you have or desire multiple configs files, you can specify which one you'd like to add configuration options to: + +```bash +## The following adds an assembly to the alt_config.json file specified +## To run JBrowse using this alt_config.json, navigate to http://localhost/jbrowse2/?config=alt_config.json +jbrowse add-assembly mygenome.fa --out /path/to/my/jbrowse2/alt_config.json --load copy +``` diff --git a/website/docs/quickstart_gui.md b/website/docs/tutorials/config_gui.md similarity index 69% rename from website/docs/quickstart_gui.md rename to website/docs/tutorials/config_gui.md index 529d407663..7d23bf6033 100644 --- a/website/docs/quickstart_gui.md +++ b/website/docs/tutorials/config_gui.md @@ -1,10 +1,10 @@ --- -id: quickstart_gui -title: Config editing quick start — graphical interface +id: config_gui +title: Configure JBrowse using the GUI toplevel: true --- -import Figure from './figure' +import Figure from '../figure' In order to display your data, JBrowse 2 needs to know about the reference genome for your organism of interest and needs to have tracks created that @@ -14,7 +14,7 @@ the JBrowse 2's graphical configuration editing. :::note You can also do this configuration with JBrowse CLI. See that guide -[here](../quickstart_cli). +[here](../config_cli). ::: @@ -22,19 +22,23 @@ You can also do this configuration with JBrowse CLI. See that guide This tutorial requires having the following software installed -- [JBrowse CLI](../quickstart_web#install-the-cli-tools) +- [JBrowse CLI](../../quickstart_cli/#installing-the-cli-tools) -- [JBrowse 2 web application](../quickstart_web#using-jbrowse-create-to-install-jbrowse) +- [JBrowse 2 web application](../../quickstart_cli/#using-jbrowse-create-to-download-jbrowse-2) ## Starting JBrowse 2 admin server The JBrowse CLI contains a tool called `admin-server`. This will act as a web server for JBrowse 2 and will write any changes made in JBrowse 2 to a config -file. The `admin-server` is meant to be run only temporarily to help you set up -your config, it is not used for serving your jbrowse instance in production. +file. + +:::warning Note +The `admin-server` is meant to be used temporarily for configuration, **not in +production.** +::: The `admin-server` launches an instance of JBrowse 2 in "admin mode", which then -lets you +lets you: - Add and edit assemblies with the "Assembly manager" - Add tracks and edit tracks @@ -42,26 +46,19 @@ lets you All of these changes will be written by the server to the JBrowse config file (usually `config.json`) located in the JBrowse instance. This is something that -can only be done while the `admin-server` is running, which again, is only meant -to be temporary! +can only be done while the `admin-server` is running, which again, is **only meant +to be temporary!** -To start the `admin-server`, navigate into your JBrowse 2 directory and run +To start the `admin-server`, navigate into your JBrowse 2 directory and run: -```sh-session +```bash ## Start the admin-server jbrowse admin-server ``` -This will then generate a link that you can visit in your web browser - -
+This will then generate a link that you can visit in your web browser: -:::warning - -Note: the admin-server is meant to be used temporarily for configuration, not in -production - -::: +
## Adding a genome assembly @@ -70,11 +67,11 @@ In order to do this, use the navigation bar to open up the Assembly Manager (`Admin > Open Assembly Manager`). This opens up a table which can be used to create, edit, and delete assemblies -in your application +in your application: -
+
-Let's add the hg38 human reference genome to our JBrowse 2 application. +As an example, let's add the hg38 human reference genome to our JBrowse 2 application. Press the "Add New Assembly" button, and enter the necessary information in the form: @@ -85,10 +82,10 @@ form: - fasta index: `https://jbrowse.org/genomes/GRCh38/fasta/hg38.prefix.fa.gz.fai` - gzi: `https://jbrowse.org/genomes/GRCh38/fasta/hg38.prefix.fa.gz.gzi` -
+
Click on "Create New Assembly". Great, we've added an assembly! -We can see that we have successfully added the hg38 assembly. +We can see that we have successfully added the hg38 assembly:
@@ -109,26 +106,30 @@ the form for adding a track `File > Open Track`:
Alternatively, you can use the action button (circular "+") inside the track -selector to access the "Add track" form. +selector to access the "Add track" form:
-In the "Add track" form, you can provide a URL to a file to load. Opening files -from your local machine is not supported currently in the JBrowse 2 web app -(JBrowse desktop does allow this, though, and this functionality may be added in -some form in the future) +In the "Add track" form, you can provide a URL or select a local file to load. -Paste a URL to a file and optionally provide an index file URL too. The -following file formats are supported +The following file formats are supported in core JBrowse 2: -- `tabix`-indexed VCF -- `tabix`-indexed BED -- `tabix`-indexed GFF -- indexed BAM -- indexed CRAM -- BigWig +- CRAM +- BAM +- htsget +- VCF (Tabix-indexed) +- GFF3 (Tabix-indexed) +- BED (Tabix-indexed) - BigBed -- Hi-C (Juicebox) +- BigWig +- JBrowse 1 nested containment lists (NCLists) +- plain text VCF, BED, CSV, TSV, BEDPE, STAR-fusion output (tabular formats) +- PAF (synteny/dotplot) +- Indexed FASTA/BGZip indexed FASTA +- 2bit +- .hic (Hi-C contact matrix visualization) + +Additional data formats can be supported via plugins; checkout the [plugin store](/plugin_store). For tabix files, TBI or CSI indexes are allowed. CSI or BAI is allowed for BAM. Only CRAI is allowed for CRAM. The index will be inferred for BAI or TBI files @@ -137,13 +138,13 @@ index file explicitly. ### Editing a track -First we will open a Linear Genome View using the navigation bar +First, open a Linear Genome View using the navigation bar (`File > Add > Linear Genome View`), and click on the "Select Tracks" button. The configuration settings are accessible by clicking on the ellipses by each track. -
+
Open the configuration editor for the track by clicking on the "Settings" button shown above. You can use the configuration editor to live-edit any configurable @@ -156,7 +157,7 @@ of your JBrowse 2 instance. This is the session that will appear when JBrowse 2 is first visited. To do so, open the form to set the default session (`Admin > Set default session`): -
+
You can use the form to clear your default session, select the currently open session, or any of your previously saved sessions. @@ -164,13 +165,13 @@ select the currently open session, or any of your previously saved sessions. ## Additional resources There are a number of additional features for configuring JBrowse 2. Make sure -to refer to the [config guide](../config_guide) for topics such as -[adding tracks](../config_guide#adding-tracks-and-connections) or -[adding an assembly with the CLI](../config_guide#adding-an-assembly-with-the-cli) +to refer to the [config guide](../../config_guide) for topics such as +[adding tracks](../../config_guide/#track-configurations) or +[adding an assembly with the CLI](../../config_guide/#adding-an-assembly-with-the-cli). ## Conclusion -This quickstart showed how to launch the `admin-server` in the JBrowse CLI to +This guide showed how to launch the `admin-server` in the JBrowse CLI to perform graphical configuration of your application. Specifically, we looked at how to access and use the assembly manager, as well as how to access the configuration editor for tracks. Importantly, all tracks have different diff --git a/website/docs/tutorials/develop_web_and_desktop_tutorial.md b/website/docs/tutorials/develop_web_and_desktop_tutorial.md new file mode 100644 index 0000000000..a20c83b27a --- /dev/null +++ b/website/docs/tutorials/develop_web_and_desktop_tutorial.md @@ -0,0 +1,120 @@ +--- +id: develop_web_and_desktop_tutorial +title: Developing with JBrowse web and desktop +toplevel: true +--- + +import Figure from '../figure' + +The following guide will walk you through setting up a developer environment for development with JBrowse web and JBrowse desktop. + +This guide will provide some steps from the perspective of a plugin developer, but if you are interested in contributing to [jbrowse-components](https://github.com/GMOD/jbrowse-components/), the setup steps are equally relevant. + +## Prerequisites + +- git +- A stable and recent version of [node](https://nodejs.org/en/) +- yarn or npm +- basic familiarity with the command line, React, package management, and npm + +## Setup JBrowse 2 using the latest developer build + +The code for both JBrowse web and JBrowse desktop is found in the [jbrowse-components](https://github.com/GMOD/jbrowse-components/) repository. First we're going to clone the repo and install the dependencies. + +```bash +git clone https://github.com/GMOD/jbrowse-components +cd jbrowse-components +yarn # or npm i +``` + +### To run JBrowse web + +```bash +cd products/jbrowse-web +yarn start # or npm run +``` + +JBrowse web will by default spin up on http://localhost:3000. + +
+ +You can select one of the sample configs to poke around with or to immediately start seeing changes you make in the codebase, or you can run JBrowse against a config with the plugin you're developing. See [the plugin tutorial](../simple_plugin_tutorial/01_introduction) if you need help starting with plugin development. + +If you have a plugin running on port 9000 from the plugin tutorial, navigate to + +``` +http://localhost:3000/?config=http://localhost:9000/jbrowse_config.json +``` + +and you'll see the pluggable elements you've added through your plugin on your running JBrowse session. + +
+ +### To run JBrowse desktop + +Open two tabs in your terminal at `~/jbrowse-components`; in one tab, run: + +```bash +cd products/jbrowse-desktop +yarn serve +``` + +And in the other tab, run: + +```bash +cd products/jbrowse-desktop +yarn develop +``` + +Doing this, you can quickly restart the "react app" part of JBrowse (the tab where you ran `yarn develop`) during your development without having to wait for the electron app (`yarn serve` tab) to restart, as you would if you simply ran `yarn start` in one tab. + +A new window running JBrowse desktop will open. + +### Running JBrowse desktop with a plugin in development + +The following assumes your plugin is running on port `9000`, as shown in the [the plugin tutorial](../simple_plugin_tutorial/02_installation_and_setup). + +JBrowse will open on the splash screen when first spun up. The easiest way to see your local plugin running on JBrowse desktop is to select a quickstart assembly (under "Launch new session" on the left side of the screen) and then press "Go". + +
+ +Then navigate: `Tools` -> `Plugin Store` and press the button at the top of the Plugin Store widget "Add Custom Plugin." + +
+ +It's important to fill these fields in correctly, if you've followed the [the plugin tutorial](../simple_plugin_tutorial/01_introduction), the information you need will be in the `jbrowse_config.json` file. + +You might see something like the following in your `jbrowse_config.json` file: + +```json +{ + "plugins": [ + { + "name": "SomeNewPlugin", + "url": "http://localhost:9000/dist/some-new-plugin.umd.development.js" + } + ] +} +``` + +To which you would fill the fields in like so: + +
+ +After pressing "Submit" on this form, your plugin should be added to your session. + +For easy access to this session, navigate `File` -> `Save as..` to save the `.jbrowse` file somewhere you can easily open it. + +:::warning Note +When developing your plugin using JBrowse desktop, the app will not automatically reload when you make changes to your plugin code. To see these changes applied, **press `F5` to refresh the desktop react application**. + +You can also abort the running process under the "yarn develop" tab we set up earlier, and start it again. +::: + +## Next Steps + +Now that you have your environments and your plugin running, you can start developing for JBrowse 2. + +If you took a detour from the plugin tutorial, [head back to where you left off](../simple_plugin_tutorial/03_running). + +If you'd like some general development information, checkout the series of [developer guides](../../developer_guide) available. diff --git a/website/docs/tutorials/no_build_plugin_tutorial.md b/website/docs/tutorials/no_build_plugin_tutorial.md new file mode 100644 index 0000000000..ef1f41079a --- /dev/null +++ b/website/docs/tutorials/no_build_plugin_tutorial.md @@ -0,0 +1,220 @@ +--- +id: no_build_plugin_tutorial +title: Writing a no-build plugin +toplevel: true +--- + +import Figure from '../figure' + +The following guide will provide a short tutorial on how to create a single page no-build plugin for JBrowse 2. + +## Prerequisites + +- you can run an instance of JBrowse 2 on the web, see [any of our quickstart guides](../../quickstart_cli) for details +- A stable and recent version of [node](https://nodejs.org/en/) +- basic familiarity with the command line and navigating the file system + +## What is the difference between a no-build plugin and a regular plugin? + +A no-build plugin can be a single file that executes all the required code to plug into JBrowse and supplement the functionality of the application with new (simple) features. + +This is in contrast to a "regular" JBrowse plugin that might have a large dependency tree, have substantial adapter logic, or other components that require the entire application build process to execute for the plugin to run properly. + +:::info No-build plugins are great for simple additions to JBrowse + +A single file can easily be hosted in an AWS bucket or otherwise hosted online with minimal resources, and adding it to a JBrowse session is as simple as the "regular" plugin process. + +::: + +## Writing a no-build plugin + +In this tutorial, we're going to add a menu item to our toolbar that opens up a JBrowse widget with citation information. + +### Set up + +Create a single `.js` file in an accessible directory. + +The only critical component of this file is an exported class that will act as our plugin, your template for this file might look like the following: + +`MyNoBuildPlugin.js` + +```js +export default class MyNoBuildPlugin { + name = 'MyNoBuildPlugin' + version = '1.0' + + install(pluginManager) {} + + configure(pluginManager) {} +} +``` + +### Adding a menu item + +A simple no-build plugin is perfect for adding small features to JBrowse, like menu items or minor extension points. + +Here, we're going to add a menu item using the `configure` method in the plugin class. + +`MyNoBuildPlugin.js` + +```js +// ... + configure(pluginManager) { + // adding a new menu to the top toolbar + pluginManager.rootModel.insertMenu('Citations', 4) + + // appending a menu item to the new menu + pluginManager.rootModel.appendToMenu('Citations', { + label: 'Cite this JBrowse session', + onClick: (session) => { } + }) + } +// ... +``` + +### Importing with jbrequire + +Because our plugin is not going to be built with any dependencies, the process for referencing external libraries is a little different. + +The first way to do this is to reference the packages directly; typically the easiest way to do this is to use the library's unpkg, as follows: + +```js +import React from 'https://unpkg.com/es-react@latest/dev/react.js' +``` + +If a package you need to use is found within the JBrowse core project, a special function `jbrequire` can provide your plugin access to these packages. Click [here](https://github.com/GMOD/jbrowse-components/blob/main/packages/core/ReExports/list.ts) for a full list of packages accessible through `jbrequire`. Using `jbrequire` might look like this: + +```js +const { types } = pluginManager.jbrequire('mobx-state-tree') +``` + +which would provide the functionality of mobx-state-tree through that value. + +### Executing some functionality + +Using our new imports, we're going to add a small functionality to this plugin; we're going to add a widget that opens up with some text. + +Our final no-build plugin looks as follows: + +`MyNoBuildPlugin.js` + +```js +// adding our import for React, we'll need this to add elements to the DOM +import React from 'https://unpkg.com/es-react@latest/dev/react.js' + +export default class MyNoBuildPlugin { + name = 'MyNoBuildPlugin' + version = '1.0' + + install(pluginManager) { + // here, we use jbrequire to reference packages exported through JBrowse + const { ConfigurationSchema } = pluginManager.jbrequire( + '@jbrowse/core/configuration', + ) + const WidgetType = pluginManager.jbrequire( + '@jbrowse/core/pluggableElementTypes/WidgetType', + ) + const { ElementId } = pluginManager.jbrequire( + '@jbrowse/core/util/types/mst', + ) + const { types } = pluginManager.jbrequire('mobx-state-tree') + + // we're adding a widget that we can open upon clicking on our menu item + pluginManager.addWidgetType(() => { + // adding a widget to the plugin + return new WidgetType({ + name: 'CiteWidget', + heading: 'Cite this JBrowse session', + configSchema: ConfigurationSchema('CiteWidget', {}), + stateModel: types.model('CiteWidget', { + id: ElementId, + type: types.literal('CiteWidget'), + }), + // we're going to provide this component ourselves + ReactComponent: CiteWidget, + }) + }) + } + + configure(pluginManager) { + pluginManager.rootModel.insertMenu('Citations', 4) + + pluginManager.rootModel.appendToMenu('Citations', { + label: 'Cite this JBrowse session', + onClick: session => { + // upon clicking on htis menu item, we need to add and show our new widget + const widget = session.addWidget('CiteWidget', 'citeWidget', { + view: self, + }) + session.showWidget(widget) + }, + }) + } +} + +// this is our react component +const CiteWidget = props => { + // React.createElement can be used to add html to our widget component + const header = React.createElement('h1', null, 'Cite this JBrowse session') + const content = React.createElement( + 'p', + null, + `Diesh, Colin, et al. "JBrowse 2: A modular genome browser with views of synteny and structural variation. bioRxiv. 2022.`, + ) + + return React.createElement('div', null, [header, content]) +} +``` + +## Adding the plugin to the config + +We'll need to add our plugin to our config file. You can add to an existing file, or create a new one (e.g. `touch jbrowse_config.json`). + +With a file processor, open your `jbrowse_config.json` and add the following to the configuration: + +```json +{ + "plugins": [ + { + "name": "MyNoBuildPlugin", + "esmUrl": "http://localhost:9000/MyNoBuildPlugin.js" + } + ] +} +``` + +It's important to note that the `name` and `esmUrl` must be accurate to the name of your plugin and the name of your file respectively. If localhost:9000 is in use, change the port in the following step. + +Now, for the purposes of this tutorial, we can access our file through localhost to make sure it's working. In production, you'll want this file to be accessible through the web. + +To start a simple webserver to host our files, run the following in the directory containing your `.js` file and your config (if applicable): + +```bash +npx serve --cors --listen 9000 . +``` + +
+ +## Running with JBrowse + +Now we can test our plugin by running our config against an instance of JBrowse. + +Spin up JBrowse web through your method of choice (see one of our [quickstart guides](../../quickstart_cli) if you have not done this already). + +Navigate to your JBrowse web instance, and provide it your configuration using the URL parameters. It might look something like the following: + +``` +http://localhost:3000/?config=http://localhost:9000/jbrowse_config.json +``` + +With JBrowse running and your plugin added to your config, your JBrowse session should look like the following: + +
+ +## Conclusion and next steps + +Congratulations! You built and ran a single file no-build plugin in JBrowse. + +If you'd like some general development information, checkout the series of [developer guides](../../developer_guide) available. + +Have some questions? [Contact us](/contact) through our various communication channels. diff --git a/website/docs/tutorials/plugin_usage.md b/website/docs/tutorials/plugin_usage.md new file mode 100644 index 0000000000..519e22e764 --- /dev/null +++ b/website/docs/tutorials/plugin_usage.md @@ -0,0 +1,316 @@ +--- +id: plugin_usage +title: Installing and using plugins +toplevel: true +--- + +import Figure from '../figure' + +The following will provide a short tutorial on how to use some of the [many plugins available](/plugins) for JBrowse 2. + +Those plugins featured here are a part of the cancer-related database plugins on the [cancer portal](/cancer). + +## Prerequisites + +- JBrowse 2 is [installed on web or desktop](../../quickstart_web) +- Familiarity editing JSON +- Optionally, the [JBrowse CLI installed](../../quickstart_cli) + +## Installing plugins with one click + +Some plugins provide all of their available functionality via the JBrowse interface, and thus can be fully accessed after utilizing the one-click install plugin store within the application. + +
+ +### GDC plugin + +The GDC plugin adapts the resources available through [NCI's Genomic Data Commons](https://gdc.cancer.gov/). + +The GDC plugin provides data adapters for the GDC API to retrieve cancer-related mutations and genes and for unique file types available via the GDC data store. The GDC plugin also provides a new internet account type that permits users to enter their GDC token to authenticate against protected data. + +#### Adding the GDC plugin to a JBrowse session + +The GDC plugin is fully accessible through the JBrowse interface. Utilize the plugin store's one-click install, or add the plugin to your configuration file, like so: + +```json +{ + "plugins": [ + { + "name": "GDC", + "url": "https://unpkg.com/jbrowse-plugin-gdc/dist/jbrowse-plugin-gdc.umd.production.min.js" + } + ] +} +``` + +Optionally, you can add a GDC Track to your configuration like so: + +```json +{ + "type": "GDCTrack", + "trackId": "gdc_plugin_track", + "name": "GDC Explore", + "assemblyNames": ["hg38"], + "category": ["Annotation"], + "adapter": { + "GDCAdapterId": "DefaultGDCAdapter", + "type": "GDCAdapter" + }, + "displays": [ + { + "type": "LinearGDCDisplay", + "displayId": "gdc_plugin_track_linear", + "renderer": { + "color1": "jexl:cast({LOW: 'blue', MODIFIER: 'goldenrod', MODERATE: 'green', HIGH: 'red'})[get(feature,'consequence').hits.edges[.node.transcript.is_canonical == true][0].node.transcript.annotation.vep_impact] || 'lightgray'", + "labels": { + "name": "jexl:get(feature,'genomicDnaChange')" + }, + "type": "SvgFeatureRenderer" + } + } + ] +} +``` + +However these track types are also available to be added to a session via the GDC data import panel. + +
+ +#### The GDC data import panel + +The data import panel provides several options to import data originating from the GDC into JBrowse. + +If you have GDC files downloaded locally, you can drag and drop them into the first Drag and Drop panel to populate your JBrowse session with them. + +You can also utilize an export functionality available via the GDC to bulk-import files if you drag that file into the panel. More detailed instructions are provided via the 'more info' button on the panel. + +
+ +
+ +#### Adding files via the add track menu + +Once installed, the track types and adapters provided by the GDC plugin are also available via the typical add track workflow. + +
+ +#### How do I authenticate protected resources + +Ensure that you have added the GDC internet account type to your configuration file. Presently, this must be done manually. Open the config file in a text processor and add the following: + +```json +{ + "type": "GDCInternetAccount", + "internetAccountId": "GDCExternalToken", + "name": "GDC", + "description": "GDC External Token", + "domains": ["portal.gdc.cancer.gov", "api.gdc.cancer.gov"], + "customEndpoint": "http://localhost:8010/proxy" +} +``` + +When you attempt to add a protected resource to your session either via the add track menu or the GDC data import panel, you will be prompted with a modal overlay to add your GDC token to the session. This token will be retained for other resources you add such that you will not have to add your token every time. + +#### Filtering the GDC Explore track + +When you have a GDC Explore track added to a session either via the config file or via the data import panel, you will be able to filter the features displayed on the track using the Filter option available through the track menu. + +
+ +You can change whether you're seeing mutations or genes using the topmost dropdown menu. + +You can browse through the various filters via the tabs, and add new filters by clicking the 'add' button on the interface. + +Changes made through the filter widget will populated automatically on the track it was opened for. + +The bottom-most dropdown menu provides coloration options for the track, such that you can change the color in which features are represented based on a certain trait. A legend is provided to guide which color corresponds to which feature. + +
+ +### ICGC plugin + +The ICGC plugin adapts the resources available through the [International Cancer Genome Consortium](https://dcc.icgc.org/). + +#### Adding the ICGC plugin to a JBrowse session + +The ICGC plugin is fully accessible through the JBrowse interface. Utilize the plugin store's one-click install, or add the plugin to your configuration file, like so: + +```json +{ + "plugins": [ + { + "name": "ICGC", + "url": "https://unpkg.com/jbrowse-plugin-icgc/dist/jbrowse-plugin-icgc.umd.production.min.js" + } + ] +} +``` + +Optionally, you can add an ICGC Track to your configuration like so: + +```json + { + "type": "ICGCTrack", + "trackId": "icgc_plugin_track", + "name": "ICGC Browse", + "assemblyNames": ["hg38"], + "category": ["Annotation"], + "adapter": { + "ICGCAdapterId": "DefaultICGCAdapter", + "type": "ICGCAdapter" + }, + "displays": [ + { + "type": "LinearICGCDisplay", + "displayId": "icgc_plugin_track_linear" + } + ] + }, +``` + +However these track types are also available to be added to a session via the ICGC data import panel. + +
+ +#### Filtering the ICGC track + +The instructions for how to use the filtering functionality of the ICGC track are essentially the same as [those for the GDC Explore track](#filtering-the-gdc-explore-track). Please refer to those instructions. + +
+ +## Configuring plugins + +Some plugins _require_ their tracks to be configured via the config file because they access remote resources and do not otherwise provide a way to add these tracks to a session. After these plugins have been configured, you can use them with the appropriate assembly like any other track. + +### UCSC plugin + +The UCSC plugin provides access to resources available through the [UCSC API](https://genome.ucsc.edu/goldenPath/help/api.html). + +You can add the UCSC plugin to your JBrowse config file as follows: + +```json +{ + "plugins": [ + { + "name": "UCSC", + "url": "https://unpkg.com/jbrowse-plugin-ucsc/dist/jbrowse-plugin-ucsc.umd.production.min.js" + } + ] +} +``` + +Then add the available tracks that are relevant to you under your "tracks" configuration, for example: + +```json +{ + "type": "FeatureTrack", + "trackId": "genehancer_ucsc_hg38", + "name": "UCSC GeneHancer", + "category": ["Annotation"], + "assemblyNames": ["hg38"], + "adapter": { + "type": "UCSCAdapter", + "track": "geneHancerInteractionsDoubleElite" + } +} +``` + +Make sure to reference the many other available tracks in the [UCSC example config](https://github.com/cmdcolin/jbrowse-plugin-ucsc-api/blob/master/config.json) + +After adding one or more of these tracks to your configuration with the UCSC plugin installed, you will be able to freely enable them on linear genome views opened to the appropriate assembly using the track menu. + +### Biothings plugin + +The Biothings plugin provides access to resources such as myvariant.info and mygene.info. + +You can add the Biothings plugin to your JBrowse config file as follows: + +```json +{ + "plugins": [ + { + "name": "Biothings", + "url": "https://unpkg.com/jbrowse-plugin-biothings/dist/jbrowse-plugin-biothings.umd.production.min.js" + } + ] +} +``` + +Then add the available tracks that are relevant to you under your "tracks" configuration, for example: + +```json +{ + "type": "FeatureTrack", + "trackId": "myvariant_hg19_evs", + "name": "MyVariant v1 (evs)", + "assemblyNames": ["hg19"], + "category": ["Annotation"], + "adapter": { + "query": "query?q={ref}:{start}-{end} AND _exists_:evs&size=1000&size=1000&fields=gwassnps&email=colin.diesh@gmail.com", + "baseUrl": "https://myvariant.info/v1/", + "type": "MyVariantV1Adapter" + } +} +``` + +Make sure to reference the many other available tracks in the [Biothings example config](https://github.com/cmdcolin/jbrowse-plugin-biothings-api/blob/master/config.json) + +After adding one or more of these tracks to your configuration with the UCSC plugin installed, you will be able to freely enable them on linear genome views opened to the appropriate assembly using the track menu. + +### CIVIC plugin + +The CIVIC plugin provides access to resources available through the [CIVIC API](https://civicdb.org/welcome). + +You can add the CIVIC plugin to your JBrowse config file as follows: + +```json +{ + "plugins": [ + { + "name": "CIVIC", + "url": "https://unpkg.com/jbrowse-plugin-civic/dist/jbrowse-plugin-civic.umd.production.min.js" + } + ] +} +``` + +Then add the relevant track to the "tracks" configuration: + +```json +{ + "type": "FeatureTrack", + "trackId": "ncbi_gff_hg19", + "name": "NCBI RefSeq (GFF3Tabix)", + "assemblyNames": ["hg19"], + "category": ["Annotation"], + "metadata": { + "source": "https://www.ncbi.nlm.nih.gov/genome/guide/human/", + "dateaccessed": "12/03/2020" + }, + "adapter": { + "type": "Gff3TabixAdapter", + "gffGzLocation": { + "uri": "https://s3.amazonaws.com/jbrowse.org/genomes/hg19/ncbi_refseq/GRCh37_latest_genomic.sort.gff.gz" + }, + "index": { + "location": { + "uri": "https://s3.amazonaws.com/jbrowse.org/genomes/hg19/ncbi_refseq/GRCh37_latest_genomic.sort.gff.gz.tbi" + } + } + } +} +``` + +Make sure to reference the many other available tracks in the [CIVIC example config](https://github.com/cmdcolin/jbrowse-plugin-civic-api/blob/master/config.json). + +After adding one or more of these tracks to your configuration with the UCSC plugin installed, you will be able to freely enable them on linear genome views opened to the appropriate assembly using the track menu. + +
+ +
+ +## Conclusion + +You should now have an understanding of how to add a plugin to a JBrowse session, and, if applicable, configure a track such that the adapter provided by the plugin is utilized. + +Plugins such as those highlighted in this tutorial provide essential annotations and datasets to a user's JBrowse session and as demonstrated can be accessed in a variety of ways. diff --git a/website/docs/tutorials/simple_plugin_tutorial/01_introduction.md b/website/docs/tutorials/simple_plugin_tutorial/01_introduction.md new file mode 100644 index 0000000000..422b292677 --- /dev/null +++ b/website/docs/tutorials/simple_plugin_tutorial/01_introduction.md @@ -0,0 +1,25 @@ +--- +id: 01_introduction +title: Introduction +toplevel: true +--- + +import Figure from '../../figure' + +JBrowse 2 plugins can be used to add new pluggable elements (views, tracks, +adapters, etc), and to modify behavior of the application by adding code that +watches the application's state. + +For the full list of what kinds of pluggable element types plugins can add, see the [pluggable elements](../../developer_guide/#pluggable-elements) page. + +The following tutorial will walk you through establishing your developer environment, +spinning up a plugin, and running a local JBrowse instance with your custom plugin functionality. + +## Prerequisites + +- git +- A stable and recent version of [node](https://nodejs.org/en/) +- yarn or npm +- basic familiarity with the command line, React, package management, and npm + +Let's get started developing a plugin for JBrowse 2. diff --git a/website/docs/tutorials/simple_plugin_tutorial/02_installation_and_setup.md b/website/docs/tutorials/simple_plugin_tutorial/02_installation_and_setup.md new file mode 100644 index 0000000000..71f424f115 --- /dev/null +++ b/website/docs/tutorials/simple_plugin_tutorial/02_installation_and_setup.md @@ -0,0 +1,115 @@ +--- +id: 02_installation_and_setup +title: Installation and setup +toplevel: true +--- + +import Figure from '../../figure' + +First we're going to install and set up the project for development. + +## Use git to clone the plugin template + +The easiest way to start developing your plugin for JBrowse 2 is to use the [plugin template](https://github.com/gmod/jbrowse-plugin-template). + +To clone the plugin template project, on the command line run: + +```bash +# change jbrowse-plugin-my-project to whatever you wish +git clone https://github.com/GMOD/jbrowse-plugin-template.git jbrowse-plugin-my-project +cd jbrowse-plugin-my-project +``` + +## Initialize the project + +To initialize your project run, + +```bash +yarn init +``` + +You'll be asked a few questions relating to your new project. + +Most fields can be left blank, but **make sure to enter a descriptive name for your plugin** in the first field. + +:::note Tip + +A typical naming convention for JBrowse plugins is **"jbrowse-plugin-"**, or, if you are going to publish to an NPM organization, we advise **"@myscope/jbrowse-plugin-"**. + +::: + +You also need to install the dependencies: + +```bash +yarn # or npm i +``` + +## Setup JBrowse 2 + +Finally, we're going to run: + +```bash +yarn setup +``` + +which will grab the latest release version of JBrowse 2 (in the `.jbrowse` directory) and make it easy for you to run within your plugin project. + +To run JBrowse: + +```bash +yarn browse +``` + +You should see something like the following: + +```bash +yarn run v1.22.10 +$ npm-run-all jbrowse:* +$ shx cp jbrowse_config.json .jbrowse/config.json +$ cross-var serve --listen $npm_package_config_browse_port .jbrowse +UPDATE AVAILABLE The latest version of `serve` is 14.0.1 + + ┌────────────────────────────────────────────────┐ + │ │ + │ Serving! │ + │ │ + │ - Local: http://localhost:8999 │ + │ - On Your Network: http://10.0.0.117:8999 │ + │ │ + │ Copied local address to clipboard! │ + │ │ + └────────────────────────────────────────────────┘ +``` + +We still need to run the plugin though; we need **both to be running** to test our plugin. + +Open a new tab in your terminal and navigate again to your plugin project, then we're going to run our plugin: + +```bash +cd jbrowse-plugin-my-project +yarn start +``` + +Now you can navigate to [http://localhost:8999/](http://localhost:8999/), and see your running JBrowse instance! + +
+ +:::info Note +At this point, you _must_ be running your plugin on port `9000` to see a running JBrowse instance, otherwise you will meet a screen asking you to configure your instance. + +If you'd like to change this port, you can edit the "port" fields under "config" in the `package.json` file. +::: + +We can verify our plugin has been added to our JBrowse session by clicking the first square on the splash screen "Empty," and then navigating `Add` -> `Hello View` in the menu bar. This is the example pluggable element that is added in the template plugin project. + +Next, we're going to add our own pluggable element to the plugin. + +If you're building a small plugin, or only want to develop against the latest release version, you can [move on to the next step](../03_adding_pluggable_element). + +However, if you: + +- want to run your plugin on JBrowse desktop +- would like more descriptive stack traces and debugging +- want to test your plugin against the most recent developer build + +You can develop against the latest JBrowse core build by taking a quick detour to our [developing with JBrowse web and desktop tutorial](../../develop_web_and_desktop_tutorial). diff --git a/website/docs/tutorials/simple_plugin_tutorial/03_adding_pluggable_element.md b/website/docs/tutorials/simple_plugin_tutorial/03_adding_pluggable_element.md new file mode 100644 index 0000000000..74d1ee1508 --- /dev/null +++ b/website/docs/tutorials/simple_plugin_tutorial/03_adding_pluggable_element.md @@ -0,0 +1,523 @@ +--- +id: 03_adding_pluggable_element +title: Adding your own pluggable element +toplevel: true +--- + +import Figure from '../../figure' + +Now that our environment is set up and running, we're going to add our own pluggable element to the project and observe it running in JBrowse. + +For this tutorial, we're going to be creating a custom [widget](../../developer_guide/#widgets), and using a [Jexl](https://github.com/TomFrost/Jexl) callback to open it when we click a chord on the circular genome view. + +
+ +## Add new files, stubs, and install dependencies + +Add a new directory under `src` called `CircularViewChordWidget` with two files `CircularViewChordWidget.tsx`, and `index.tsx`. + +This component is essentially just a react component we're going to embed in a JBrowse widget. + +### A widget's `index.tsx` + +The index file is going to export what our `pluginManager` needs to recognize the widget: a `ReactComponent`, a `configSchema`, and a `stateModelFactory`. + +`CircularViewChordWidget/index.tsx` + +```ts +import { ConfigurationSchema } from '@jbrowse/core/configuration' +import PluginManager from '@jbrowse/core/PluginManager' +import { ElementId } from '@jbrowse/core/util/types/mst' +import { types } from 'mobx-state-tree' + +export { default as ReactComponent } from './CircularViewChordWidget' +export const configSchema = ConfigurationSchema('CircularViewChordWidget', {}) + +export function stateModelFactory(pluginManager: PluginManager) { + const stateModel = types + .model('CircularViewChordWidget', { + id: ElementId, + type: types.literal('CircularViewChordWidget'), + featureData: types.frozen({}), + }) + .actions(self => ({ + setFeatureData(data: any) { + self.featureData = data + }, + clearFeatureData() { + self.featureData = {} + }, + })) + + return stateModel +} +``` + +With [mobx-state-tree](https://mobx-state-tree.js.org/), you can observe here we're defining the properties of our widget and some actions it can take. + +Within the `.model` method, we're defining that the model of our `CircularViewChordWidget` has an `id`, a `type`, and `featureData`. We can define whatever we want in here. For example, we could add a "widgetByline" string property, and be able to use it later in our React component. + +To add the new property and some functions: + +```ts +// ... +export function stateModelFactory(pluginManager: PluginManager) { + const stateModel = types + .model('CircularViewChordWidget', { + id: ElementId, + type: types.literal('CircularViewChordWidget'), + featureData: types.frozen({}), + widgetByline: 'Default widget byline', // NEW + }) + .actions(self => ({ + setFeatureData(data: any) { + self.featureData = data + }, + clearFeatureData() { + self.featureData = {} + }, + // NEW + setWidgetByline(byline: string) { + self.widgetByline = byline + }, + // NEW + getWidgetByline() { + return self.widgetByline + }, + })) + + return stateModel +} +// ... +``` + +Within the `.actions` method, we're definining methods for the model. These can be far more complex than just accessors and mutators (anything you want really). + +If you have a particularly complex model, consider moving your component's model into a `model.ts`, and then exporting the stateModel from `index.ts` similar to how the ReactComponent is exported. + +### A widget's ReactComponent + +Now that we have our model set up, let's build a simple widget that will open when we click the circular genome view chord. + +`CircularViewChordWidget.tsx` + +```ts +import React, { useState } from 'react' +import { observer } from 'mobx-react' + +const CircularViewChordWidget = observer(({ model }: { model: any }) => { + return ( +
+ ) +} + +export default CircularViewChordWidget +``` + +It's important to note the use of the mobx observer here: when making modifications to the model, you'll see those changes populated in your widget, thanks to the observer. We export the widget such that it can be seen by `CircularViewChordWidget/index.tsx`. + +We'll make our widget do something basic: display the chord's information and a message we can edit. + + + +```ts +import React from 'react' +import { observer } from 'mobx-react' +// JBrowse uses material-ui where possible for basic components +import { TextField } from '@material-ui/core' +// @jbrowse/core also has some reusable components available +import { + FeatureDetails, + BaseCard, +} from '@jbrowse/core/BaseFeatureWidget/BaseFeatureDetail' + +const CircularViewChordWidget = observer(({ model }: { model: any }) => { + // these are two properties we have in our model + // widgetByline is going to start out as an empty string + // but featureData will be populated with the information from our chord; + // we'll talk about how that happens more later + const { featureData, widgetByline } = model + return ( +
+ {/* features will always have a name, start, end, and id; they can + have additional information too */} + + {/* here we're just demonstrating using a basic property from the + model and updating it with observer */} +

{widgetByline}

+

Care to change the widget byline?

+ model.setWidgetByline(e.target.value)} + /> +
+ {/* the FeatureDetails component is a proprietary JBrowse component + for displaying feature details clearly */} + +
+ ) +}) + +export default CircularViewChordWidget +``` + +As noted in the codeblock, @jbrowse/core has some reusable UI components exported. If you see something proprietary in the application you'd like to reuse, investigate whether it's exported by @jbrowse/core, and if not [make a request](https://github.com/GMOD/jbrowse-components/discussions/new) for that component to be exported for use in your plugin. + +Now that we have our component built, we can install it into our plugin and test it out. + +## Install the plugin to JBrowse at runtime + +The file `src/index.ts` exports your plugin and installs all the necessary components to JBrowse at runtime such that it runs properly. + +Your `src/index.ts` file is going to look something like the following right now: + +```ts +import Plugin from '@jbrowse/core/Plugin' +import PluginManager from '@jbrowse/core/PluginManager' +import { ViewType } from '@jbrowse/core/pluggableElementTypes' +import { SessionWithWidgets, isAbstractMenuManager } from '@jbrowse/core/util' +import { version } from '../package.json' +import { + ReactComponent as HelloViewReactComponent, + stateModel as helloViewStateModel, +} from './HelloView' + +export default class SomeNewPluginPlugin extends Plugin { + name = 'SomeNewPluginPlugin' + version = version + + install(pluginManager: PluginManager) { + pluginManager.addViewType(() => { + return new ViewType({ + name: 'HelloView', + stateModel: helloViewStateModel, + ReactComponent: HelloViewReactComponent, + }) + }) + } + + configure(pluginManager: PluginManager) { + if (isAbstractMenuManager(pluginManager.rootModel)) { + pluginManager.rootModel.appendToMenu('Add', { + label: 'Hello View', + onClick: (session: SessionWithWidgets) => { + session.addView('HelloView', {}) + }, + }) + } + } +} +``` + +You'll notice we're already adding a new view type and configuring the rootModel in the template's project. We can use these patterns to add our widget. + +`src/index.ts` + +```ts +// imports +// ... +import { ViewType, WidgetType } from '@jbrowse/core/pluggableElementTypes' +// notice we're importing the components we exported from src/CircularViewChordWidget/index.ts +import { + configSchema as circularViewChordWidgetConfigSchema, + stateModelFactory as circularViewChordWidgetStateModelFactory, + ReactComponent as CircularViewChordWidgetComponent +} from './CircularViewChordWidget' +// ... + install(pluginManager: PluginManager) { + // ... + pluginManager.addWidgetType(() => { + return new WidgetType({ + name: 'CircularViewChordWidget', + heading: 'Chord Details', + configSchema: circularViewChordWidgetConfigSchema, + stateModel: circularViewChordWidgetStateModelFactory(pluginManager), + ReactComponent: CircularViewChordWidgetComponent, + }) + }) + } +// ... +``` + +This is also where we'll add our Jexl callback function: + +`src/index.ts` + +```ts +// ... +import { getSession } from '@jbrowse/core/util' +// ... + // Jexl callback functions are adding inside configure in the plugin class + configure(pluginManager: PluginManager) { + // ... + /* .jexl.addFunction is the method to add a function + the first parameter is the name of your jexl function, and how you'll + call it + the second paramter is the supplementary properties the function + needs, here, we need these three properties for + the circular view's chord click function */ + pluginManager.jexl.addFunction( + 'openWidgetOnChordClick', + (feature: any, chordTrack: any) => { + // the session contains a ton of necessary information about the + // present state of the app, here we use it to call the + // showWidget function to show our widget upon chord click + const session = getSession(chordTrack) + + if (session) { + // @ts-ignore + session.showWidget( + // @ts-ignore + session.addWidget( + 'CircularViewChordWidget', + 'circularViewChordWidget', + { featureData: feature.toJSON() }, + ), + ) + session.setSelection(feature) + } + }, + ) + } +// ... +``` + +Now that we've configured the jexl function to our JBrowse session, we can use it essentially anywhere. + +While we could programatically tell certain displays to use this jexl function when they perform an action, for our use case (clicking a chord on the circular view), we can simply write it into our config file. + +## Setup the configuration for proper testing + +To open a view in JBrowse, we need an assembly configured, append the following to your `jbrowse_config.json` file (i.e. after the "plugins" field): + +```json +{ + "assemblies": [ + { + "name": "hg38", + "aliases": ["GRCh38"], + "sequence": { + "type": "ReferenceSequenceTrack", + "trackId": "P6R5xbRqRr", + "adapter": { + "type": "BgzipFastaAdapter", + "fastaLocation": { + "uri": "https://jbrowse.org/genomes/GRCh38/fasta/hg38.prefix.fa.gz", + "locationType": "UriLocation" + }, + "faiLocation": { + "uri": "https://jbrowse.org/genomes/GRCh38/fasta/hg38.prefix.fa.gz.fai", + "locationType": "UriLocation" + }, + "gziLocation": { + "uri": "https://jbrowse.org/genomes/GRCh38/fasta/hg38.prefix.fa.gz.gzi", + "locationType": "UriLocation" + } + } + }, + "refNameAliases": { + "adapter": { + "type": "RefNameAliasAdapter", + "location": { + "uri": "https://jbrowse.org/genomes/GRCh38/hg38_aliases.txt", + "locationType": "UriLocation" + } + } + } + } + ] +} +``` + +Take some time to dissect what's being added here: + +- we're adding the assembly GRCh38 +- it can be referenced either by its name (hg38) or its aliases (GRCh38) +- it has a sequence, which has a BgzipFastaAdapter from which the reference sequence is derived +- these FASTA's are hosted on jbrowse.org, referenced as a UriLocation +- there is also a refNameAliases text file being used to derive the reference names of the assembly + +We're now going to add a track that will make use of our jexl function. As mentioned previously, you _could_ add your jexl function programatically to all tracks of this type, but for now we're just adding it to our assembly _for this specific track_. + +```json + "tracks": [ + { + "type": "VariantTrack", + "trackId": "demo_vcf", + "name": "demo_vcf", + "assemblyNames": ["hg38"], + "category": ["Annotation"], + "adapter": { + "type": "VcfAdapter", + "vcfLocation": { + "locationType": "UriLocation", + "uri": "https://s3.amazonaws.com/jbrowse.org/genomes/hg19/skbr3/reads_lr_skbr3.fa_ngmlr-0.2.3_mapped.bam.sniffles1kb_auto_l8_s5_noalt.new.vcf" + } + }, + "displays": [ + { + "type": "ChordVariantDisplay", + "displayId": "demo_ch_v_disp", + "onChordClick": "jexl:openWidgetOnChordClick(feature, track, pluginManager)", + "renderer": { "type": "StructuralVariantChordRenderer" } + } + ] + } + ] +``` + +Take some time to dissect what's being added here: + +- this is a track that will appear in our track list when we run JBrowse against this assembly +- it's a VariantTrack called "demo_vcf" +- it derives its data from a given UriLocation, the file is a `.vcf` file using the VcfAdapter +- it declares its display, the `ChordVariantDisplay`, and specifies its `onChordClick` callback function +- the specified `onChordClick` callback function is that which we defined in our plugin class, the jexl function + +
+ +## Testing it out + +### Run JBrowse with your new plugin and manually test + +Everything is in place to test this widget we've added to the plugin project out. + +If you shut your instance down, restart JBrowse and your plugin (`yarn browse` and `yarn start`). + +Navigate to [localhost:8999/?config=localhost:3000/jbrowse_config.json](localhost:8999/?config=localhost:3000/jbrowse_config.json) or equivalent to see JBrowse running with your config. + +Now navigate: + +1. Click `Start a new session` -> `Empty` +2. In the top menu bar, click `Add` -> `Circular view` +3. When the view is open, click `Open` beside the assembly +4. Click the far right three rows of rectangles icon in the top left of the circular view, `Open track selector` +5. Select the track we populated from our config +6. Click any chord in the circular view + +Expected result: + +The widget opens on the right hand side with two panels, one with our editable widget byline, and one with our feature data. + +
+ +:::info Troubleshooting +If you get to this point and note that nothing happens, open the developer tools in your browser and investigate the console errors. Also check your running process in your terminal for any errors. Review the code you added to ensure you didn't miss any imports or statements. Check over your config file to ensure that "plugins", "assemblies", and "tracks" are all present for the configuration to work properly. +::: + +## Writing a simple integration test with cypress + +For completeness, we might want to write a few tests for our plugin to ensure that future changes we make do not break the application. + +The `jbrowse-plugin-template` uses cypress to write its integration tests. For plugins, integration tests are a particularly good way to test functionality, as a failing test might indicate the plugin needs to be updated for a new version of JBrowse, or, if interfacing with a third-party API or toolset, that the plugin might have to be tweaked to suit these changes. + +We're going to write a simple integration test suite that executes the action we tested [above](#run-jbrowse-with-your-new-plugin-and-manually-test). + +### Add a cypress test + +See the [cypress documentation](https://docs.cypress.io/) for a dive into options and best practices for writing cypress tests. The following is a very brief overview to get you started. + +Within the directory `cypress`, you'll see a number of folders; you'll likely only need to make use of `fixtures` and `integration`. + +- `fixtures`: This directory is where you might place testing files or a testing config.json file. +- `integration`: This directory is where all your integration tests go. You can organize them however you want. Using the template project, there will be two in there already you can use as an example, but we'll write one of our own. + +Make your own `circ_test.spec.ts` file within `cypress/integration`, and populate it with the following to start: + +```js +describe('Circular chord widget tests', () => { + it('can access the widget', () => { + cy.exec('shx cp cypress/fixtures/hello_view.json .jbrowse') + cy.visit( + '/?config=hello_view.json&session=spec-{"views": [{"type": "CircularView"}]}', + ) + }) +}) +``` + +Right now our test does two things: + +- copies our fixture `hello_view.json` into `.jbrowse` and, +- visits our JBrowse URL (default configured to `localhost:8999`) with that configuration and a circular view open + +Notice the use of [URL params](../../api_guide/#url-params) to speed up the test setup; using URL params like this can come in handy for larger suites. + +Take a moment to add the track specification to `hello_view.json` for testing purposes: + +```json + "tracks": [ + { + "type": "VariantTrack", + "trackId": "demo_vcf", + "name": "demo_vcf", + "assemblyNames": ["hg38"], + "category": ["Annotation"], + "adapter": { + "type": "VcfAdapter", + "vcfLocation": { + "locationType": "UriLocation", + "uri": "https://s3.amazonaws.com/jbrowse.org/genomes/hg19/skbr3/reads_lr_skbr3.fa_ngmlr-0.2.3_mapped.bam.sniffles1kb_auto_l8_s5_noalt.new.vcf" + } + }, + "displays": [ + { + "type": "ChordVariantDisplay", + "displayId": "demo_ch_v_disp", + "onChordClick": "jexl:openWidgetOnChordClick(feature, track, pluginManager)", + "renderer": { "type": "StructuralVariantChordRenderer" } + } + ] + } + ], +``` + +### Running cypress + +First, ensure both your plugin (`yarn start`) and JBrowse (`yarn browse`) are running. Open a third tab in your terminal at your project directory, and run `yarn cypress:open`. A cypress browser will open, click on the test you just wrote to run it. + +
+ +Now that we have a visual on our test running, let's add some more complexity: + +```js +// ... +it('can access the widget', () => { + // ... + // .contains checks elements for one which displays the provided text + cy.contains('Open').click() + // .get can retrieve a given property of an element, data-testid is used for testing with jest and works well + cy.get('[data-testid="circular_track_select"]').click() + cy.contains('demo_vcf').click() + // if any asyncronous calls are made it might be pertinent to .wait + cy.wait(2000) + // we use force: true here to make sure we can click the chord, that's an svg overlayed over many other svg's + cy.get('[data-testid="chord-1591034956-148"]').click({ force: true }) + // we can see this text, so we know we've accomplished our goal + cy.contains('Care to change the widget byline?') +}) +``` + +We can add one more small test to check data input: + +```js +it('can change the byline', () => { + // you can use the share functionality to generate a session at any point you might want to revisit for future tests + cy.visit( + 'http://localhost:8999/?config=config.json&session=share-V0PG_1mjHJ&password=ho4Uq', + ) + cy.wait(2000) + // .get can be used to nab elements of a certain type as well, here we're referencing the third 'input' + cy.get('input').eq(3).type('Some testing string') + cy.get('input').eq(3).type('{enter}') + cy.contains('Some testing string') +}) +``` + +This test will check the functionality of our input field and updating the property on the widget model. + +Run your suite again for completeness (you may have to reset your instance of cypress, then run `yarn cypress:open` again). + +
+ +## Next steps + +We have a complete and tested plugin, so now we're ready to publish it to NPM and request that it be added to the plugin store. diff --git a/website/docs/tutorials/simple_plugin_tutorial/04_publishing.md b/website/docs/tutorials/simple_plugin_tutorial/04_publishing.md new file mode 100644 index 0000000000..b8b2d5b026 --- /dev/null +++ b/website/docs/tutorials/simple_plugin_tutorial/04_publishing.md @@ -0,0 +1,91 @@ +--- +id: 04_publishing +title: Publishing a plugin to the store +toplevel: true +--- + +import Figure from '../../figure' + +Sometimes you might write a plugin that is specific to you or your organization's needs, but you also might want to share it with the greater community. That's where the [plugin store](/plugin_store) shows off its strengths. + +As a plugin developer, you can publish your plugin to NPM, and then reqest that your plugin be added to the plugin store. After your plugin is successfully whitelisted, you will see it within the JBrowse app's plugin store widget and you and others can freely install the plugin into their JBrowse session. Any further publications you make to the plugin via NPM will automatically be updated for the plugin available through the plugin store. + +The following document will describe how to accomplish this. + +## Publish your plugin to NPM + +The following will guide you through publishing with [NPM](https://www.npmjs.com/). You'll need an NPM account and token to do this, so please set that up first through the NPM site. + +If you'd prefer not to publish to NPM, you can host your plugin files elsewhere, just ensure the link is accessible publicly. + +When your plugin is in a publishable state and you have NPM credentials, you can run the following within your plugin's root directory (where `package.json` is found): + +```bash +yarn publish +``` + +Set the version to whatever you'd like, enter your credentials, and then complete the publication process. Once you can see your package on NPM, move on to the next step. + +## Request your plugin be added to the plugin store + +To populate your plugin to the plugin store, it must be added to the [plugin list](https://github.com/GMOD/jbrowse-plugin-list), a whitelist of JBrowse plugins. + +Navigate to the [plugin list repository](https://github.com/GMOD/jbrowse-plugin-list) and use the github UI to **Fork** the repository. + +
+ +:::info Tip + +It's easy enough to edit the files required using the github UI, but feel free to clone and push to the forked repo using your local environment as well. + +::: + +### Optional: create an image for your plugin + +An image helps communicate the capabilities of your plugin to adopters at a glance. Consider creating an 800 x 200 `.png` screenshot of a core feature of your plugin to show off. + +We recommend using [pngquant](https://pngquant.org/) to compress your image to keep the repo manageable. + +Once your image is all set, you can upload it to your forked repo (ideally in ~/jbrowse-plugin-list/img/) using the Github UI or pushing the file from your computer. + +### Adding the details for your plugin to the list + +Once forked, you can edit the `plugins.json` file to include the following information regarding your new plugin: + +`plugins.json` + +```json +{ + "plugins": [ + // ...other plugins already published, + { + // this plugin name needs to match what is in your package.json + "name": "SomeNewPlugin", + "authors": ["You, dear reader!"], + "description": "JBrowse 2 plugin that demonstrates adding a simple pluggable element", + // change this to your github repo for your plugin + "location": "https://github.com/ghost/jbrowse-plugin-some-new-plugin", + // assuming you published to NPM, this url is going to be mostly the same, other than the correct name of your project + "url": "https://unpkg.com/jbrowse-plugin-some-new-plugin/dist/jbrowse-plugin-some-new-plugin.umd.production.min.js", + // make sure the license is accurate, otherwise use "NONE" + "license": "MIT", + // the image url will be wherever you placed it in the repo earlier, img is appropriate + "image": "https://raw.githubusercontent.com/GMOD/jbrowse-plugin-list/main/img/plugin-screenshot-fs8.png" + } + ] +} +``` + +Push your changes to the `main` branch of your forked repo when you're done. + +### Make a pull request + +Now that your plugin's information is accurate, navigate again to the [plugin list repository](https://github.com/GMOD/jbrowse-plugin-list), and create a new pull request. + +In the pull request UI, click "compare across forks" and select your fork as the head repository to merge into the main of `jbrowse-plugin-list`. Your changes should show in the editor, and you can create your PR. + +
+ +## Next steps + +The JBrowse development team will review your plugin to ensure that it is functional, then when it is merged in the plugin will be available on the plugin store. diff --git a/website/docs/tutorials/simple_plugin_tutorial/05_conclusion.md b/website/docs/tutorials/simple_plugin_tutorial/05_conclusion.md new file mode 100644 index 0000000000..7ab5111276 --- /dev/null +++ b/website/docs/tutorials/simple_plugin_tutorial/05_conclusion.md @@ -0,0 +1,15 @@ +--- +id: 05_conclusion +title: Conclusion +toplevel: true +--- + +import Figure from '../../figure' + +In this tutorial, we set up a development environment for JBrowse 2 and added a custom pluggable element to a plugin. + +We also published the plugin to NPM and requested that it be added to the JBrowse plugin store so others can access our plugin. + +To learn more about the various pluggable elements available in JBrowse (and thus more that you can do with plugins!) checkout our [developer guide documentation](../../developer_guide/). + +If you have further questions about plugin development, or development with JBrowse in general, stop by the JBrowse team [gitter channel](https://gitter.im/GMOD/jbrowse2), or start a discssion on the [jbrowse-components discussions forum](https://github.com/GMOD/jbrowse-components/discussions). diff --git a/website/docs/user_guide.md b/website/docs/user_guide.md index 179c99ec65..58291b4d86 100644 --- a/website/docs/user_guide.md +++ b/website/docs/user_guide.md @@ -6,67 +6,63 @@ title: User guide import Figure from './figure' +This user guide is a comprehensive compilation of all general UI navigation, tools/features available for some of the different track types, and other useful features for using JBrowse. + +Use the navigation menu on the right to skip to a topic of interest, if applicable. + ## Navigating the UI ### Linear genome view usage -To start a linear genome view, use the menu bar +To open a linear genome view (LGV), use the menu bar: `ADD` -> `Linear genome view` -File->Add->Linear genome view +#### Scrolling -#### Using the location search box +You can scroll side to side using your mouse wheel or via click and drag. Left and right pan buttons found in the header of the LGV can also be used to scroll in their respective directions. -- Use the search box in the LGV -- Enter syntax chr1:1-100 or chr1:1..100 (e.g. colon or dash is allowed) -- You can also specify an assembly name with the locstring {hg19}chr1:1-100 -- Discontinuous regions can be specified with a space-separated loc string like - chr1:1-100 chr2:1-100 -- You can make a region horizontally flipped by using [rev] after the string - e.g. chr1:1-100[rev] -- You can also space-separate a single locstring e.g. "chr1 1 100" and it will - attempt to resolve this +#### Zooming -You can also use the search box to search by gene name (if it is configured) +The zoom buttons and the slider bar found in the header of the linear genome view can be used to zoom in and out on the view -
+You can also hold the `Ctrl` key and use your mousewheel or trackpad to scroll to zoom in and out. -In order to enable name searching, you or the admin on the instance will need to -create a "text index". See the [quickstart -guide](../quickstart_cli#indexing-feature-names-for-searching) for more info. +#### Re-ordering tracks -#### Scrolling +Click and drag up or down on the drag handle on the track labels (indicated by six vertical dots) to reorder tracks. -Mouse wheel can scroll side to side, as well as click and drag. The pan buttons -also exist in the header of the linear genome view +
-#### Zooming +#### Using the location search box -The zoom buttons exist in the header of the linear genome view, and there is -also a slider bar to zoom in and out. +The location search box is located at the top of the LGV. -Note: You can also hold the Ctrl key and use your mousewheel or -trackpad to scroll and this will zoom in and out +You can search a location in several ways when typing in the search box: -#### Re-ordering tracks +1. Searching by region and location, e.g. `chr1:1..100` or `chr1:1-100` or `chr1 1 100` +2. Searching by assembly, region, and location, e.g. `{hg19}chr1:1-100` +3. Searching discontinuous regions, delimited by a space, and opening them side-by-side, e.g. `chr1:1..100 chr2:1..100` +4. Searching in any of the above ways and appending \[rev\] to the end of the region will horizontally flip it, e.g. `chr1:1-100\[rev\]` +5. If configured, searching by gene name or feature keywords, e.g. `BRCA1` -There is a drag handle on the track labels indicating by the six dots, clicking -and dragging on this part of the track label can reorder tracks +To configure name searching, you or the admin of the instance will need to +create a "text index". See the [configuration guide](../tutorials/config_cli#indexing-feature-names-for-searching) for more information. -## Adding tracks +
-To add a new track or connection, you can use the menu bar in the app to open -the form for adding a track: +## Opening tracks -File->Open Track +To open a new track or connection, use the menu bar: `File` -> `Open track..` -
+
-Note: There is also a circular "+" button inside the track selector menu that -can also be used to access the "Add track" form. +:::info Tip +There is a circular plus (+) icon button inside the "Available tracks" widget that +can also be used to access the "Add a track" form. +::: -
+
-In the "Add track" form, you can provide a URL to a file to load, or you can +In the "Add a track" form, you can provide a URL to a file to load, or you can also open files from your local machine. In some cases, you need to provide an index (bigwig files for example have no index, but BAM/CRAM or tabix filetypes like VCF/GFF/BED tabix do). In some cases we can automatically infer the index @@ -74,35 +70,39 @@ e.g. if you provide a URL for a BAM and the index filename is bamfilename +'.bai' but you may need to manually supply it in some cases (index inference can't be done with files from your local machine) -The following file formats are supported +The following file formats are supported in core JBrowse 2: -- Tabixed VCF -- Tabixed BED -- Tabixed GFF -- BAM - CRAM -- BigWig +- BAM +- htsget +- VCF (Tabix-indexed) +- GFF3 (Tabix-indexed) +- BED (Tabix-indexed) - BigBed -- .hic file (Juicebox) -- PAF +- BigWig +- JBrowse 1 nested containment lists (NCLists) +- plain text VCF, BED, CSV, TSV, BEDPE, STAR-fusion output (tabular formats) +- PAF (synteny/dotplot) +- Indexed FASTA/BGZip indexed FASTA +- 2bit +- .hic (Hi-C contact matrix visualization) + +Additional data formats can be supported via plugins; checkout the [plugin store](/plugin_store). For tabix files, TBI or CSI indexes are allowed. CSI or BAI is allowed for BAM. Only CRAI is allowed for CRAM. The index will be inferred for BAI or TBI files as filename+'.bai' for example, but if it is different than this, make sure to specify the index file explicitly. -Note: If you are an administrator, you can add tracks with the command line or -with the admin server [add-track](../cli#jbrowse-add-track) or [admin-server -guide](../quickstart_gui) +:::info Note +If you are an administrator, you can add tracks with the [command line](../tutorials/config_cli/#adding-a-track) or with the [admin server](../tutorials/config_gui). +::: ### Undo and redo You can undo the closing of a view, track, or any other action in the UI with -the ToolsUndo/Redo -buttons. The keyboard shortcuts Ctrl+Z -/Cmd+Z (mac) work for undo as well -as Ctrl+Y -/Cmd+Shift+Z (mac) for redo. +the Tools->Undo/Redo buttons. The keyboard shortcut "ctrl+z"/"cmd+z"(mac) work +for undo as well as "ctrl+y"/"cmd+shift"z"(mac) ### Sharing sessions @@ -110,16 +110,16 @@ On JBrowse Web, the main menu bar has a "Share" button to enable users to share their sessions with other people. The share button generates a URL that can be sent to other users. -Note: Share sessions is not available on JBrowse Desktop. +You **cannot** copy the URL in your address bar and send it to other users, you +**must** use the "Share" button to share your session. -Also note: you can't copy the literal URL in your address bar and send it to -other users, you must use the "Share" button to do that, but you can copy and -paste the URL in your URL bar between different tabs in your local browser -though +:::info Note +Sharing sessions is not available for JBrowse Desktop. +::: -
+
-The session URL will contain +The session URL will contain the following: - what views are on the screen, and settings for the views (e.g. track labels overlapping or offset) @@ -127,9 +127,7 @@ The session URL will contain - extra tracks that you added with the "Add track workflow" - for the alignments track, the show soft clipping and sort settings on the pileup -- etc - -All this stuff gets included in the session +- ...and more! This means you can share links with your custom tracks with other users, without being a JBrowse admin! @@ -147,15 +145,15 @@ from the track menu on the track selector. ### About track dialog Using the track menu as described above, you can access the "About track" -dialog +dialog. -
+
### Editing track configs As a non-admin user, in order to edit a track config, you have to make a copy of the track. This will copy it to your "session tracks", which you can edit -freely +freely.
@@ -163,11 +161,7 @@ freely The scale bars accept a click-and-drag action to select a region. Rubberband selection can be performed on both the main (lower) and overview (upper) scale bars. - - -
+
#### Track label positioning @@ -175,23 +169,19 @@ Track labels can be positioned on their own row or overlapping the data to save vertical screen space. They can also be hidden. This is done by clicking on the hamburger menu for a specific view. - - -
+
#### Horizontally flip The view can be horizontally flipped, or reverse complemented, to make the -coordinates go from right to left instead of left to right +coordinates go from right to left instead of left to right. We use triangles pointing in the direction of the orientation in the overview -bar to help indicate whether the app is horizontally flipped or not +bar to help indicate whether the app is horizontally flipped or not. -Here is an example of before and after horizontally flipping the view +Here is an example of before and after horizontally flipping the view: -
+
## Sequence track @@ -205,9 +195,9 @@ bottom. ## Alignments tracks Visualizing alignments is an important aspect of genome browsers. This guide -will go over the main features of the "Alignments track" +will go over the main features of the "Alignments track." -The alignments track is a combination of a pileup and a coverage visualization +The alignments track is a combination of a pileup and a coverage visualization. ### Pileup visualization @@ -223,16 +213,7 @@ The coverage visualization shows the depth-of-coverage of the reads at each position on the genome, and also draws using colored boxes any occurrence of mismatches between the read and the reference genome, so if 50% of the reads had a T instead of the reference A, half the height of the coverage histogram -would contain a 'red' box - - +would contain a 'red' box.
@@ -240,21 +221,13 @@ https://s3.amazonaws.com/jbrowse.org/code/jb2/alpha/master/index.html?config=tes If a read contains bases that do not map the the genome properly, they can either be removed from the alignment (hard clipping) or can be included, and -not shown by default (soft clipping) +not shown by default (soft clipping). JBrowse 2 also contains an option to "show the soft clipping" that has occurred. This can be valuable to show the signal around a region that contains -structural variation or difficult mappability - - +structural variation or difficult mappability. +
### Sort by options @@ -262,115 +235,114 @@ http://localhost:3001/?config=test_data%2Fvolvox%2Fconfig.json&session=eJztVVFv2 The alignments tracks can also be configured to "sort by" a specific attribute for reads that span **the center line**. -By default the center line is not shown, but by showing it (Go to the view's -hamburger menu->Select "Show center line") then you will obtain a better idea -of what the "sort by" option is doing +By default the center line is not shown, but by showing it (detailed below) then you will obtain a better idea +of what the "sort by" option is doing. ### Showing the center line -Here is how to turn on the center line - 1. Open the hamburger menu in the top left of the linear genome view 2. Select "Show center line" -
+
+
-### Sorting by base +:::info Note +The center line is used by the 'Sort by' function discussed in this section; the sort is performed using properties of the feature, or even exact base pair underlying the center line. +::: -Sorting by base will re-arrange the pileup so that the reads that have a -specific base-pair mutation at the position crossing the center line (which is -1bp wide) will be arranged in a sorted manner. To enable Sort by base +### Sorting by base pair + +Sorting by base pair will re-arrange the pileup so that the reads that have a +specific base pair mutation at the position crossing the center line (which is +1bp wide) will be arranged in a sorted manner. To enable Sort by base pair: 1. Open the track menu for the specific track using the vertical '...' in the track label -2. Select 'Sort by'->'Base pair' +2. Select `Pileup settings`->`Sort by`->`Base pair`
### Sort, color and filter by tag -We can now also do things like - -- Sort by tag -- Filter by tag -- Color by tag - -With these features, we can create very expressive views of alignments tracks. +With these features, we can create expressive views of alignments tracks. For example, in the below step-by-step guide, it shows how to color and sort -the reads by the HP tag. +the reads by the HP tag: -
+
### Color by modifications/methylation If you have data that marks DNA/RNA modifications using the MM tag in BAM/CRAM -format, then the alignments track can use these to color these. It uses two -modes +format, then the alignments track can use these merks to color these modification. It uses two +modes: 1. Modifications mode - draws the modifications as they are 2. Methylation mode - draws both unmodified and modifified CpGs (unmodified positions are not indicated by the MM tag and this mode considers the sequence context) -
-
-
+
+
+
### Color by orientation JBrowse uses the same color scheme as IGV for coloring by pair orientation. These pair orientations can be used to reveal complex patterns of structural -variation +variation. -See -https://software.broadinstitute.org/software/igv/interpreting_pair_orientations -for a good guide on interpreting these pair orientations +See [IGV's Interpreting Color by Pair Orientation guide](https://software.broadinstitute.org/software/igv/interpreting_pair_orientations) +for further details on interpreting these pair orientations. -
+
### Sashimi-style arcs The alignments track will draw sashimi-track style arcs across spliced alignments (indicated by N in the CIGAR string). If the reads additionally are tagged with XS tags, it will try to draw the arcs using the strand indicated by -the alignment +the alignment. -
+
-Note that you can disable these by clicking on the track menu (vertical ... +:::info Note +You can disable these by clicking on the track menu (vertical "..." next to track label, then hovering over SNPCoverage options, and unchecking -"Draw arcs") +"Draw arcs"). +::: ### Insertion and clipping indicators -The alignments track will also draw a upside-down histogram of insertion and +The alignments track will also draw an upside-down histogram of insertion and soft/hard clipped read counts at all positions, and mark significant positions (covering 30% of the reads) with a colored triangle.
-Also, insertions that are larger than 10bp are marked with a special larger -purple rectangle, seen in the below screenshot. Generally, long reads span +Also, insertions that are larger than 10bp are marked with a larger +purple rectangle, seen in the screenshot below. Generally, long reads span larger insertions better, so this feature is more prominant with large reads. -
+
-Note that you can disable these by clicking on the track menu (vertical ... +:::info Note +You can disable these by clicking on the track menu (vertical "..." next to track label, then hovering over SNPCoverage options, and unchecking -"Draw insertion/clipping indicators" and "Draw insertion/clipping counts") +"Draw insertion/clipping indicators" and "Draw insertion/clipping counts"). +::: ## Quantitative tracks Visualizing genome signals, whether it is read depth-of-coverage or other -signal, can often be done by using BigWig or other quantitative feature files +signal, can often be done by using BigWig or other quantitative feature files. -
+
-### Example use case: viewing whole-genome coverage for profiling CNV +### Viewing whole-genome coverage for profiling CNV -The latest JBrowse also allows refining the resolution of BigWig tracks, and -viewing whole genome coverage. This allows us to get detailed global views of -CNV for example from whole-genome coverage profiling. +You can refine the resolution of BigWig tracks, and +view whole genome coverage to get detailed global views of +CNV, for example from whole-genome coverage profiling. Here is a short picture guide to setup a whole-genome view of a BigWig for CNV coverage visualization: @@ -384,17 +356,18 @@ coverage visualization: 5. Go to the track menu and select "Resolution->Finer resolution" a couple times until resolution looks nice -Also note: all tracks have a drag handle on the bottom of it which you can drag -down to make the track taller. +:::info Note +All tracks have a drag handle on the bottom, which you can drag down to make the track taller. +::: -
+
## Multi-quantitative tracks In 2.1.0, we created the ability to have "Multi-quantitative tracks" which is a single track composed of multiple quantitative signals, which have their Y-scalebar synchronized. There are 5 rendering modes for the multi-quantitative -tracks +tracks. - xyplot - multirowxyplot @@ -402,16 +375,16 @@ tracks - multirowline - multidensity -You can interactively change these settings through the track menu +You can interactively change these settings through the track menu. -
+
With the "multi-row" settings (multirowxyplot, multirowline, multidensity) the track colors are not modified. For the overlapping (xyplot, multiline), the tracks will be autoassigned a color from the palette. You can manually -customize the subtrack colors from the track menu as well +customize the subtrack colors from the track menu as well. -
+
Oftentimes, one of the outliers on one of the subtracks may affect the Y-scalebar too much, so it is often helpful to use the "Autoscale type->Local @@ -420,31 +393,30 @@ the min or max scores is available via the track menu also. ### Adding multi-quantitative tracks via the UI -There are several ways to create multi-quantitative tracks from scratch +There are several ways to create multi-quantitative tracks from scratch. 1. Using the add track panel to open up a list of URLs for bigwig files, or from several local tracks from your machine 2. Using the track selector to add multiple tracks to your current selection, and then creating a multi-wiggle track from the tracks in your selection 3. Hardcoding the multiwiggle track in your config file (see [multi-quantitative track configuration](../config_guide#multiquantitativetrack-config) for more info) -
-
+
+
## Variant tracks Visualizing variant tracks from the VCF format alongside the original alignment -evidence track is a common workflow for validating your results. In JBrowse 2 -we can open a variant track and an alignments track as shown below +evidence track is a common workflow for validating your results, shown below: -
+
### Variant widget The variant features have a specialized widget that contains a table indicating all the calls that were made in a multi-sample VCF. Some VCF files, like the 1000 genomes VCF, can contain thousands of samples in a single file. This -table can display the details +table can display the details. -
+
## Comparative views @@ -452,110 +424,84 @@ The dotplot view is a 2D comparative view that can display alignments between different genome assemblies, or even compare a long-read or NGS short-read against the genome. -### Opening a dotplot view - -Currently the workflow for launching a dotplot is done by navigating in the -header bar to the File->Add->Dotplot view - -This will let you select the genome assemblies of interest - -Then you can also provide a synteny file in the form of PAF via the Add track -workflow +### Opening a dotplot view or synteny view -Then currently you must configuration edit the PAFAdapter to indicate the two -assemblies in the PAFAdapter +1. Navigate on the header bar `Add`->`Dotplot view` or `Add`->`Linear synteny view` +2. Select the genome assemblies of interest +3. Optionally, add a .paf, .out (MashMap), .delta (Mummer), .chain, .anchors or .anchors.simple (MCScan) file -
+
-
+
-
+
-See the [dotplot configuration](../config_guide#dotplot-view-config) for more -detailed descriptions - -### Opening a linear synteny view - -Use the main menu bar to select - -File->Add->Linear synteny view - -
- -
- -See the [linear synteny -configuration](../config_guide#configuring-linear-synteny-views) for more details -on manually configuring the synteny view +
### Opening a synteny view from a dotplot view -We have designed JBrowse 2 to be able to open up a synteny view from a dotplot -view. This is enabled by "display modes" so that the same track can be -displayed in different contexts. +You can open a synteny view from a dotplot view by selecting a region on the dotplot and clicking "Open linear synteny view", shown below: -Here is a short demo that shows opening a synteny view from a dotplot view -selection - -
+
### Long read vs reference plots -One can also launch a dotplot view that compares a long read to the reference -genome by +You can also launch a dotplot view that compares a long read to the reference +genome: -- Right clicking an alignment -- Select "Dotplot read vs ref" or "Linear read vs ref" in the context menu +1. With your alignments track open, right click on an alignment +2. Select "Dotplot read vs ref" or "Linear read vs ref" in the context menu -
+
-
+
## Hi-C tracks -Visualizing Hi-C data can be performed with .hic files which are generated by +Visualizing Hi-C data can be performed with .hic files generated by the Juicebox software suite. It uses the hic-straw module developed by the -juicebox/igv.js team to visualize it in jbrowse. +juicebox/igv.js team to visualize it in JBrowse. Currently configuration options are basic for Hi-C tracks, see -[configuration](../config_guide#hictrack-config) for info about configuring Hi-C -tracks +[the comprehensive config guide](../config_guide#hictrack-config) for info about configuring Hi-C +tracks. -
+
## SV inspector -The SV inspector is a "workflow" that is designed to help users inspect -structural variant calls +The Structural Variant (SV) inspector is a "workflow" that is designed to help users inspect +structural variant calls. ### Opening the SV inspector We can start the SV inspector by launching it from the App level menu bar -
+
+ +This will bring up an "import form" that asks you for your SV evidence. -This will bring up an "import form" that asks you for your SV evidence. This -can be provided opening a file locally or using a URL for files in the -following formats: +The following formats are supported: +- CSV, TSV - VCF or VCF.gz (plain text VCF, or (b)gzipped VCF) -- BEDPE +- BED, BEDPE - STAR-fusion result file -
+
### Example SV inspector workflow We can start the SV inspector workflow by opening up this file containing translocation events called from a breast cancer cell line SKBR3, based on -these published data http://schatz-lab.org/publications/SKBR3/ +[these published data](http://schatz-lab.org/publications/SKBR3/). ## Example VCF for use in the SV inspector https://jbrowse.org/genomes/hg19/skbr3/reads_lr_skbr3.fa_ngmlr-0.2.3_mapped.bam.sniffles1kb_auto_l8_s5_noalt.new.vcf -Copy this URL and paste it into the import form and select hg19 +Copy this URL and paste it into the import form and select hg19: -
+
### SV inspector results @@ -563,14 +509,14 @@ After loading the user's requested file, you will have a tabular view with each row representing a row of the file you opened, along with a whole-genome overview of the SVs on the right -
+
Now here is where things can become interesting We can search and filter the table, with filtering and searching being reflected in the circular view as well. -
+
### Launching breakpoint split view @@ -582,13 +528,13 @@ view" This allows us to inspect the breakpoints of the structural variant, and compare each side to the alignments. -
+
-## Getting the protein sequence for features +### Getting the protein sequence for features If you have a track with gene or transcript level features, then the feature detail sidebar will automatically stitch together the sequence for that -feature. The options include: +feature. Options include: - CDS - the coding sequences, spliced together - Protein - performs protein translation on the CDS, currently assuming the @@ -602,10 +548,10 @@ feature. The options include: - Gene w/ 500 up+down stream + 10bp of introns - the spliced gene sequence with 10bp around the splice sites shown and the up/down stream shown -Some of the params such as 500bp and 10bp are arbitrarily chosen, if you are -interested in adjusting these parameters let us know +Some of the parameters such as 500bp and 10bp are arbitrarily chosen, if you are +interested in adjusting these default parameters [let us know](/contact/). -
+
## Using the plugin store @@ -614,34 +560,35 @@ plugin will be added to your "session" which can be shared with the share button (or if you are an admin running the admin-server, then it will be added to the config file). -This can add extra functions or tracks or many other interesting features. For +This can add extra functions, tracks, or many other interesting features. For example, if you add the CIVIC plugin, it will automatically add a track that contains the CIVIC cancer gene annotations to hg19. -Note that not all plugins are directly useful from being added (sometimes it -needs extra work on the part of the plugin developer to make them useful in the -GUI, some plugins require hand editing of configuration files). +:::info Note +Not all plugins are directly useful from being added, and require hand-editing of the configuration file to be useful. +If you would like to use such a plugin and do not have access to the configuration file, contact your administrator. +::: -
+
## Using the bookmark widget -JBrowse Web and JBrowse Desktop come with a "bookmark widget" that you can use to store lists -of interesting regions that would would like to easily revisit. +The "bookmark widget" can store lists of interesting regions that you might like to easily revisit. -
+
The bookmark stores a list of single regions (chromosome, start, and end coordinate), and clicking on the regions in the bookmark widget will launch a linear genome view at that region. -You can also import a list of regions from a BED file +You can also import a list of regions from a BED file. -
+
-Note also that you can add "notes" for your list of regions, allowing a simple -way to "annotate" your datasets +:::info Note +You can add "notes" for your list of regions by double clicking on the label field to easily "annotate" your datasets. +::: -
+
-Finally, you can export your list of regions to a BED file or TSV +Finally, you can export your list of regions to a BED file or TSV. diff --git a/website/package.json b/website/package.json index 3733f8030e..e3e496c9f6 100644 --- a/website/package.json +++ b/website/package.json @@ -26,7 +26,8 @@ "clsx": "^1.1.1", "copy-to-clipboard": "^3.3.1", "react": "^18.0.0", - "react-dom": "^18.0.0" + "react-dom": "^18.0.0", + "react-player": "^2.10.1" }, "browserslist": { "production": [ diff --git a/website/sidebars.json b/website/sidebars.json index d9bd110f00..d6fa7092e7 100644 --- a/website/sidebars.json +++ b/website/sidebars.json @@ -1,25 +1,57 @@ { "sidebar": [ "introduction", - "combined", { "type": "category", "label": "Quickstart guides", - "items": [ - "superquickstart_web", - "quickstart_web", - "quickstart_cli", - "quickstart_gui", - "quickstart_desktop" - ] + "items": ["quickstart_desktop", "quickstart_web", "quickstart_cli"] }, "user_guide", "config_guide", - "developer_guide", - "embedded_components", - "api_guide", - "urlparams", - "cli", + { + "type": "category", + "label": "Developer guides", + "items": [ + "developer_guide", + "devguide_config", + "devguide_pluggable_elements", + "urlparams", + "api_guide" + ] + }, + { + "type": "category", + "label": "User tutorials", + "items": [ + "tutorials/config_cli", + "tutorials/config_gui", + "tutorials/plugin_usage", + { + "type": "category", + "label": "Archive", + "items": [ + "tutorials/archive/pag2022_synteny_tutorial", + "tutorials/archive/bcc2020_plugin_development", + { + "type": "category", + "label": "BCC2020 - Embedding JBrowse 2 in your website", + "items": [ + "tutorials/archive/bcc2020_embedding_jbrowse_01_getting_started", + "tutorials/archive/bcc2020_embedding_jbrowse_02_introduction", + "tutorials/archive/bcc2020_embedding_jbrowse_03_simple_site", + "tutorials/archive/bcc2020_embedding_jbrowse_04_assemblies", + "tutorials/archive/bcc2020_embedding_jbrowse_05_tracks", + "tutorials/archive/bcc2020_embedding_jbrowse_06_other_options", + "tutorials/archive/bcc2020_embedding_jbrowse_07_creating_the_view", + "tutorials/archive/bcc2020_embedding_jbrowse_08_default_session", + "tutorials/archive/bcc2020_embedding_jbrowse_09_reacting", + "tutorials/archive/bcc2020_embedding_jbrowse_10_conclusion" + ] + } + ] + } + ] + }, { "type": "category", "label": "Developer tutorials", @@ -38,39 +70,26 @@ "tutorials/embed_linear_genome_view/08_reacting", "tutorials/embed_linear_genome_view/09_conclusion" ] - } - ] - }, - { - "type": "category", - "label": "JBrowse educational courses", - "items": [ + }, { "type": "category", - "label": "Archive", + "label": "Writing a simple JBrowse 2 plugin", "items": [ - "pag2022_synteny_tutorial", - "bcc2020_plugin_development", - { - "type": "category", - "label": "BCC2020 - Embedding JBrowse 2 in your website", - "items": [ - "bcc2020_embedding_jbrowse_01_getting_started", - "bcc2020_embedding_jbrowse_02_introduction", - "bcc2020_embedding_jbrowse_03_simple_site", - "bcc2020_embedding_jbrowse_04_assemblies", - "bcc2020_embedding_jbrowse_05_tracks", - "bcc2020_embedding_jbrowse_06_other_options", - "bcc2020_embedding_jbrowse_07_creating_the_view", - "bcc2020_embedding_jbrowse_08_default_session", - "bcc2020_embedding_jbrowse_09_reacting", - "bcc2020_embedding_jbrowse_10_conclusion" - ] - } + "tutorials/simple_plugin_tutorial/01_introduction", + "tutorials/simple_plugin_tutorial/02_installation_and_setup", + "tutorials/simple_plugin_tutorial/03_adding_pluggable_element", + "tutorials/simple_plugin_tutorial/04_publishing", + "tutorials/simple_plugin_tutorial/05_conclusion" ] - } + }, + "tutorials/develop_web_and_desktop_tutorial", + "tutorials/no_build_plugin_tutorial" ] }, + "jbrowse_jupyter", + "embedded_components", + "cli", + "combined", "faq" ] } diff --git a/website/src/components/MiniFeatures/index.js b/website/src/components/MiniFeatures/index.js new file mode 100644 index 0000000000..bf073c55da --- /dev/null +++ b/website/src/components/MiniFeatures/index.js @@ -0,0 +1,88 @@ +import React from 'react' +import clsx from 'clsx' +import styles from './styles.module.css' +import ReactPlayer from 'react-player' + +const FeatureList = [ + { + title: + 'Download a sample configuration file to quick start using JBrowse 2 for cancer workflows', + img: '../img/sv_inspector_importform_loaded.png', + link: '/jb2/download', + description: + 'Includes hg19 and hg38 as default assemblies, the plugins highlighted below, and some sample data for exemplar purposes.', + }, + { + title: 'Download the most recent version of JBrowse 2', + img: '../img/multirow_bigwig.png', + link: '/jb2/download', + description: 'Available as a desktop application or web application.', + }, +] + +function Feature({ img, title, link, description }) { + return ( +
+
+ {/* eslint-disable-next-line react/jsx-no-target-blank*/} + + {`A + +
+
+

{title}

+

{description}

+
+
+ ) +} + +export default function MiniFeatures() { + return ( +
+
+
+
+
+ +
+
+

Check out the video tutorial series

+

+ Also checkout our{' '} + + written guides + + . +

+
+
+ {FeatureList.map((props, idx) => ( + + ))} +
+
+
+ ) +} diff --git a/website/src/components/MiniFeatures/styles.module.css b/website/src/components/MiniFeatures/styles.module.css new file mode 100644 index 0000000000..1f412a66cd --- /dev/null +++ b/website/src/components/MiniFeatures/styles.module.css @@ -0,0 +1,11 @@ +.features { + display: flex; + align-items: center; + padding: 2rem 0; + width: 100%; +} + +.featureSvg { + height: 208px; + width: 408px; +} diff --git a/website/src/components/MiniPlugins/index.js b/website/src/components/MiniPlugins/index.js new file mode 100644 index 0000000000..d1444bff1a --- /dev/null +++ b/website/src/components/MiniPlugins/index.js @@ -0,0 +1,163 @@ +import React from 'react' +import pluginStyles from './styles.module.css' +import { + Link, + Typography, + Card, + CardActions, + CardContent, + CardMedia, + Button, +} from '@mui/material' + +import { + Person, + AccountBalance, + GitHub, + Book, + Outbound, +} from '@mui/icons-material' + +const plugins = [ + { + name: 'GDC', + authors: ['Garrett Stevens', 'Colin Diesh', 'Rob Buels', 'Caroline Bridge'], + description: + "JBrowse 2 plugin for integrating resources from NCI's Genomic Data Commons (GDC).", + location: 'https://github.com/GMOD/jbrowse-plugin-gdc', + repoName: 'jbrowse-plugin-gdc', + url: 'https://unpkg.com/jbrowse-plugin-gdc/dist/jbrowse-plugin-gdc.umd.production.min.js', + license: 'MIT', + image: + 'https://raw.githubusercontent.com/GMOD/jbrowse-plugin-list/main/img/gdc-screenshot-fs8.png', + guideURL: '/jb2/docs/tutorials/plugin_usage/#gdc-plugin', + resourceURL: 'https://portal.gdc.cancer.gov/', + }, + { + name: 'ICGC', + authors: ['Caroline Bridge'], + description: + 'JBrowse 2 plugin for integrating resources from the International Cancer Genome Consortium (ICGC).', + location: 'https://github.com/GMOD/jbrowse-plugin-icgc', + repoName: 'jbrowse-plugin-icgc', + url: 'https://unpkg.com/jbrowse-plugin-icgc/dist/jbrowse-plugin-icgc.umd.production.min.js', + license: 'Apache License 2.0', + image: + 'https://raw.githubusercontent.com/GMOD/jbrowse-plugin-list/main/img/icgc-screenshot-fs8.png', + guideURL: '/jb2/docs/tutorials/plugin_usage/#icgc-plugin', + resourceURL: 'https://dcc.icgc.org/', + }, + { + name: 'UCSC', + authors: ['Colin Diesh'], + description: + 'JBrowse 2 plugin for integrating resources from the UCSC API.', + location: 'https://github.com/cmdcolin/jbrowse-plugin-ucsc-api', + repoName: 'jbrowse-plugin-uscs-api', + url: 'https://unpkg.com/jbrowse-plugin-ucsc/dist/jbrowse-plugin-ucsc.umd.production.min.js', + license: 'MIT', + image: + 'https://raw.githubusercontent.com/GMOD/jbrowse-plugin-list/main/img/ucsc-screenshot-fs8.png', + guideURL: '/jb2/docs/tutorials/plugin_usage/#ucsc-plugin', + resourceURL: 'https://genome.ucsc.edu/', + }, + { + name: 'Biothings', + authors: ['Colin Diesh'], + description: + "JBrowse 2 plugin for adapting the API's from mygene.info and myvariant.info to get super rich gene annotations.", + location: 'https://github.com/cmdcolin/jbrowse-plugin-biothings-api', + repoName: 'jbrowse-plugin-biothings-api', + url: 'https://unpkg.com/jbrowse-plugin-biothings/dist/jbrowse-plugin-biothings.umd.production.min.js', + license: 'MIT', + image: + 'https://raw.githubusercontent.com/GMOD/jbrowse-plugin-list/main/img/biothings-screenshot-fs8.png', + guideURL: '/jb2/docs/tutorials/plugin_usage/#biothings-plugin', + resourceURL: 'https://biothings.io/', + }, + { + name: 'CIVIC', + authors: ['Colin Diesh'], + description: + 'JBrowse 2 plugin for fetching data from the CIVIC clinical interpretation of cancer variants.', + location: 'https://github.com/cmdcolin/jbrowse-plugin-civic-api', + repoName: 'jbrowse-plugin-civic-api', + url: 'https://unpkg.com/jbrowse-plugin-civic/dist/jbrowse-plugin-civic.umd.production.min.js', + license: 'Apache License 2.0', + image: + 'https://raw.githubusercontent.com/GMOD/jbrowse-plugin-list/main/img/civic-screenshot-fs8.png', + guideURL: '/jb2/docs/tutorials/plugin_usage/#civic-plugin', + resourceURL: 'https://civicdb.org/welcome', + }, +] + +export const PluginCard = ({ plugin }) => { + return ( + + {plugin.image ? ( + + ) : null} + +
+ {plugin.name} +
+
+ + {plugin.authors.join(', ')} + + + {plugin.license === 'NONE' ? 'No license' : plugin.license} + +
+
+ + + {plugin.repoName} + + + + {plugin.name} website + +
+ Description: + {plugin.description} +
+ + + +
+ ) +} + +export default function MiniPlugins() { + return ( +
+
+
+ {plugins.map((plugin, idx) => ( + + ))} +
+
+
+ ) +} diff --git a/website/src/components/MiniPlugins/styles.module.css b/website/src/components/MiniPlugins/styles.module.css new file mode 100644 index 0000000000..0ac9fe35a4 --- /dev/null +++ b/website/src/components/MiniPlugins/styles.module.css @@ -0,0 +1,65 @@ +.button { + text-transform: none; +} + +.section { + margin-top: 24px; + margin-bottom: 32px; +} + +.container { + display: flex; + justify-content: center; + align-items: center; +} + +.body { + margin: 5em; +} + +.topLinks { + margin: 0 auto; + display: flex; + align-items: space-between; + justify-content: center; +} + +.card { + margin: 1em auto; + width: 500px; +} + +.cardMedia { + height: 200px; + width: 800px; +} + +@media (max-width: 800px) { + .cardMedia { + display: none; + } + + .card { + width: auto; + } +} + +.icon { + margin-left: 0.5em; + margin-right: 0.5em; +} + +.topButton { + margin: 1em; +} + +.dataField { + display: flex; + align-items: center; + margin: 0.4em 0em; +} + +.customLink { + color: #fff; + text-decoration-color: #fff; +} diff --git a/website/src/pages/cancer.js b/website/src/pages/cancer.js new file mode 100644 index 0000000000..4e79685656 --- /dev/null +++ b/website/src/pages/cancer.js @@ -0,0 +1,81 @@ +import React from 'react' +import clsx from 'clsx' +import Link from '@docusaurus/Link' +import useDocusaurusContext from '@docusaurus/useDocusaurusContext' +import Layout from '@theme/Layout' +import MiniFeatures from '@site/src/components/MiniFeatures' +import MiniPlugins from '../components/MiniPlugins' + +import styles from './styles.module.css' +import { Alert, AlertTitle } from '@mui/material' + +function Header() { + const { siteConfig } = useDocusaurusContext() + + return ( +
+
+

JBrowse 2 Cancer Resources

+

+ A hub of tutorials, plugins, and information regarding cancer data and + JBrowse 2 +

+
+ + Browse the cancer demo web instance + +
+
+
+ ) +} + +export default function Home() { + const { siteConfig } = useDocusaurusContext() + return ( + +
+
+ +
+

JBrowse 2 plugins to connect cancer annotation datasets

+

+ This is a hub of plugins that provide an instance of JBrowse 2 + access to cancer-associated annotation datasets. +

+ + + Don't see your dataset here? + + {/* eslint-disable-next-line react/jsx-no-target-blank*/} + + Make a request + + {' '} + for a new plugin to connect the resource, or{' '} + + {/* eslint-disable-next-line react/jsx-no-target-blank*/} + + design your own plugin + + + . + +
+
+
+ + ) +} diff --git a/website/static/img/add_lgv.png b/website/static/img/add_lgv.png new file mode 100644 index 0000000000..e26d81610d Binary files /dev/null and b/website/static/img/add_lgv.png differ diff --git a/website/static/img/add_track_form.png b/website/static/img/add_track_form.png index 8a481e99bc..3a23be70ae 100644 Binary files a/website/static/img/add_track_form.png and b/website/static/img/add_track_form.png differ diff --git a/website/static/img/add_track_tracklist.png b/website/static/img/add_track_tracklist.png index 8cab9a7bb1..227c4f18ef 100644 Binary files a/website/static/img/add_track_tracklist.png and b/website/static/img/add_track_tracklist.png differ diff --git a/website/static/img/alignments_center_line.png b/website/static/img/alignments_center_line.png index ae81e9dca0..aa53b11a65 100644 Binary files a/website/static/img/alignments_center_line.png and b/website/static/img/alignments_center_line.png differ diff --git a/website/static/img/alignments_center_line_menu.png b/website/static/img/alignments_center_line_menu.png new file mode 100644 index 0000000000..a6682840ad Binary files /dev/null and b/website/static/img/alignments_center_line_menu.png differ diff --git a/website/static/img/alignments_soft_clipped.png b/website/static/img/alignments_soft_clipped.png index 158ce2885c..5b2cb43ba0 100644 Binary files a/website/static/img/alignments_soft_clipped.png and b/website/static/img/alignments_soft_clipped.png differ diff --git a/website/static/img/alignments_soft_clipped_menu.png b/website/static/img/alignments_soft_clipped_menu.png new file mode 100644 index 0000000000..32536f5646 Binary files /dev/null and b/website/static/img/alignments_soft_clipped_menu.png differ diff --git a/website/static/img/alignments_sort_by_base.png b/website/static/img/alignments_sort_by_base.png index 34a9e55d85..866cea9477 100644 Binary files a/website/static/img/alignments_sort_by_base.png and b/website/static/img/alignments_sort_by_base.png differ diff --git a/website/static/img/alignments_sort_by_base_pair_menu.png b/website/static/img/alignments_sort_by_base_pair_menu.png new file mode 100644 index 0000000000..e54da6ea55 Binary files /dev/null and b/website/static/img/alignments_sort_by_base_pair_menu.png differ diff --git a/website/static/img/config_not_found.png b/website/static/img/config_not_found.png index 633ce4801f..43ab5e136f 100644 Binary files a/website/static/img/config_not_found.png and b/website/static/img/config_not_found.png differ diff --git a/website/static/img/desktop_add_cstm_plgn.png b/website/static/img/desktop_add_cstm_plgn.png new file mode 100644 index 0000000000..03402db6e5 Binary files /dev/null and b/website/static/img/desktop_add_cstm_plgn.png differ diff --git a/website/static/img/desktop_add_cstm_plgn_modal.png b/website/static/img/desktop_add_cstm_plgn_modal.png new file mode 100644 index 0000000000..536077ce06 Binary files /dev/null and b/website/static/img/desktop_add_cstm_plgn_modal.png differ diff --git a/website/static/img/dotplot.png b/website/static/img/dotplot.png index 0664e855d3..d1a8e360a6 100644 Binary files a/website/static/img/dotplot.png and b/website/static/img/dotplot.png differ diff --git a/website/static/img/dotplot_add.png b/website/static/img/dotplot_add.png index 2fa0f5f669..5a9a8d2c71 100644 Binary files a/website/static/img/dotplot_add.png and b/website/static/img/dotplot_add.png differ diff --git a/website/static/img/dotplot_menu.png b/website/static/img/dotplot_menu.png index 503e24afeb..2ae52e9f86 100644 Binary files a/website/static/img/dotplot_menu.png and b/website/static/img/dotplot_menu.png differ diff --git a/website/static/img/lgv_usage_guide.png b/website/static/img/lgv_usage_guide.png new file mode 100644 index 0000000000..edcf96de04 Binary files /dev/null and b/website/static/img/lgv_usage_guide.png differ diff --git a/website/static/img/linear_align_ctx_menu.png b/website/static/img/linear_align_ctx_menu.png new file mode 100644 index 0000000000..cf2150a890 Binary files /dev/null and b/website/static/img/linear_align_ctx_menu.png differ diff --git a/website/static/img/multirow_bigwig.png b/website/static/img/multirow_bigwig.png new file mode 100644 index 0000000000..fe2876bdac Binary files /dev/null and b/website/static/img/multirow_bigwig.png differ diff --git a/website/static/img/no_build_final.png b/website/static/img/no_build_final.png new file mode 100644 index 0000000000..c2fa1b7079 Binary files /dev/null and b/website/static/img/no_build_final.png differ diff --git a/website/static/img/no_build_localhost.png b/website/static/img/no_build_localhost.png new file mode 100644 index 0000000000..6f74563f37 Binary files /dev/null and b/website/static/img/no_build_localhost.png differ diff --git a/website/static/img/plugin-dev-tutorial-cypress.png b/website/static/img/plugin-dev-tutorial-cypress.png new file mode 100644 index 0000000000..307fbc0521 Binary files /dev/null and b/website/static/img/plugin-dev-tutorial-cypress.png differ diff --git a/website/static/img/plugin-dev-tutorial-final.png b/website/static/img/plugin-dev-tutorial-final.png new file mode 100644 index 0000000000..d3daa11034 Binary files /dev/null and b/website/static/img/plugin-dev-tutorial-final.png differ diff --git a/website/static/img/plugin-dev-tutorial-running-cypress.png b/website/static/img/plugin-dev-tutorial-running-cypress.png new file mode 100644 index 0000000000..6feeaa5640 Binary files /dev/null and b/website/static/img/plugin-dev-tutorial-running-cypress.png differ diff --git a/website/static/img/plugin-dev-tutorial-track-added.png b/website/static/img/plugin-dev-tutorial-track-added.png new file mode 100644 index 0000000000..a4d961cd25 Binary files /dev/null and b/website/static/img/plugin-dev-tutorial-track-added.png differ diff --git a/website/static/img/plugin-store.png b/website/static/img/plugin-store.png new file mode 100644 index 0000000000..44877d4261 Binary files /dev/null and b/website/static/img/plugin-store.png differ diff --git a/website/static/img/plugin_template_spin_up_start.png b/website/static/img/plugin_template_spin_up_start.png new file mode 100644 index 0000000000..d17337622b Binary files /dev/null and b/website/static/img/plugin_template_spin_up_start.png differ diff --git a/website/static/img/plugin_usage_gdc_add_track_adapters.png b/website/static/img/plugin_usage_gdc_add_track_adapters.png new file mode 100644 index 0000000000..e37f8c56e2 Binary files /dev/null and b/website/static/img/plugin_usage_gdc_add_track_adapters.png differ diff --git a/website/static/img/plugin_usage_gdc_file_uuid.png b/website/static/img/plugin_usage_gdc_file_uuid.png new file mode 100644 index 0000000000..044f0bcbe5 Binary files /dev/null and b/website/static/img/plugin_usage_gdc_file_uuid.png differ diff --git a/website/static/img/plugin_usage_gdc_filter_widget.png b/website/static/img/plugin_usage_gdc_filter_widget.png new file mode 100644 index 0000000000..6011e51868 Binary files /dev/null and b/website/static/img/plugin_usage_gdc_filter_widget.png differ diff --git a/website/static/img/plugin_usage_gdc_import.png b/website/static/img/plugin_usage_gdc_import.png new file mode 100644 index 0000000000..430678d512 Binary files /dev/null and b/website/static/img/plugin_usage_gdc_import.png differ diff --git a/website/static/img/plugin_usage_gdc_multi_filter.png b/website/static/img/plugin_usage_gdc_multi_filter.png new file mode 100644 index 0000000000..8e4c64f8b4 Binary files /dev/null and b/website/static/img/plugin_usage_gdc_multi_filter.png differ diff --git a/website/static/img/plugin_usage_gdc_quick_add.png b/website/static/img/plugin_usage_gdc_quick_add.png new file mode 100644 index 0000000000..9db1574514 Binary files /dev/null and b/website/static/img/plugin_usage_gdc_quick_add.png differ diff --git a/website/static/img/plugin_usage_guide_icgc_filter.png b/website/static/img/plugin_usage_guide_icgc_filter.png new file mode 100644 index 0000000000..687c85cb15 Binary files /dev/null and b/website/static/img/plugin_usage_guide_icgc_filter.png differ diff --git a/website/static/img/plugin_usage_guide_icgc_panel.png b/website/static/img/plugin_usage_guide_icgc_panel.png new file mode 100644 index 0000000000..f25b6a6674 Binary files /dev/null and b/website/static/img/plugin_usage_guide_icgc_panel.png differ diff --git a/website/static/img/plugin_usage_tracks_hg19.png b/website/static/img/plugin_usage_tracks_hg19.png new file mode 100644 index 0000000000..a7a4cfe7bc Binary files /dev/null and b/website/static/img/plugin_usage_tracks_hg19.png differ diff --git a/website/static/img/plugin_usage_tracks_hg38.png b/website/static/img/plugin_usage_tracks_hg38.png new file mode 100644 index 0000000000..ae04d35026 Binary files /dev/null and b/website/static/img/plugin_usage_tracks_hg38.png differ diff --git a/website/static/img/publish_compare_repo_guide.png b/website/static/img/publish_compare_repo_guide.png new file mode 100644 index 0000000000..3b0148cf90 Binary files /dev/null and b/website/static/img/publish_compare_repo_guide.png differ diff --git a/website/static/img/publish_fork_repo_guide.png b/website/static/img/publish_fork_repo_guide.png new file mode 100644 index 0000000000..c213793bfa Binary files /dev/null and b/website/static/img/publish_fork_repo_guide.png differ diff --git a/website/static/img/template_hello_view.png b/website/static/img/template_hello_view.png new file mode 100644 index 0000000000..f3ae4bb2b1 Binary files /dev/null and b/website/static/img/template_hello_view.png differ diff --git a/website/yarn.lock b/website/yarn.lock index 357ee826fd..7e93e2b9c2 100644 --- a/website/yarn.lock +++ b/website/yarn.lock @@ -3462,7 +3462,7 @@ deep-extend@^0.6.0: resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== -deepmerge@^4.2.2: +deepmerge@^4.0.0, deepmerge@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== @@ -4985,6 +4985,11 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== +load-script@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/load-script/-/load-script-1.0.0.tgz#0491939e0bee5643ee494a7e3da3d2bac70c6ca4" + integrity sha512-kPEjMFtZvwL9TaZo0uZ2ml+Ye9HUMmPwbYRJ324qF9tqMejwykJ5ggTyvzmrbBeapCAbk98BSbTeovHEEP1uCA== + loader-runner@^4.2.0: version "4.3.0" resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" @@ -5154,6 +5159,11 @@ memfs@^3.1.2, memfs@^3.4.3: dependencies: fs-monkey "^1.0.3" +memoize-one@^5.1.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" + integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q== + merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" @@ -6166,7 +6176,7 @@ react-error-overlay@^6.0.11: resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.11.tgz#92835de5841c5cf08ba00ddd2d677b6d17ff9adb" integrity sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg== -react-fast-compare@^3.2.0: +react-fast-compare@^3.0.1, react-fast-compare@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb" integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== @@ -6214,6 +6224,17 @@ react-loadable-ssr-addon-v5-slorber@^1.0.1: dependencies: "@babel/runtime" "^7.10.3" +react-player@^2.10.1: + version "2.10.1" + resolved "https://registry.yarnpkg.com/react-player/-/react-player-2.10.1.tgz#f2ee3ec31393d7042f727737545414b951ffc7e4" + integrity sha512-ova0jY1Y1lqLYxOehkzbNEju4rFXYVkr5rdGD71nsiG4UKPzRXQPTd3xjoDssheoMNjZ51mjT5ysTrdQ2tEvsg== + dependencies: + deepmerge "^4.0.0" + load-script "^1.0.0" + memoize-one "^5.1.1" + prop-types "^15.7.2" + react-fast-compare "^3.0.1" + react-router-config@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/react-router-config/-/react-router-config-5.1.1.tgz#0f4263d1a80c6b2dc7b9c1902c9526478194a988"