Skip to content

Commit 9f4169b

Browse files
committed
Misc
1 parent 0cdff0f commit 9f4169b

7 files changed

+53
-211
lines changed

README.md

+33-17
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,27 @@
1212
```bash
1313
git clone [email protected]:GMOD/genomefeatures
1414
yarn
15-
yarn dev
15+
yarn dev # vite demo
16+
yarn storybook # storybook examples
1617
```
1718

1819
# Screenshot
1920

2021
![Example 1](images/ExampleIsoform1.png)
2122

22-
## Live demo
23+
## Demo
2324

24-
https://gmod.org/genomefeatures/
25+
Demo https://gmod.org/genomefeatures/
2526

26-
## Loading data
27+
Storybook https://gmod.org/genomefeatures/storybook
2728

28-
### Apollo REST API
29+
## Loading data
2930

30-
The original component accessed data via an Apollo REST API
31+
### Legacy access pattern - Apollo REST API
3132

32-
This is still supported, though it is a overkill for most usages
33+
The original implementation of this component required fetching data from an
34+
Apollo REST API endpoint. This is still supported, though it is a overkill for
35+
most usages
3336

3437
```typescript
3538
import {
@@ -61,7 +64,7 @@ const gfc = new GenomeFeatureViewer(
6164
genome,
6265
tracks: [
6366
{
64-
type,
67+
type: 'ISOFORM_EMBEDDED_VARIANT',
6568
trackData,
6669
variantData,
6770
},
@@ -79,24 +82,37 @@ And then in your HTML
7982
<svg id="svgelement"></svg>
8083
```
8184

82-
### Accessing JBrowse NCList files via @gmod/nclist
85+
### Static access pattern - Accessing JBrowse NCList files and VCF tabix files
8386

84-
Uses a "baseUrl" and "urlTemplate" similar to JBrowse 1 configs
87+
After the refactor, we can now fetch files from static files like JBrowse 1
88+
NCList and VCF tabix files. This means you do not need a complex apollo
89+
deployment to use this component: just some static files
8590

8691
```typescript
8792
import {
8893
fetchNCListData,
94+
fetchTabixVcfData,
8995
parseLocString,
9096
GenomeFeatureViewer,
9197
} from 'genomefeatures'
9298

93-
const locString = 'NC_045512.2:17894..28259'
94-
const genome = 'SARS-CoV-2'
99+
const locString = '2L:130639..135911'
100+
const genome = 'fly'
101+
102+
const vcfTabixUrl =
103+
'https://s3.amazonaws.com/agrjbrowse/VCF/7.0.0/fly-latest.vcf.gz'
104+
const ncListUrlTemplate =
105+
'https://s3.amazonaws.com/agrjbrowse/docker/7.0.0/FlyBase/fruitfly/tracks/All_Genes/{refseq}/trackData.jsonz'
106+
95107
const region = parseLocString(locString)
96108
const trackData = await fetchNCListData({
97109
region,
98-
baseUrl: `https://s3.amazonaws.com/agrjbrowse/docker/3.2.0/SARS-CoV-2/tracks/`,
99-
urlTemplate: 'All%20Genes/NC_045512.2/trackData.jsonz',
110+
urlTemplate: ncListUrlTemplate,
111+
})
112+
113+
const variantData = await fetchTabixVcfData({
114+
url: vcfTabixUrl,
115+
region,
100116
})
101117

102118
const gfc = new GenomeFeatureViewer(
@@ -105,8 +121,9 @@ const gfc = new GenomeFeatureViewer(
105121
genome,
106122
tracks: [
107123
{
108-
type,
124+
type: 'ISOFORM_EMBEDDED_VARIANT',
109125
trackData,
126+
variantData,
110127
},
111128
],
112129
},
@@ -124,5 +141,4 @@ And then in your HTML
124141

125142
## Notes
126143

127-
Can be run in ReactJS, VueJS, VanillaJS. Height is calculated on the fly for
128-
'global' isoform tracks.
144+
Can be run in ReactJS, VueJS, VanillaJS

eslint.config.mjs

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export default tseslint.config(
1313
'vite.config.ts',
1414
'vite-gh-pages.config.ts',
1515
'.storybook/*',
16+
'out/*',
1617
],
1718
},
1819
{

src/GMODVcfFetcher.ts

+10-11
Original file line numberDiff line numberDiff line change
@@ -37,27 +37,26 @@ export async function fetchTabixVcfData({
3737
parser,
3838
id: `${i++}`,
3939
})
40+
const info = f.get('INFO') as Record<string, string[]>
41+
// @ts-expect-error
4042
feats.push({
4143
id: f.get('ID'),
4244
reference_allele: f.get('REF'),
43-
// @ts-expect-error
44-
alt_allele: f.get('ALT'),
45+
alternative_alleles: { values: f.get('ALT') },
4546
name: f.get('name'),
4647
seqId: f.get('refName'),
4748
fmin: f.get('start'),
4849
fmax: f.get('end'),
4950
strand: 1,
5051
source: '',
51-
type: stripQuotes(f.get('INFO').soTerm[0]) ?? f.get('type'),
52+
type: stripQuotes(info.soTerm[0]) ?? f.get('type'),
5253
...Object.fromEntries(
53-
Object.entries(f.get('INFO') as Record<string, string[]>).map(
54-
([key, val]) => [
55-
key,
56-
{
57-
values: val.map(v => stripQuotes(v)),
58-
},
59-
],
60-
),
54+
Object.entries(info).map(([key, val]) => [
55+
key,
56+
{
57+
values: [JSON.stringify(val.map(v => stripQuotes(v)))],
58+
},
59+
]),
6160
),
6261
})
6362
},

