Skip to content

Commit

Permalink
Merge pull request #392 from vgteam/lancet-demo
Browse files Browse the repository at this point in the history
Left-right button and region description integration
  • Loading branch information
adamnovak authored Feb 14, 2024
2 parents ca4f248 + 523a249 commit f4ab3c2
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 51 deletions.
17 changes: 13 additions & 4 deletions scripts/prepare_chunks.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,21 @@ set -e
function usage() {
echo >&2 "${0}: Extract graph and read chunks for a region, producing a referencing line for a BED file on standard output"
echo >&2
echo >&2 "Usage: ${0} -x mygraph.xg [-h mygraph.gbwt] -r chr1:1-100 [-d 'Description of region'] [-n 123 [-n 456]] -o chunk-chr1-1-100 [-g mygam1.gam [-g mygam2.gam ...]] >> regions.bed"
echo >&2 "Usage: ${0} -x mygraph.xg [-h mygraph.gbwt] -r chr1:1-100 [-d 'Description of region'] [-n 123 [-n 456]] -o chunk-chr1-1-100 [-g mygam1.gam [-p '{\"mainPalette\": \"blues\", \"auxPalette\": \"reds\"}'] [-g mygam2.gam [-p ...] ...]] >> regions.bed"
exit 1
}

GAM_FILES=()
GAM_PALETTES=()
NODE_COLORS=()

while getopts x:h:g:r:o:d:n: flag
while getopts x:h:g:p:r:o:d:n: flag
do
case "${flag}" in
x) GRAPH_FILE=${OPTARG};;
h) HAPLOTYPE_FILE=${OPTARG};;
g) GAM_FILES+=("$OPTARG");;
p) GAM_PALETTES+=("$OPTARG");;
r) REGION=${OPTARG};;
o) OUTDIR=${OPTARG};;
d) DESC="${OPTARG}";;
Expand Down Expand Up @@ -84,13 +87,19 @@ fi

# construct track JSON for each gam file
echo >&2 "Gam Files:"
READ_PALETTE="$(cat "$(dirname ${BASH_SOURCE[0]})/../src/config.json" | jq '.defaultReadColorPalette')"
GAM_NUM=0
DEFAULT_READ_PALETTE="$(cat "$(dirname ${BASH_SOURCE[0]})/../src/config.json" | jq '.defaultReadColorPalette')"
echo >&2 "Read Palette: $READ_PALETTE"
for GAM_FILE in "${GAM_FILES[@]}"; do
GAM_PALETTE="${GAM_PALETTES[${GAM_NUM}]}"
if [[ -z "${GAM_PALETTE}" ]] ; then
GAM_PALETTE="${DEFAULT_READ_PALETTE}"
fi
GAM_FILE_PATH=$(realpath --relative-to $(dirname ${BASH_SOURCE[0]})/../ $GAM_FILE)
echo >&2 " - $GAM_FILE_PATH"
jq -n --arg trackFile "${GAM_FILE_PATH}" --arg trackType "read" --argjson trackColorSettings "$READ_PALETTE" '$ARGS.named' >> $OUTDIR/temp.json
jq -n --arg trackFile "${GAM_FILE_PATH}" --arg trackType "read" --argjson trackColorSettings "$GAM_PALETTE" '$ARGS.named' >> $OUTDIR/temp.json
vg_chunk_params+=(-a $GAM_FILE)
GAM_NUM=$((GAM_NUM + 1))
done

# put all tracks objects into an array
Expand Down
16 changes: 11 additions & 5 deletions scripts/prepare_local_chunk.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,20 @@ set -e
function usage() {
echo >&2 "${0}: Prepare a tube map chunk and BED line on standard output from a pre-made subgraph. Only supports paths, not haplotypes."
echo >&2
echo >&2 "Usage: ${0} -x subgraph.xg -r chr1:1-100 [-d 'Description of region'] [-n 123 [-n 456]] -o chunk-chr1-1-100 [-g mygam1.gam [-g mygam2.gam ...]] >> regions.bed"
echo >&2 "Usage: ${0} -x subgraph.xg -r chr1:1-100 [-d 'Description of region'] [-n 123 [-n 456]] -o chunk-chr1-1-100 [-g mygam1.gam [-p '{\"mainPalette\": \"blues\", \"auxPalette\": \"reds\"}'] [-g mygam2.gam [-p ...] ...]] >> regions.bed"
exit 1
}

GAM_FILES=()
GAM_PALETTES=()
NODE_COLORS=()

while getopts x:g:r:o:d:n: flag
while getopts x:g:p:r:o:d:n: flag
do
case "${flag}" in
x) GRAPH_FILE=${OPTARG};;
g) GAM_FILES+=("$OPTARG");;
p) GAM_PALETTES+=("$OPTARG");;
r) REGION=${OPTARG};;
o) OUTDIR=${OPTARG};;
d) DESC="${OPTARG}";;
Expand Down Expand Up @@ -82,13 +85,16 @@ printf "${REGION_CONTIG}\t${REGION_START}\t${REGION_END}" > $OUTDIR/regions.tsv

echo >&2 "Gam Files:"
GAM_NUM=0
READ_PALETTE="$(cat "$(dirname ${BASH_SOURCE[0]})/../src/config.json" | jq '.defaultReadColorPalette')"
DEFAULT_READ_PALETTE="$(cat "$(dirname ${BASH_SOURCE[0]})/../src/config.json" | jq '.defaultReadColorPalette')"
for GAM_FILE in "${GAM_FILES[@]}"; do
echo >&2 " - $GAM_FILE"

