Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "Get sequence" action to LGV rubber-band #1588

Merged
merged 77 commits into from
Jan 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
a163a75
added button to rubberband to get sequence
Dec 9, 2020
e3cb0c5
Merge branch 'master' of https://github.com/GMOD/jbrowse-components i…
Dec 10, 2020
3020e22
Merge branch 'master' of https://github.com/GMOD/jbrowse-components i…
Dec 11, 2020
c195b74
added button to the rubberband and calculate start and end bp selected
teresam856 Dec 11, 2020
86dd162
creating dialog for get sequence
teresam856 Dec 17, 2020
8e45d38
potential places to display the dialog
teresam856 Dec 17, 2020
f6587f5
changing params to feed to get sequence action
teresam856 Dec 18, 2020
c4ab3e6
progress on getting sequence string from sequence adapter
teresam856 Dec 18, 2020
9a0afaf
dialog connected to get sequence button
teresam856 Dec 21, 2020
a5ad205
controlling state with action from dialog, modified styles, changed i…
teresam856 Dec 22, 2020
1209518
cleanup after closing dialog
teresam856 Dec 22, 2020
bf2e5e6
set selected region seq back to undefined once dialog is closed
teresam856 Dec 24, 2020
88c40b6
fetch sequence from get sequence button, need to refactor fetch seque…
teresam856 Dec 24, 2020
9e3d3fc
Merge branch 'master' of https://github.com/GMOD/jbrowse-components i…
teresam856 Dec 24, 2020
bd64ea6
test that get sequence modal is active onclick of menu item
teresam856 Jan 2, 2021
aeb4309
modify test to open and close get seq dialog
teresam856 Jan 2, 2021
a7f5a64
modified tests and edit download fasta file button
teresam856 Jan 2, 2021
fd36b54
sequence now appears in dialog, TODO: tune get seq functionality and …
teresam856 Jan 4, 2021
ddb4270
add close button to dialog actions
teresam856 Jan 4, 2021
024a81b
getting sequence for multiple regions, need to format these into fast…
teresam856 Jan 5, 2021
9c4d033
added helper methods to format seq chunks into fasta and check size o…
teresam856 Jan 5, 2021
7df20fc
formating string blob into fasta, adding conditionals to disable get …
teresam856 Jan 6, 2021
ed4dd22
disabling buttons and handling errors in dialog, need to refine seque…
teresam856 Jan 7, 2021
b36cdf4
fix fasta formating for multiple sequences
teresam856 Jan 7, 2021
62b5b76
changes to dialog to disable clipboard button
teresam856 Jan 7, 2021
d512576
change text for get sequence button and dialog
teresam856 Jan 7, 2021
8b5b17f
added tests for helper methods
teresam856 Jan 8, 2021
5a1f12a
fix lint
teresam856 Jan 8, 2021
77e5347
merge master changes into 898_get_sequence
teresam856 Jan 8, 2021
418fc50
format
teresam856 Jan 8, 2021
894a621
fixed get selected regions, start offset by one
teresam856 Jan 10, 2021
5c53290
need to account for start offset of one
teresam856 Jan 10, 2021
2d8440f
fixed getSelectedRegions when offset is oob
teresam856 Jan 11, 2021
c6832a5
added loading circular progress, session warnings for file sizes and …
teresam856 Jan 11, 2021
6c7257a
lint
teresam856 Jan 11, 2021
cb14ac9
add clean up on mouse out
teresam856 Jan 11, 2021
886c551
fix lint and tests
teresam856 Jan 11, 2021
9ee8669
Merge branch 'master' of https://github.com/GMOD/jbrowse-components i…
teresam856 Jan 11, 2021
a282b7b
starting to migrate to rpc call
teresam856 Jan 11, 2021
4ba2ea7
Merge branch 'master' of https://github.com/GMOD/jbrowse-components i…
teresam856 Jan 11, 2021
1dba702
returned sequence now matches samtools results
teresam856 Jan 11, 2021
fd9a794
selected bp typography innacuracy fixed
teresam856 Jan 11, 2021
6590b04
rearranging flow of opening dialog, adding warning about size of sele…
teresam856 Jan 12, 2021
68737bf
fixed selecting entirely over oob region
teresam856 Jan 12, 2021
27ce514
core rpc method for obtaining features from mult displayedRegions
teresam856 Jan 12, 2021
dfb28bd
removed rpc method
teresam856 Jan 12, 2021
09dc6f0
working state before refactoring
teresam856 Jan 12, 2021
b472510
removed unsused imports
teresam856 Jan 12, 2021
39613f0
starting refactor and migration of fetch seq to dialog component
teresam856 Jan 13, 2021
549d41e
moved formatting functions into core
teresam856 Jan 13, 2021
c578a53
refactor, lint, edit tests
teresam856 Jan 13, 2021
28e19d7
remove unsused variables
teresam856 Jan 13, 2021
85b43e4
remove unused imports
teresam856 Jan 13, 2021
39655cf
Merge branch 'master' of https://github.com/GMOD/jbrowse-components i…
teresam856 Jan 13, 2021
9245393
update snapshots
teresam856 Jan 13, 2021
e58ca79
attempt to fix lint errors
teresam856 Jan 13, 2021
fd76f87
fixed tests and removed comments
teresam856 Jan 13, 2021
e04198a
fix lint and add fasta formatting tests
teresam856 Jan 13, 2021
653bfbb
added more tests
teresam856 Jan 14, 2021
2824d5e
refactored dialog content
teresam856 Jan 14, 2021
cd2e784
attempting to fix possibly undefined var, todo refactor get selectedR…
teresam856 Jan 14, 2021
1eaeb55
fix type check
teresam856 Jan 14, 2021
b308d53
Add a method for using dynamicBlocks for the "Get sequence" dialog
cmdcolin Jan 14, 2021
db18604
Use monospace font
cmdcolin Jan 14, 2021
65d23d5
Fixup tests
cmdcolin Jan 14, 2021
624cde6
fix prettier
teresam856 Jan 14, 2021
bc32de7
Simplify the fasta formatter
cmdcolin Jan 14, 2021
dc846ed
Fix lint
cmdcolin Jan 14, 2021
d57aeeb
Avoid a useState for disabled state
cmdcolin Jan 14, 2021
6cd0f2d
Couple unneeded templates
cmdcolin Jan 14, 2021
f5c6858
Remove some more useState
cmdcolin Jan 14, 2021
a93ce1e
Helper function for sequence too large
cmdcolin Jan 14, 2021
c19382e
Add a CoreGetFeatures rpc call
cmdcolin Jan 14, 2021
f9d69c3
Merge remote-tracking branch 'origin/master' into 898_get_sequence
cmdcolin Jan 14, 2021
8c16324
Remove some state for a computed
cmdcolin Jan 14, 2021
98c96fd
Move fetchSequence function out of lgv model
cmdcolin Jan 14, 2021
111b2ed
Fix test
cmdcolin Jan 14, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions packages/core/rpc/coreRpcMethods.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { toArray } from 'rxjs/operators'
import {
freeAdapterResources,
getAdapter,
Expand Down Expand Up @@ -57,6 +58,31 @@ export class CoreGetFileInfo extends RpcMethodType {
}
}

