Skip to content

Commit

Permalink
Local hub track order follows the hub file, bam track supported in lo…
Browse files Browse the repository at this point in the history
…cal track
  • Loading branch information
lidaof committed Jun 11, 2019
1 parent cf30efc commit af6a69a
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 133 deletions.
3 changes: 3 additions & 0 deletions Version.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
* fixed a bug that intra-region arcs are not displayed
* fixed an [Unable to preventDefault inside passive event listener](https://github.com/facebook/react/issues/6436) bug
* fixed the bug highlight region error when genomealign track is added, related to [#104](https://github.com/lidaof/eg-react/issues/104)
* fixed an issue that tracks order in local hub doesn't follow order in `hub.config.json` file
* local track supports BAM track now
* fixed a bug that categorytrack error when category not exists in hub file

## 48.4.6

Expand Down
101 changes: 19 additions & 82 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"@babel/preset-env": "^7.1.5",
"@babel/preset-react": "^7.0.0",
"@babel/preset-typescript": "^7.1.0",
"@gmod/bam": "^1.0.18",
"@gmod/bam": "^1.0.20",
"@storybook/addon-actions": "^3.3.15",
"@storybook/addon-links": "^3.3.15",
"@storybook/addons": "^3.3.15",
Expand Down Expand Up @@ -64,7 +64,7 @@
"enzyme-adapter-react-16": "^1.1.1",
"firebase": "^5.4.0",
"fuse.js": "^3.4.4",
"generic-filehandle": "^1.0.8",
"generic-filehandle": "^2.0.0",
"hic-straw": "^0.9.4",
"jest-image-snapshot": "^1.0.1",
"jquery": "^3.2.1",
Expand Down
70 changes: 37 additions & 33 deletions frontend/src/components/TrackUpload.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,22 @@ export class TrackUpload extends React.Component {
this.state = {
fileType: "bigWig",
selectedTabIndex: 0,
indexSuffix: '.tbi',
msg: '',
}
}

handleTypeChange = (event) => {
this.setState({fileType: event.target.value});
const fileType = event.target.value;
const indexSuffix = fileType === 'bam' ? '.bai' : '.tbi';
this.setState({fileType, indexSuffix});
}

handleFileUpload = async (event) => {
this.setState({msg: "Uploading track..."});
let tracks;
const fileList = Array.from(event.target.files);
const {indexSuffix} = this.state;
if (ONE_TRACK_FILE_LIST.includes(this.state.fileType.toLocaleLowerCase())) {
tracks = fileList.map(file =>
new TrackModel({
Expand All @@ -49,7 +55,7 @@ export class TrackUpload extends React.Component {
notify.show('Aborting, please only select 2 files, the track file and the index file', 'error', 5000);
return null;
}
if (fileList[0].name.replace(".tbi", "") !== fileList[1].name.replace(".tbi", "")) {
if (fileList[0].name.replace(indexSuffix, "") !== fileList[1].name.replace(indexSuffix, "")) {
notify.show('Aborting, track file not match index file', 'error', 5000);
return null;
}
Expand All @@ -63,74 +69,69 @@ export class TrackUpload extends React.Component {
})];
}
this.props.onTracksAdded(tracks);
this.setState({msg: 'Track added.'});
}

handleHubUpload = async (event) => {
this.setState({msg: 'Uploading hub...'});
const tracks = [];
const fileList = Array.from(event.target.files);
const hubFile = fileList.filter(f => f.name === 'hub.config.json');
const idxFiles = fileList.filter(f => f.name.endsWith('.tbi'));
const idxHash = {};
idxFiles.forEach(item => {
idxHash[item.name] = item;
})
if (hubFile.length !== 1) {
notify.show('Aborting, can not find `hub.config.json` file', 'error', 5000);
return null;
}
const hubContent = await readFileAsText(hubFile[0]);
const json = JSON5.parse(hubContent);
const trackTypes = {};
const trackNames = {};
const trackOptions = {};
json.forEach(item => {
trackTypes[item.filename] = item.type;
});
json.forEach(item => {
trackNames[item.filename] = item.name;
});
json.forEach(item => {
trackOptions[item.filename] = item.options;
const idxFiles = fileList.filter(f => f.name.endsWith('.tbi') || f.name.endsWith('.bai') );
const idxHash = {};
const fileHash = {};
idxFiles.forEach(item => {
idxHash[item.name] = item;
});
for (const file of fileList) {
const fileName = file.name;
// find a type in hub.config.json file
if (fileName.startsWith('.')) {
continue; // skip hidden files like .DS_Store
}
if (fileName.endsWith('.tbi')) {
if (fileName.endsWith('.tbi') || fileName.endsWith('.bai') ) {
continue; // skip index files
}
if (fileName === 'hub.config.json') {
continue;
}
if (trackTypes.hasOwnProperty(fileName) ) {
const trackType = trackTypes[fileName];
fileHash[fileName] = file;
};
const hubContent = await readFileAsText(hubFile[0]);
const json = JSON5.parse(hubContent);
for (const item of json) {
if (fileHash.hasOwnProperty(item.filename) ) {
const trackType = item.type.toLocaleLowerCase();
const indexSuffix = trackType === 'bam' ? '.bai' : '.tbi';
let track;
if (ONE_TRACK_FILE_LIST.includes(trackType)) {
track = new TrackModel({
type: trackType,
url: null,
fileObj: file,
name: trackNames[fileName] || fileName,
label: trackNames[fileName] || fileName,
fileObj: fileHash[item.filename],
name: item.name || item.filename,
label: item.label || item.name || item.filename,
files: null,
options: trackOptions[fileName] || {},
options: item.options || {},
});
} else {
track = new TrackModel({
type: trackType,
url: null,
fileObj: file,
name: trackNames[fileName] || fileName,
label: trackNames[fileName] || fileName,
files: [file, idxHash[fileName+'.tbi']],
options: trackOptions[fileName] || {},
fileObj: fileHash[item.filename],
name: item.name || item.filename,
label: item.label || item.name || item.filename,
files: [fileHash[item.filename], idxHash[item.filename+indexSuffix]],
options: item.options || {},
});
}
tracks.push(track);
} else {
notify.show('Skipping ' + file.name + ' not found in `hub.config.json`', 'warning', 3000);
notify.show('Skipping ' + item.filename + ' not found in `hub.config.json`', 'warning', 3000);
}
}
if (tracks.length > 0) {
Expand All @@ -139,6 +140,7 @@ export class TrackUpload extends React.Component {
notify.show('No local tracks could be found, please check your files and configuration', 'error', 5000);
return null;
}
this.setState({msg: 'Hub uploaded.'});
}

renderTrackUpload = () => {
Expand All @@ -161,6 +163,7 @@ export class TrackUpload extends React.Component {
<option value="refBed">refBed</option>
<option value="longrange">longrange</option>
<option value="callingcard">callingcard</option>
<option value="bam">BAM</option>
</optgroup>
</select>
</label>
Expand Down Expand Up @@ -203,6 +206,7 @@ export class TrackUpload extends React.Component {
<Tab label="Add Local Track">{this.renderTrackUpload()}</Tab>
<Tab label="Add Local Hub">{this.renderHubUpload()}</Tab>
</Tabs>
<div className="text-danger font-italic">{this.state.msg}</div>
</div>
);
}
Expand Down
6 changes: 5 additions & 1 deletion frontend/src/components/trackConfig/BamTrackConfig.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ export class BamTrackConfig extends AnnotationTrackConfig {
}

initDataSource() {
return new BamSource(this.trackModel.url);
if (this.trackModel.files.length > 0) {
return new BamSource(this.trackModel.files);
} else {
return new BamSource(this.trackModel.url);
}
}

formatData(data: any[]) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,19 +64,23 @@ class CategoricalTrackNoTooltip extends React.Component<CategoricalTrackProps> {
* @return {JSX.Element} element visualizing the feature
*/
renderAnnotation(placedGroup: PlacedFeatureGroup, y: number, isLastRow: boolean, index: number) {
return placedGroup.placedFeatures.map((placement, i) =>
<CategoricalAnnotation
const {category, height} = this.props.options;
return placedGroup.placedFeatures.map((placement, i) => {
const featureName = placement.feature.getName();
const color = category && category[featureName] ? category[featureName].color: 'blue';
return <CategoricalAnnotation
key={i}
feature={placement.feature}
xSpan={placement.xSpan}
y={0}
isMinimal={false}
color={this.props.options.category ?
this.props.options.category[placement.feature.getName()].color: 'blue'}
color={color}
onClick={this.renderTooltip}
category={this.props.options.category}
height={this.props.options.height}
/>
category={category}
height={height}
/>;
}

);
}

Expand Down
Loading

0 comments on commit af6a69a

Please sign in to comment.