GAM_PALETTE="${GAM_PALETTES[${GAM_NUM}]}"
if [[ -z "${GAM_PALETTE}" ]] ; then
GAM_PALETTE="${DEFAULT_READ_PALETTE}"
fi
GAM_FILE_PATH=$(realpath --relative-to $(dirname ${BASH_SOURCE[0]})/../ $GAM_FILE)
# construct track JSON for each gam file
jq -n --arg trackFile "${GAM_FILE_PATH}" --arg trackType "read" --argjson trackColorSettings "$READ_PALETTE" '$ARGS.named' >> $OUTDIR/temp.json
jq -n --arg trackFile "${GAM_FILE_PATH}" --arg trackType "read" --argjson trackColorSettings "$GAM_PALETTE" '$ARGS.named' >> $OUTDIR/temp.json
# Work out a chunk-internal GAM name with the same leading numbering vg chunk uses
if [[ "${GAM_NUM}" == "0" ]] ; then
GAM_LEADER="chunk"
Expand Down
68 changes: 29 additions & 39 deletions src/components/HeaderForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -574,48 +574,42 @@ class HeaderForm extends Component {
}
};

getRegionCoords = (desc) => {
getRegionCoordsByDesc = (desc) => {
// Given a region description (string), return the actual corresponding coordinates
// Returns null if there is no corresponding coords
// i: number that corresponds to record
// Find index of given description in regionInfo
if (!this.state.regionInfo["desc"]) {
return null;
}
const i = this.state.regionInfo["desc"].findIndex((d) => d === desc);
if (i === -1)
// Not found
return null;
// Find corresponding chr, start, and end
const regionChr = this.state.regionInfo["chr"][i];
const regionStart = this.state.regionInfo["start"][i];
const regionEnd = this.state.regionInfo["end"][i];
// Combine chr, start, and end to get region string
const regionString = regionChr.concat(":", regionStart, "-", regionEnd);
return regionString;
return regionStringFromRegionIndex(i, this.state.regionInfo);
};



// Get the description of the region with the given coordinates, or null if no such region exists.
getRegionDescByCoords = (coords) => {
for (let i = 0; i < this.state.regionInfo["chr"]?.length ?? 0; i++) {
if (coords === regionStringFromRegionIndex(i, this.state.regionInfo)) {
return this.state.regionInfo["desc"]?.[i] ?? null;
}
}
return null;
}

// In addition to a new region value, also takes tracks and chunk associated with the region
// Update current track if the new tracks are valid
// Otherwise check if the current bed file is a url, and if tracks can be fetched from said url
// Adopt a new region
// Update the region description
// Update current tracks if the stored tracks for the region are valid
// Otherwise check if the current bed file has associated tracks
// Tracks remain unchanged if neither condition is met
handleRegionChange = async (value, desc) => {
// Update region description
this.setState({ desc: desc });

// After user selects a region name or coordinates,
// update path, region, and associated tracks(if applicable)

// Update path and region
let coords = value;
if (
this.state.regionInfo.hasOwnProperty("desc") &&
this.state.regionInfo["desc"].includes(value)
) {
// Just a description was selected, get coords
coords = this.getRegionCoords(value);
}
this.setState({ region: coords });
handleRegionChange = async (coords) => {
// Update region coords and description
this.setState({
region: coords,
desc: this.getRegionDescByCoords(coords),
});

let coordsToMetaData = {};

Expand Down Expand Up @@ -694,7 +688,7 @@ class HeaderForm extends Component {

// Budge the region left or right by the given negative or positive fraction
// of its width.
budgeRegion(fraction) {
async budgeRegion(fraction) {
let parsedRegion = parseRegion(this.state.region);

if (parsedRegion.distance !== undefined) {
Expand All @@ -709,28 +703,24 @@ class HeaderForm extends Component {
parsedRegion.start = Math.max(0, Math.round(parsedRegion.start + shift));
parsedRegion.end = Math.max(0, Math.round(parsedRegion.end + shift));
}


await this.handleRegionChange(stringifyRegion(parsedRegion));
this.setState(
(state) => ({
region: stringifyRegion(parsedRegion),
}),
() => this.handleGoButton()
);
}


/* Offset the region left or right by the given negative or positive fraction*/
// offset: +1 or -1
jumpRegion(offset) {
async jumpRegion(offset) {
let regionIndex = determineRegionIndex(this.state.region, this.state.regionInfo) ?? 0;
if ((offset === -1 && this.canGoLeft(regionIndex)) || (offset === 1 && this.canGoRight(regionIndex))){
regionIndex += offset;
}
let regionString = regionStringFromRegionIndex(regionIndex, this.state.regionInfo);
await this.handleRegionChange(regionString);
this.setState(
(state) => ({
region: regionString,
}),
() => this.handleGoButton()
);
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/RegionInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export const RegionInput = ({
if (regionObject) {
regionValue = regionObject.value;
}
handleRegionChange(regionValue, regionToDesc.get(regionValue));
handleRegionChange(regionValue);
}}
options={displayRegions}
renderInput={(params) => (
Expand Down
3 changes: 1 addition & 2 deletions src/components/RegionInput.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ test("it calls handleRegionChange when region is changed with new region", async
await userEvent.type(input, NEW_REGION);

expect(handleRegionChangeMock).toHaveBeenLastCalledWith(
NEW_REGION,
undefined
NEW_REGION
);
});

0 comments on commit f4ab3c2

Please sign in to comment.