export class CoreGetFeatures extends RpcMethodType {
name = 'CoreGetFeatures'

async execute(args: {
sessionId: string
signal: RemoteAbortSignal
region: Region
adapterConfig: {}
}) {
const deserializedArgs = await this.deserializeArguments(args)
const { sessionId, adapterConfig, region } = deserializedArgs
const { dataAdapter } = getAdapter(
this.pluginManager,
sessionId,
adapterConfig,
)
if (dataAdapter instanceof BaseFeatureDataAdapter) {
const ret = dataAdapter.getFeatures(region)
const feats = await ret.pipe(toArray()).toPromise()
return JSON.parse(JSON.stringify(feats))
}
return []
}
}

/**
* free up any resources (e.g. cached adapter objects)
* that are only associated with the given track ID.
Expand Down
34 changes: 34 additions & 0 deletions packages/core/util/Base1DViewModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,40 @@ const Base1DView = types
self.features = features
},

zoomToDisplayedRegions(
leftPx: BpOffset | undefined,
rightPx: BpOffset | undefined,
) {
if (leftPx === undefined || rightPx === undefined) return

const singleRefSeq =
leftPx.refName === rightPx.refName && leftPx.index === rightPx.index
// zooming into one displayed Region
if (
(singleRefSeq && rightPx.offset < leftPx.offset) ||
leftPx.index > rightPx.index
) {
;[leftPx, rightPx] = [rightPx, leftPx]
}
const startOffset = {
start: leftPx.start,
end: leftPx.end,
index: leftPx.index,
offset: leftPx.offset,
}
const endOffset = {
start: rightPx.start,
end: rightPx.end,
index: rightPx.index,
offset: rightPx.offset,
}
if (startOffset && endOffset) {
this.moveTo(startOffset, endOffset)
} else {
throw new Error('regions not found')
}
},

// this makes a zoomed out view that shows all displayedRegions
// that makes the overview bar square with the scale bar
showAllRegions() {
Expand Down
18 changes: 18 additions & 0 deletions packages/core/util/__snapshots__/formatFastaStrings.test.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`formatting seqChunks and strings into Fasta format formats headers and sequence 1`] = `
">ctgA:1-10
cattgttgcg
>ctgB:1-81
cattgttgcggagttgaacaACGGCATTAGGAACACTTCCGTCTCtcacttttatacgattatgattggttctttagcct
t"
`;

exports[`formatting seqChunks and strings into Fasta format sequence length is 80 characters 1`] = `"cattgttgcggagttgaacaACGGCATTAGGAACACTTCCGTCTCtcacttttatacgattatgattggttctttagcct"`;

exports[`formatting seqChunks and strings into Fasta format sequence length is less than 80 characters 1`] = `"cattgttgcg"`;

exports[`formatting seqChunks and strings into Fasta format sequence length is more than 80 characters 1`] = `
"cattgttgcggagttgaacaACGGCATTAGGAACACTTCCGTCTCtcacttttatacgattatgattggttctttagcct
t"
`;
36 changes: 36 additions & 0 deletions packages/core/util/formatFastaStrings.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { formatSeqFasta, formatFastaLines } from './formatFastaStrings'

describe('formatting seqChunks and strings into Fasta format', () => {
const small = 'cattgttgcg'
const medium =
'cattgttgcggagttgaacaACGGCATTAGGAACACTTCCGTCTCtcacttttatacgattatgattggttctttagcct'
const large =
'cattgttgcggagttgaacaACGGCATTAGGAACACTTCCGTCTCtcacttttatacgattatgattggttctttagcctt'
it('sequence length is less than 80 characters', () => {
const formattedSmallFasta = formatFastaLines(small)
expect(formattedSmallFasta).toMatchSnapshot()
})
it('sequence length is 80 characters', () => {
const formattedMediumFasta = formatFastaLines(medium)
expect(formattedMediumFasta).toMatchSnapshot()
})
it('sequence length is more than 80 characters', () => {
const formattedLargeFasta = formatFastaLines(large)
expect(formattedLargeFasta).toMatchSnapshot()
})
it('formats headers and sequence', () => {
const chunks = [
{ header: 'ctgA:1-10', seq: small },
{ header: 'ctgB:1-81', seq: large },
]
const formattedFastaFile = formatSeqFasta(chunks)
/*
>ctgA:1-10
cattgttgcg
>ctgB:1-81
cattgttgcggagttgaacaACGGCATTAGGAACACTTCCGTCTCtcacttttatacgattatgattggttctttagcct
t
*/
expect(formattedFastaFile).toMatchSnapshot()
})
})
25 changes: 25 additions & 0 deletions packages/core/util/formatFastaStrings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export interface SeqChunk {
header: string
seq: string
}
/**
* Returns sequence with new line every 80 characters
* ref https://stackoverflow.com/a/51506718/2129219
*
* @param seqString - string
* @returns formated sequence string
*/
export function formatFastaLines(seqString: string) {
return seqString.replace(/(.{1,80})/g, '$1\n').trimEnd()
}
/**
* Formats the sequences chunks into Fasta format
*
* @param chunks - array of seq chunks of the form `{ header: string, seq: string }`
* @returns formatted sequence in fasta format
*/
export function formatSeqFasta(chunks: SeqChunk[]) {
return chunks
.map(chunk => `>${chunk.header}\n${formatFastaLines(chunk.seq)}`)
.join('\n')
}
2 changes: 2 additions & 0 deletions plugins/linear-genome-view/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
"@material-ui/icons": "^4.9.1",
"clone": "^2.1.2",
"clsx": "^1.0.4",
"copy-to-clipboard": "^3.3.1",
"file-saver": "^2.0.0",
"is-object": "^1.0.1",
"json-stable-stringify": "^1.0.1",
"normalize-wheel": "^1.0.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import TracksContainer from './TracksContainer'
import ImportForm from './ImportForm'
import MiniControls from './MiniControls'
import AboutDialog from './AboutDialog'
import SequenceDialog from './SequenceDialog'

