Skip to content
/ igv Public
forked from igvteam/igv

Commit

Permalink
Apply upstream BEDPE support changes mostly
Browse files Browse the repository at this point in the history
  • Loading branch information
brainstorm committed Aug 2, 2019
2 parents 7a0160d + 9fad72b commit b261022
Show file tree
Hide file tree
Showing 18 changed files with 146 additions and 67 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jdk: openjdk11
install:
- ./gradlew assemble
script:
- ./gradlew check --debug
- ./gradlew check
- ./gradlew createMacAppDistZip
- ./gradlew createLinuxDistZip
- ./gradlew createWinDistZip
Expand Down
32 changes: 26 additions & 6 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
// THE SOFTWARE.

apply plugin: 'java'
apply plugin: 'maven'
apply plugin: 'application'

import org.apache.tools.ant.filters.ReplaceTokens
Expand Down Expand Up @@ -190,19 +191,19 @@ tasks.withType(Test) {
systemProperties['ignore.ioexceptions'] = 'false'
maxHeapSize = '2g'
maxParallelForks = Runtime.runtime.availableProcessors().intdiv(2) ?: 1



}

compileTestJava {
inputs.property("moduleName", moduleName)
doFirst {
options.compilerArgs = [
'--module-path', classpath.asPath,
'--module-path', classpath.asPath,
'--add-modules', 'junit',
'--add-modules', 'fest.swing',
'--patch-module', "$moduleName=" + files(sourceSets.test.java.srcDirs).asPath,
'--patch-module', "$moduleName=" + files(sourceSets.test.java.srcDirs).asPath,
]
classpath = files()
}
Expand Down Expand Up @@ -377,7 +378,26 @@ task signWinExeDist(type: Exec, dependsOn: createWinExeDist) {
}
}

tasks.build.dependsOn { [createDistZip, createLinuxDistZip, createMacAppDistZip, createWinDistZip] }
task fullJar(type: Jar, dependsOn: jar) {
// Based on https://discuss.gradle.org/t/removing-dependencies-from-a-jar-file-during-jar-task/5521/3
from {
((configurations.compile - configurations.default) + "${buildDir}/libs/igv.jar").collect {
zipTree(it)
}
} {
exclude "META-INF/**"
}

manifest {
attributes(
"Permissions": "all-permissions",
"Application-Name": "IGV",
"Built-By": System.getProperty('user.name'),
"Main-Class": mainClassName,
"Class-Path": configurations.default.collect { it.getName() }.join(' ')
)
}
}

// XXX: META-INF versions support seem to clash with proguard at this point in time:
// https://sourceforge.net/p/proguard/bugs/665/
Expand Down
6 changes: 6 additions & 0 deletions docs/AWS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Amazon Web Services support for IGV desktop

Please refer to the following step by step tutorial to setup an AWS backend that provides
access to S3 for IGV:

https://umccr.org/blog/igv-amazon-backend-setup/
3 changes: 1 addition & 2 deletions src/main/java/org/broad/igv/Globals.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import org.apache.log4j.Logger;
import org.broad.igv.renderer.SequenceRenderer;