src/main.ts

-1
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,6 @@ export class GenomeFeatureViewer {
190190

191191
if (track.type === TRACK_TYPE.ISOFORM_AND_VARIANT) {
192192
const isoformVariantTrack = new IsoformAndVariantTrack({
193-
region,
194193
viewer,
195194
height,
196195
width,

src/stories/util.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ export function createExampleApollo({
111111
showVariantLabel,
112112
variantFilter,
113113
isoformFilter,
114-
showVariants,
114+
showVariants = true,
115115
}: {
116116
locString: string
117117
genome: string

src/tracks/IsoformAndVariantTrack.ts

+5-12
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import {
2626

2727
import type { VariantFeature } from '../services/VariantService'
2828
import type { SimpleFeatureSerialized } from '../services/types'
29-
import type { Region } from '../types'
3029
import type { Selection } from 'd3'
3130

3231
export default class IsoformAndVariantTrack {
@@ -41,7 +40,6 @@ export default class IsoformAndVariantTrack {
4140
private transcriptTypes: string[]
4241
private variantTypes: string[]
4342
private binRatio: number
44-
private region: Region
4543
private showVariantLabel: boolean
4644

4745
constructor({
@@ -57,7 +55,6 @@ export default class IsoformAndVariantTrack {
5755
initialHighlight,
5856
trackData,
5957
variantData,
60-
region,
6158
}: {
6259
viewer: Selection<SVGGElement, unknown, HTMLElement | null, undefined>
6360
height: number
@@ -71,9 +68,7 @@ export default class IsoformAndVariantTrack {
7168
initialHighlight?: string[]
7269
trackData?: SimpleFeatureSerialized[]
7370
variantData?: VariantFeature[]
74-
region: Region
7571
}) {
76-
this.region = region
7772
this.trackData = trackData ?? []
7873
this.variantData = variantData ?? []
7974
this.viewer = viewer
@@ -89,22 +84,20 @@ export default class IsoformAndVariantTrack {
8984
}
9085

9186
DrawTrack() {
92-
const variantDataPre = this.variantData
93-
const trackData = this.trackData
9487
const isoformFilter = this.isoformFilter
95-
let isoformData = trackData
88+
let isoformData = this.trackData
9689
const initialHighlight = this.initialHighlight
9790
const variantData = this.filterVariantData(
98-
variantDataPre,
91+
this.variantData,
9992
this.variantFilter,
10093
)
10194
const viewer = this.viewer
10295
const width = this.width
10396
const binRatio = this.binRatio
10497
const distinctVariants = getVariantTrackPositions(variantData)
10598
const numVariantTracks = distinctVariants.length
106-
const source = trackData[0].source
107-
const chr = trackData[0].seqId
99+
const source = this.trackData[0].source
100+
const chr = this.trackData[0].seqId
108101
const MAX_ROWS = isoformFilter.length === 0 ? 9 : 30
109102

110103
const UTR_feats = ['UTR', 'five_prime_UTR', 'three_prime_UTR']
@@ -188,7 +181,7 @@ export default class IsoformAndVariantTrack {
188181
)
189182

190183
// We need to do all of the deletions first...
191-
const deletionBins = variantBins.filter(v => v.type == 'deletion')
184+
const deletionBins = variantBins.filter(v => v.type === 'deletion')
192185
const otherBins = variantBins.filter(v => v.type !== 'deletion')
193186

194187
const deletionSpace = [] as { fmin: number; fmax: number; row: number }[] // Array of array of objects for deletion layout.

0 commit comments

Comments
 (0)