Skip to content

Commit 07394b4

Browse files
committed
Support loading track hubs by GCF or GCA identifier
1 parent f0bd627 commit 07394b4

17 files changed

+155
-55
lines changed

Diff for: src/main/java/org/broad/igv/batch/CommandListener.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,9 @@ private String processGet(String command, Map<String, String> params, CommandExe
433433
IGV.getInstance().goToLocus(locus);
434434
} else if (command.equals("/execute")) {
435435
String param = StringUtils.decodeURL(params.get("command"));
436-
return cmdExe.execute(param);
436+
result = cmdExe.execute(param);
437+
} else if (command.equals("/ping")) {
438+
result = "OK";
437439
} else {
438440
return ("ERROR Unknown command: " + command);
439441
}

Diff for: src/main/java/org/broad/igv/feature/genome/load/ChromAliasParser.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77

88
import java.io.BufferedReader;
99
import java.io.IOException;
10-
import java.util.*;
10+
import java.util.ArrayList;
11+
import java.util.List;
1112

1213
public class ChromAliasParser {
1314

Diff for: src/main/java/org/broad/igv/feature/genome/load/ChromSizesParser.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,10 @@
2525

2626
package org.broad.igv.feature.genome.load;
2727

28-
import org.broad.igv.logging.*;
2928
import org.broad.igv.Globals;
3029
import org.broad.igv.feature.Chromosome;
30+
import org.broad.igv.logging.LogManager;
31+
import org.broad.igv.logging.Logger;
3132
import org.broad.igv.util.ParsingUtils;
3233

3334
import java.io.BufferedReader;

Diff for: src/main/java/org/broad/igv/feature/genome/load/DotGenomeLoader.java

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
package org.broad.igv.feature.genome.load;
22

33
import htsjdk.tribble.Feature;
4-
import org.broad.igv.feature.genome.ChromAliasDefaults;
5-
import org.broad.igv.feature.genome.ChromAliasFile;
6-
import org.broad.igv.logging.*;
74
import org.broad.igv.feature.*;
85
import org.broad.igv.feature.genome.Genome;
96
import org.broad.igv.feature.genome.Sequence;
107
import org.broad.igv.feature.genome.fasta.FastaBlockCompressedSequence;
118
import org.broad.igv.feature.genome.fasta.FastaIndexedSequence;
129
import org.broad.igv.feature.gff.GFFFeatureSource;
10+
import org.broad.igv.logging.LogManager;
11+
import org.broad.igv.logging.Logger;
1312
import org.broad.igv.track.FeatureCollectionSource;
1413
import org.broad.igv.track.FeatureTrack;
1514
import org.broad.igv.track.TrackProperties;
@@ -19,7 +18,6 @@
1918

2019
import java.awt.*;
2120
import java.io.*;
22-
import java.util.Collection;
2321
import java.util.List;
2422

2523

Diff for: src/main/java/org/broad/igv/feature/genome/load/FastaGenomeLoader.java

-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
package org.broad.igv.feature.genome.load;
22

33
import org.broad.igv.feature.genome.Genome;
4-
import org.broad.igv.feature.genome.Sequence;
5-
import org.broad.igv.feature.genome.SequenceWrapper;
6-
import org.broad.igv.feature.genome.fasta.FastaBlockCompressedSequence;
7-
import org.broad.igv.feature.genome.fasta.FastaIndexedSequence;
84
import org.broad.igv.feature.genome.fasta.FastaUtils;
95
import org.broad.igv.util.FileUtils;
106
import org.broad.igv.util.HttpUtils;

Diff for: src/main/java/org/broad/igv/feature/genome/load/GenbankParser.java

+7-3
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,15 @@
2525

2626
package org.broad.igv.feature.genome.load;
2727

28-
import org.broad.igv.logging.*;
28+
import htsjdk.tribble.Feature;
2929
import org.broad.igv.Globals;
30-
import org.broad.igv.feature.*;
30+
import org.broad.igv.feature.BasicFeature;
31+
import org.broad.igv.feature.Exon;
32+
import org.broad.igv.feature.FeatureUtils;
33+
import org.broad.igv.feature.Strand;
34+
import org.broad.igv.logging.LogManager;
35+
import org.broad.igv.logging.Logger;
3136
import org.broad.igv.util.ParsingUtils;
32-
import htsjdk.tribble.Feature;
3337
import org.broad.igv.util.StringUtils;
3438

3539
import java.io.*;

Diff for: src/main/java/org/broad/igv/feature/genome/load/GenomeConfig.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package org.broad.igv.feature.genome.load;
22

3+
import com.google.gson.Gson;
34
import org.broad.igv.feature.Cytoband;
4-
import org.broad.igv.feature.genome.ChromAliasFile;
55
import org.broad.igv.feature.genome.Sequence;
66

77
import java.util.LinkedHashMap;
@@ -53,4 +53,9 @@ public class GenomeConfig {
5353
public Sequence sequence;
5454
public LinkedHashMap<String, List<Cytoband>> cytobands;
5555
public List<List<String>> chromAliases;
56+
57+
public static GenomeConfig fromJson(String json) {
58+
return (new Gson()).fromJson(json, GenomeConfig.class);
59+
60+
}
5661
}

Diff for: src/main/java/org/broad/igv/feature/genome/load/GenomeDescriptor.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525

2626
package org.broad.igv.feature.genome.load;
2727

28-
import org.broad.igv.logging.*;
28+
import org.broad.igv.logging.LogManager;
29+
import org.broad.igv.logging.Logger;
2930
import org.broad.igv.util.HttpUtils;
3031

3132
import java.io.*;

Diff for: src/main/java/org/broad/igv/feature/genome/load/GenomeLoader.java

+11-5
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,25 @@
11
package org.broad.igv.feature.genome.load;
22

3-
import org.broad.igv.logging.*;
43
import org.broad.igv.DirectoryManager;
54
import org.broad.igv.Globals;
6-
import org.broad.igv.feature.*;
7-
import org.broad.igv.feature.genome.*;
5+
import org.broad.igv.feature.FeatureDB;
6+
import org.broad.igv.feature.genome.Genome;
7+
import org.broad.igv.feature.genome.GenomeException;
8+
import org.broad.igv.feature.genome.GenomeManager;
9+
import org.broad.igv.logging.LogManager;
10+
import org.broad.igv.logging.Logger;
811
import org.broad.igv.track.FeatureCollectionSource;
912
import org.broad.igv.track.FeatureTrack;
1013
import org.broad.igv.ui.util.MessageUtils;
11-
import org.broad.igv.util.*;
14+
import org.broad.igv.util.FileUtils;
15+
import org.broad.igv.util.HttpUtils;
16+
import org.broad.igv.util.Utilities;
1217

1318
import java.awt.*;
1419
import java.io.*;
20+
import java.util.HashMap;
1521
import java.util.List;
16-
import java.util.*;
22+
import java.util.Map;
1723

1824
/**
1925
* Collection of static load methods for various genome definition formats

Diff for: src/main/java/org/broad/igv/feature/genome/load/GenomeObjectLoader.java

+2-15
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,10 @@
11
package org.broad.igv.feature.genome.load;
22

3-
import org.broad.igv.feature.CytoBandFileParser;
4-
import org.broad.igv.feature.genome.*;
5-
import org.broad.igv.feature.genome.fasta.FastaBlockCompressedSequence;
6-
import org.broad.igv.feature.genome.fasta.FastaIndexedSequence;
3+
import org.broad.igv.feature.genome.Genome;
74
import org.broad.igv.logging.LogManager;
85
import org.broad.igv.logging.Logger;
9-
import org.broad.igv.track.Track;
10-
import org.broad.igv.track.TrackProperties;
11-
import org.broad.igv.ui.color.ColorUtilities;
12-
import org.broad.igv.util.FileUtils;
13-
import org.broad.igv.util.ParsingUtils;
14-
import org.broad.igv.util.ResourceLocator;
15-
16-
import java.io.BufferedReader;
6+
177
import java.io.IOException;
18-
import java.util.ArrayList;
19-
import java.util.Arrays;
20-
import java.util.List;
218

229
public class GenomeObjectLoader extends GenomeLoader {
2310

Diff for: src/main/java/org/broad/igv/feature/genome/load/HubGenomeLoader.java

+14
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,20 @@ public static boolean isHubURL(String obj) {
1717
return obj.endsWith("/hub.txt");
1818
}
1919

20+
public static String convertToHubURL(String accension) {
21+
//https://hgdownload.soe.ucsc.edu/hubs/GCF/016/808/095/GCF_016808095.1/
22+
//https://hgdownload.soe.ucsc.edu/hubs/GCA/028/534/965/GCA_028534965.1/
23+
if(accension.startsWith("GCF") || accension.startsWith("GCA") && accension.length() >= 13) {
24+
String prefix = accension.substring(0, 3);
25+
String n1 = accension.substring(4, 7);
26+
String n2 = accension.substring(7, 10);
27+
String n3 = accension.substring(10, 13);
28+
return "https://hgdownload.soe.ucsc.edu/hubs/" + prefix + "/" + n1 + "/" + n2 + "/" + n3 + "/" + accension + "/hub.txt";
29+
} else {
30+
return null;
31+
}
32+
}
33+
2034
@Override
2135
public Genome loadGenome() throws IOException {
2236

Diff for: src/main/java/org/broad/igv/feature/genome/load/JsonGenomeLoader.java

+10-16
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,26 @@
11
package org.broad.igv.feature.genome.load;
22

3-
import com.google.gson.*;
3+
import com.google.gson.Gson;
4+
import com.google.gson.JsonObject;
5+
import com.google.gson.JsonParser;
46
import htsjdk.tribble.CloseableTribbleIterator;
57
import htsjdk.tribble.Feature;
68
import htsjdk.tribble.FeatureReader;
7-
import org.broad.igv.feature.genome.ChromAliasBB;
8-
import org.broad.igv.feature.genome.ChromAliasDefaults;
9-
import org.broad.igv.feature.genome.ChromAliasFile;
10-
import org.broad.igv.feature.IGVNamedFeature;
11-
import org.broad.igv.logging.*;
12-
import org.broad.igv.Globals;
13-
import org.broad.igv.feature.CytoBandFileParser;
149
import org.broad.igv.feature.FeatureDB;
10+
import org.broad.igv.feature.IGVNamedFeature;
1511
import org.broad.igv.feature.genome.Genome;
16-
import org.broad.igv.feature.genome.fasta.FastaBlockCompressedSequence;
17-
import org.broad.igv.feature.genome.fasta.FastaIndexedSequence;
18-
import org.broad.igv.track.Track;
19-
import org.broad.igv.track.TrackProperties;
12+
import org.broad.igv.logging.LogManager;
13+
import org.broad.igv.logging.Logger;
2014
import org.broad.igv.track.TribbleFeatureSource;
21-
import org.broad.igv.ui.color.ColorUtilities;
2215
import org.broad.igv.util.FileUtils;
2316
import org.broad.igv.util.ParsingUtils;
2417
import org.broad.igv.util.ResourceLocator;
25-
import org.broad.igv.util.liftover.Liftover;
2618

2719
import java.io.BufferedReader;
2820
import java.io.IOException;
29-
import java.util.*;
21+
import java.util.Arrays;
22+
import java.util.List;
23+
import java.util.Map;
3024

3125
public class JsonGenomeLoader extends GenomeLoader {
3226

@@ -51,7 +45,7 @@ public Genome loadGenome() throws IOException {
5145
jsonString = fixChromosomeOrder(jsonString);
5246
}
5347

54-
GenomeConfig genomeConfig = (new Gson()).fromJson(jsonString, GenomeConfig.class);
48+
GenomeConfig genomeConfig = GenomeConfig.fromJson (jsonString);
5549

5650
fixPaths(genomeConfig);
5751

Diff for: src/main/java/org/broad/igv/ui/IGVMenuBar.java

+4
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,10 @@ JMenu createFileMenu() {
288288
menuAction.setToolTipText(UIConstants.LOAD_SERVER_DATA_TOOLTIP);
289289
menuItems.add(MenuAndToolbarUtils.createMenuItem(menuAction));
290290

291+
menuAction = new LoadFromURLMenuAction(LoadFromURLMenuAction.LOAD_TRACKHUB, KeyEvent.VK_S, igv);
292+
menuAction.setToolTipText(UIConstants.LOAD_TRACKHUB_TOOLTIP);
293+
menuItems.add(MenuAndToolbarUtils.createMenuItem(menuAction));
294+
291295
menuAction = new LoadFromURLMenuAction(LoadFromURLMenuAction.LOAD_FROM_HTSGET, 0, igv);
292296
menuAction.setToolTipText(UIConstants.LOAD_HTSGET_TOOLTOP);
293297
menuItems.add(MenuAndToolbarUtils.createMenuItem(menuAction));

Diff for: src/main/java/org/broad/igv/ui/UIConstants.java

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ public class UIConstants {
5252

5353
static final public String LOAD_HTSGET_TOOLTOP = "Load BAM or VCF tracks from an htsget server";
5454
static final public String LOAD_SERVER_DATA_TOOLTIP = "Load tracks or sample information from a server";
55+
static final public String LOAD_TRACKHUB_TOOLTIP = "Load an assemlby and tracks from a UCSC Track Hub";
5556
static final public String SAVE_PNG_IMAGE_TOOLTIP = "Capture and save a PNG image";
5657
static final public String SAVE_SVG_IMAGE_TOOLTIP = "Capture and save an SVG image";
5758
static final public String NEW_SESSION_TOOLTIP = "Create a new session";

Diff for: src/main/java/org/broad/igv/ui/action/LoadFromURLMenuAction.java

+27-3
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,7 @@
3737
import org.broad.igv.ui.IGV;
3838
import org.broad.igv.ui.util.LoadFromURLDialog;
3939
import org.broad.igv.ui.util.MessageUtils;
40-
import org.broad.igv.util.AmazonUtils;
41-
import org.broad.igv.util.LongRunningTask;
42-
import org.broad.igv.util.ResourceLocator;
40+
import org.broad.igv.util.*;
4341

4442
import javax.swing.*;
4543
import java.awt.*;
@@ -58,6 +56,7 @@ public class LoadFromURLMenuAction extends MenuAction {
5856
public static final String LOAD_FROM_URL = "Load from URL...";
5957
public static final String LOAD_GENOME_FROM_URL = "Load Genome from URL...";
6058
public static final String LOAD_FROM_HTSGET = "Load from htsget Server...";
59+
public static final String LOAD_TRACKHUB = "Load Track Hub...";
6160
private IGV igv;
6261

6362
public LoadFromURLMenuAction(String label, int mnemonic, IGV igv) {
@@ -139,6 +138,31 @@ else if (inputs.length == 1 && SessionReader.isSessionFile(inputs[0])) {
139138
String url = JOptionPane.showInputDialog(IGV.getInstance().getMainFrame(), ta, "Enter URL to .genome or FASTA file",
140139
JOptionPane.QUESTION_MESSAGE);
141140

141+
if (url != null && url.trim().length() > 0) {
142+
url = url.trim();
143+
try {
144+
checkURLs(new String[]{url});
145+
GenomeManager.getInstance().loadGenome(url);
146+
} catch (Exception e1) {
147+
MessageUtils.showMessage("Error loading genome: " + e1.getMessage());
148+
}
149+
150+
}
151+
} else if ((e.getActionCommand().equalsIgnoreCase(LOAD_TRACKHUB))) {
152+
153+
String urlOrAccension = JOptionPane.showInputDialog(IGV.getInstance().getMainFrame(), ta, "Enter GCA or GCF accension, or URL to hub.txt file",
154+
JOptionPane.QUESTION_MESSAGE);
155+
156+
String url;
157+
if(urlOrAccension.startsWith("GC")) {
158+
url = HubGenomeLoader.convertToHubURL(urlOrAccension);
159+
if(url == null || !FileUtils.resourceExists(url)) {
160+
MessageUtils.showMessage("Unrecognized hub identifier: " + urlOrAccension);
161+
}
162+
} else {
163+
url = urlOrAccension;
164+
}
165+
142166
if (url != null && url.trim().length() > 0) {
143167
url = url.trim();
144168
try {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.broad.igv.feature.genome.load;
2+
3+
import org.junit.Test;
4+
5+
import static org.junit.Assert.*;
6+
7+
public class HubGenomeLoaderTest {
8+
9+
@Test
10+
public void convert() {
11+
String gcfAccession = "GCF_000442705.1";
12+
String gcfURL = "https://hgdownload.soe.ucsc.edu/hubs/GCF/000/442/705/GCF_000442705.1/hub.txt";
13+
String hubTxt = HubGenomeLoader.convertToHubURL(gcfAccession);
14+
assertEquals(gcfURL, hubTxt);
15+
}
16+
17+
}

Diff for: test/web/TrackHubs.html

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>Track Hub links</title>
6+
</head>
7+
<body>
8+
9+
<ul>
10+
11+
<li><a href="#" id="IGV_GCF_016808095.1">GCF_016808095.1 - dynamic link</a> </li>
12+
</ul>
13+
14+
<script type="module">
15+
16+
document.getElementById("IGV_GCF_016808095.1").addEventListener('click', async evt => {
17+
try {
18+
const igvResponse = await fetch("http://localhost:60151/?hubURL=https://hgdownload.soe.ucsc.edu/hubs/GCF/016/808/095/GCF_016808095.1/hub.txt")
19+
//igvResponse.ok
20+
} catch (e) {
21+
//igvDesktopIsResponding = false
22+
alert("IGV Desktop is not running or not listening on port 60151");
23+
}
24+
25+
})
26+
27+
</script>
28+
29+
30+
<!--<script type="module">-->
31+
32+
<!-- let igvDesktopIsResponding-->
33+
<!-- try {-->
34+
<!-- const igvResponse = await fetch("http://localhost:60151/ping")-->
35+
<!-- igvDesktopIsResponding = igvResponse.ok-->
36+
<!-- } catch (e) {-->
37+
<!-- igvDesktopIsResponding = false-->
38+
<!-- }-->
39+
40+
<!-- console.log(igvDesktopIsResponding);-->
41+
42+
<!--</script>-->
43+
44+
</body>
45+
</html>

0 commit comments

Comments
 (0)