import java.io.FileReader;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.*;
Expand Down Expand Up @@ -132,7 +131,7 @@ public class Globals {
TIMESTAMP = properties.getProperty("timestamp", "???");
BEDtoolsPath = System.getProperty("BEDtoolsPath", BEDtoolsPath);

//Runtime property overrides compile-time property, if both exist.
//Runtime property overrides compile-time property, if both exist.
//If neither exist we default to false
final String developmentProperty = System.getProperty("development", properties.getProperty("development", "false"));
development = Boolean.parseBoolean(developmentProperty);
Expand Down
9 changes: 3 additions & 6 deletions src/main/java/org/broad/igv/batch/CommandListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ public void run() {
try {
clientSocket.close();
clientSocket = null;
// We do NOT set isListening = false here, otherwise logout/login state change falls back to OOB
} catch (IOException e) {
log.error("Error in client socket loop", e);
isListening = false;
Expand Down Expand Up @@ -168,6 +169,7 @@ private void processClientSession(CommandExecutor cmdExe) throws IOException {


while (!halt && (inputLine = in.readLine()) != null) {

String cmd = inputLine;
if (cmd.startsWith("GET")) {

Expand All @@ -180,11 +182,8 @@ private void processClientSession(CommandExecutor cmdExe) throws IOException {
if (tokens.length == 2) {
headers.put(tokens[0].trim(), tokens[1].trim());
}
log.info("Tokens (as in *tokenized* headers, not oauth tokens): "+Arrays.toString(tokens));
}

log.info("Headers: "+headers);
log.info("Command: "+cmd);
log.info(cmd);

String command = null;
Map<String, String> params = null;
Expand All @@ -195,13 +194,11 @@ private void processClientSession(CommandExecutor cmdExe) throws IOException {
} else {
String[] parts = tokens[1].split("\\?");
command = parts[0];
log.debug("Parts of the request: "+Arrays.toString(parts));
params = parts.length < 2 ? new HashMap() : parseParameters(parts[1]);
}

// Detect google oauth callback
if (command.equals("/oauthCallback")) {
log.debug("Response parameters: " + params.toString());
if (params.containsKey("code")) {
OAuthUtils.getInstance().setAuthorizationCode(params.get("code"));
} else if (params.containsKey("token")) {
Expand Down
11 changes: 6 additions & 5 deletions src/main/java/org/broad/igv/bedpe/BedPEFeature.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public class BedPEFeature implements BedPE {
int start2;
int end2;
String name;
String scoreString = "";
double score;
Color color;
int thickness = 1;
Expand Down Expand Up @@ -52,12 +53,12 @@ public int getEnd() {
return Math.max(end1, end2);
}

public int getMidStart() {
return Math.min ((start1 + end1) / 2, (start2 + end2) / 2);
public double getMidStart() {
return Math.min ((start1 + end1) / 2.0, (start2 + end2) / 2.0);
}

public int getMidEnd() {
return Math.max ((start1 + end1) / 2, (start2 + end2) / 2);
public double getMidEnd() {
return Math.max ((start1 + end1) / 2.0, (start2 + end2) / 2.0);
}

@Override
Expand Down Expand Up @@ -114,7 +115,7 @@ public String getValueString() {
}
buf.append(locus1);
buf.append("<br>" + locus2);
buf.append("<br>Score: " + score);
buf.append("<br>Score: " + scoreString);
if(attributes != null) {
buf.append("<br><hr>");
for (Map.Entry<String, String> entry : attributes.entrySet()) {
Expand Down
89 changes: 60 additions & 29 deletions src/main/java/org/broad/igv/bedpe/BedPEParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,17 @@ public static Dataset parse(ResourceLocator locator, Genome genome) throws IOExc
int thicknessColumn = -1;
DatasetType type = DatasetType.UNKNOWN;
boolean parsedHeader = true;
String[] columns;

// Default column headers from BedPE spec. Can be overriden
String[] columns = {"chrom1", "start1", "stop1", "chrom2", "start2", "stop2", "name", "score", "strand1", "strand2"};
boolean col7isNumeric = true; // Until proven otherwise

Map<String, Color> colorCache = new HashMap<>();
List<BedPEFeature> features = new ArrayList<>();
BufferedReader br = null;
br = ParsingUtils.openBufferedReader(locator.getPath());
String nextLine;
boolean firstLine = true;
while ((nextLine = br.readLine()) != null) {

if (nextLine.startsWith("#columns")) {
Expand All @@ -57,11 +60,15 @@ public static Dataset parse(ResourceLocator locator, Genome genome) throws IOExc
} catch (NumberFormatException e) {
log.error("Error parsing #column line.", e);
}
} else if (nextLine.startsWith("#")) {
columns = Globals.tabPattern.split(nextLine);
if (nextLine.trim().equals("#chrom1\tstart1\tstop1\tchrom2\tstart2\tstop2\tname\tqual\tstrand1\tstrand2\tfilters\tinfo")) {
type = DatasetType.TENX;
} else {
} else if (nextLine.trim().equals("#chrom1\tstart1\tstop1\tchrom2\tstart2\tstop2\tname\tqual\tstrand1\tstrand2\tfilters\tinfo")) {
type = DatasetType.TENX;
}

if (nextLine.startsWith("#") || nextLine.startsWith("chr1\tx1\tx2")) {

String[] tokens = Globals.tabPattern.split(nextLine);
if (tokens.length >= 6) {
columns = tokens;
for (int i = 6; i < columns.length; i++) {
if (columns[i].equalsIgnoreCase("color")) {
colorColumn = i;
Expand All @@ -70,10 +77,16 @@ public static Dataset parse(ResourceLocator locator, Genome genome) throws IOExc
}
}
}

} else if (nextLine.startsWith("track") || nextLine.startsWith("##track")) {
TrackProperties trackProperties = new TrackProperties();
ParsingUtils.parseTrackLine(nextLine, trackProperties);
} else if (firstLine && nextLine.startsWith("chromosome1\tx1\tx2") || nextLine.startsWith("chr1\tx1\tx2")) {
columns = Globals.tabPattern.split(nextLine);
for (int i = 6; i < columns.length; i++) {
if (columns[i].equalsIgnoreCase("color")) {
colorColumn = i;
}
}
} else {
String[] tokens = Globals.tabPattern.split(nextLine);

Expand All @@ -100,50 +113,68 @@ public static Dataset parse(ResourceLocator locator, Genome genome) throws IOExc
}

if (tokens.length > 7) {
feature.score = Double.parseDouble(tokens[7]);
feature.scoreString = tokens[7];
try {
feature.score = Double.parseDouble(tokens[7]);
} catch (NumberFormatException e) {
feature.score = 0;
}
}

if (type == DatasetType.TENX) {
if (tokens.length > 8) {
Map<String, String> attributes = new LinkedHashMap<>();
if (!tokens[8].equals(".")) {
attributes.put("filters", tokens[8]);
}
String[] kvPairs = Globals.semicolonPattern.split(tokens[11]);
for (String kvPair : kvPairs) {
String[] kv = Globals.equalPattern.split(kvPair);
attributes.put(kv[0], kv[1]);

for (int i = 8; i < tokens.length; i++) {

String t = tokens[i];
String c = columns != null && columns.length > i ? columns[i] : String.valueOf(i);

if (c.equals("info") && t.contains("=")) {
String[] kvPairs = Globals.semicolonPattern.split(tokens[11]);
for (String kvPair : kvPairs) {
String[] kv = Globals.equalPattern.split(kvPair);
if (kv.length > 1) {
attributes.put(kv[0], kv[1]);
}
}
} else {
attributes.put(c, t);
}
}
feature.attributes = attributes;
feature.type = attributes.get("TYPE");
} else {
if (colorColumn > 0) {
String colorString = tokens[colorColumn];
Color c = colorCache.get(colorString);
if (c == null) {
c = ColorUtilities.stringToColor(colorString);
colorCache.put(colorString, c);
}
feature.color = c;
}
}

if (thicknessColumn > 0) {
feature.thickness = Integer.parseInt(tokens[thicknessColumn]);
if (colorColumn > 0) {
String colorString = tokens[colorColumn];
Color c = colorCache.get(colorString);
if (c == null) {
c = ColorUtilities.stringToColor(colorString);
colorCache.put(colorString, c);
}
feature.color = c;
}

if (thicknessColumn > 0) {
feature.thickness = Integer.parseInt(tokens[thicknessColumn]);
}

// Skipping remaining fields for now

features.add(feature);
}
firstLine = false;
}


// A hack to detect "interaction" bedpe files, which are not spec compliant. Interaction score is column 7
if (col7isNumeric) {
for (BedPEFeature f : features) {
f.score = Double.parseDouble(f.name);
f.scoreString = f.name;
f.name = null;
}
if(type == DatasetType.UNKNOWN) {
if (type == DatasetType.UNKNOWN) {
type = DatasetType.CLUSTER; // A guess
}
}
Expand Down
21 changes: 19 additions & 2 deletions src/main/java/org/broad/igv/bedpe/InteractionTrack.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public class InteractionTrack extends AbstractTrack {
protected static Color axisLineColor = new Color(255, 180, 180);
private JCheckBoxMenuItem autoscaleCB;
private JMenuItem maxScoreItem;
private List<BedPE> wgFeatures;


enum Direction {UP, DOWN}
Expand Down Expand Up @@ -101,6 +102,15 @@ public InteractionTrack(ResourceLocator locator, BedPEParser.Dataset dataset, Ge
} else {
direction = UP;
}

String blockString = PreferencesManager.getPreferences().get(Constants.ARC_BLOCKS);
if (blockString != null) {
try {
showBlocks = Boolean.valueOf(blockString);
} catch (IllegalArgumentException e) {
log.error("Illegal arc blocks option: " + blockString, e);
}
}
}

private void init(List<BedPEFeature> featureList, Genome genome) {
Expand All @@ -116,10 +126,12 @@ private void init(List<BedPEFeature> featureList, Genome genome) {
newList.add(new BedPEInterFeature(f, 2));
}
}
newList.addAll(createWGFeatures(featureList, genome));

featureCache = new FeatureCache<>(newList, 50);

wgFeatures = createWGFeatures(featureList, genome);


}


Expand Down Expand Up @@ -160,7 +172,11 @@ public void load(ReferenceFrame frame) {

private List<BedPE> getFeaturesOverlapping(String chr, double start, double end) {

return featureCache.getFeatures(chr, (int) start, (int) end);
if(chr.equals(Globals.CHR_ALL)) {
return wgFeatures;
} else {
return featureCache.getFeatures(chr, (int) start, (int) end);
}
}

@Override
Expand Down Expand Up @@ -281,6 +297,7 @@ public IGVPopupMenu getPopupMenu(TrackClickEvent te) {
showBlocksCB.setSelected(showBlocks);
showBlocksCB.addActionListener(e -> {
showBlocks = showBlocksCB.isSelected();
PreferencesManager.getPreferences().put(Constants.ARC_BLOCKS, String.valueOf(showBlocksCB.isSelected()));
refresh();
});
menu.add(showBlocksCB);
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/broad/igv/bedpe/PEBlockRenderer.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
public class PEBlockRenderer implements BedPERenderer {

InteractionTrack track;
int rowHeight = 10;
int rowHeight = 6;

public PEBlockRenderer(InteractionTrack track) {
this.track = track;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ public void render(List<BedPE> features, RenderContext context, Rectangle trackR


if (track.maxScore > 0 && bedPE.getScore() > 0) {
double logMax = Math.log10(track.maxScore);
h = (int) ((Math.log10(bedPE.getScore()) / logMax) * h);
double logMax = Math.log10(track.maxScore + 1);
h = (int) ((Math.log10(bedPE.getScore() + 1) / logMax) * h);
}

if (bedPE.isSameChr()) {
Expand Down
Loading

0 comments on commit b261022

Please sign in to comment.