type LGV = Instance<LinearGenomeViewStateModel>

Expand Down Expand Up @@ -63,6 +64,14 @@ const LinearGenomeView = observer((props: { model: LGV }) => {
}
/>
) : null}
{model.isSeqDialogDisplayed ? (
<SequenceDialog
model={model}
handleClose={() => {
model.setOffsets(undefined, undefined)
}}
/>
) : null}
{!hideHeader ? (
<Header model={model} />
) : (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import React, { useRef, useEffect, useState } from 'react'
import ReactPropTypes from 'prop-types'
import { observer, PropTypes as MobxPropTypes } from 'mobx-react'
import { Instance } from 'mobx-state-tree'
// material ui
import { fade } from '@material-ui/core/styles/colorManipulator'
import MenuOpenIcon from '@material-ui/icons/MenuOpen'
import { Menu } from '@jbrowse/core/ui'
import { stringify } from '@jbrowse/core/util'
import Popover from '@material-ui/core/Popover'
import { makeStyles } from '@material-ui/core/styles'
import { fade } from '@material-ui/core/styles/colorManipulator'
import Popover from '@material-ui/core/Popover'
import Tooltip from '@material-ui/core/Tooltip'
import Typography from '@material-ui/core/Typography'
import ZoomInIcon from '@material-ui/icons/ZoomIn'
import { observer, PropTypes as MobxPropTypes } from 'mobx-react'
import { Instance } from 'mobx-state-tree'
import ReactPropTypes from 'prop-types'
import React, { useRef, useEffect, useState } from 'react'

import { stringify } from '@jbrowse/core/util'
import { LinearGenomeViewStateModel } from '..'

type LGV = Instance<LinearGenomeViewStateModel>
Expand Down Expand Up @@ -135,7 +138,7 @@ function RubberBand({
) {
handleClose()
}
})
}, [mouseDragging, currentX, startX, model.bpPerPx])

function mouseDown(event: React.MouseEvent<HTMLDivElement>) {
event.preventDefault()
Expand All @@ -154,6 +157,7 @@ function RubberBand({

function mouseOut() {
setGuideX(undefined)
model.setOffsets(undefined, undefined)
}

function zoomToRegion() {
Expand All @@ -170,6 +174,21 @@ function RubberBand({
model.moveTo(leftOffset, rightOffset)
}

function getSequence() {
if (startX === undefined || anchorPosition === undefined) {
return
}
let leftPx = startX
let rightPx = anchorPosition.left
// handles clicking and draging to the left
if (rightPx < leftPx) {
;[leftPx, rightPx] = [rightPx, leftPx]
}
const leftOffset = model.pxToBp(leftPx)
const rightOffset = model.pxToBp(rightPx)
model.setOffsets(leftOffset, rightOffset)
}

function handleClose() {
setAnchorPosition(undefined)
setStartX(undefined)
Expand All @@ -192,6 +211,18 @@ function RubberBand({
handleClose()
},
},
{
label: 'Get sequence',
disabled:
currentX !== undefined &&
startX !== undefined &&
Math.abs(currentX - startX) * model.bpPerPx > 500_000_000,
icon: MenuOpenIcon,
onClick: () => {
getSequence()
handleClose()
},
},
]

if (startX === undefined) {
Expand Down Expand Up @@ -221,8 +252,7 @@ function RubberBand({
const width = Math.abs(right - startX)
const leftBpOffset = model.pxToBp(left)
const rightBpOffset = model.pxToBp(left + width)
const numOfBpSelected = Math.round(width * model.bpPerPx)

const numOfBpSelected = Math.ceil(width * model.bpPerPx)
return (
<>
{rubberBandRef.current ? (
Expand Down
Loading