Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 9 additions & 3 deletions src/main/java/org/igv/bedpe/HicSource.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public HicSource(String path, Genome genome) throws IOException {
@Override
public List<BedPE> getFeatures(String chr, int start, int end, double bpPerPixel, String normalization, int maxFeatureCount) throws IOException {

final int binSize = getBinSize(bpPerPixel);
final int binSize = getBinSize(chr, bpPerPixel);

List<ContactRecord> records = getRecords(chr, start, end, binSize);

Expand Down Expand Up @@ -159,7 +159,13 @@ public List<BedPE> getFeatures(String chr, int start, int end, double bpPerPixel
return features;
}

private int getBinSize(double bpPerPixel) {
private int getBinSize(String chr, double bpPerPixel) {

if("all".equalsIgnoreCase(chr)) {
// Special case, the whole-genome psuedo-chromosome all has a single resolution
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in comment: "psuedo-chromosome" should be "pseudo-chromosome".

Suggested change
// Special case, the whole-genome psuedo-chromosome all has a single resolution
// Special case, the whole-genome pseudo-chromosome all has a single resolution

Copilot uses AI. Check for mistakes.
return hicFile.getWGResolution();
}

// choose resolution
List<Integer> resolutions = hicFile.getBpResolutions();
int index = 0;
Expand All @@ -180,7 +186,7 @@ public List<String> getNormalizationTypes() {

@Override
public boolean hasNormalizationVector(String type, String chr, double bpPerPixel) {
return hicFile.hasNormalizationVector(type, chr, "BP", getBinSize(bpPerPixel));
return hicFile.hasNormalizationVector(type, chr, "BP", getBinSize(chr, bpPerPixel));
}

/**
Expand Down
69 changes: 38 additions & 31 deletions src/main/java/org/igv/encode/EncodeTrackChooserFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,17 @@

package org.igv.encode;

import org.igv.Globals;
import org.igv.logging.LogManager;
import org.igv.logging.Logger;
import org.igv.prefs.Constants;
import org.igv.prefs.PreferencesManager;
import org.igv.ui.IGV;
import org.igv.ui.action.BrowseEncodeAction;
import org.igv.util.Pair;
import org.igv.util.ParsingUtils;

import javax.swing.text.NumberFormatter;
import java.awt.*;
import java.io.BufferedReader;
import java.io.IOException;
Expand All @@ -12,17 +23,6 @@
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;
import javax.swing.*;
import javax.swing.text.NumberFormatter;

import org.igv.logging.*;
import org.igv.Globals;
import org.igv.prefs.Constants;
import org.igv.prefs.PreferencesManager;
import org.igv.ui.IGV;
import org.igv.ui.action.BrowseEncodeAction;
import org.igv.util.Pair;
import org.igv.util.ParsingUtils;

/**
* @author Jim Robinson
Expand All @@ -35,7 +35,9 @@ public class EncodeTrackChooserFactory {
private static NumberFormatter numberFormatter = new NumberFormatter();
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused field declaration. The numberFormatter field on line 35 is declared but never used in the file. Consider removing it to reduce unnecessary code.

Copilot uses AI. Check for mistakes.

private static String ENCODE_HOST = "https://www.encodeproject.org";
private static Set<String> filteredColumns = new HashSet(Arrays.asList("ID", "Assembly", "HREF", "path"));
private static Set<String> filteredColumns = new HashSet<>(Arrays.asList(
"ID", "Assembly", "HREF", "path",
"url", "Project", "name", "color", "altColor"));

private static List<String> filteredExtensions = Arrays.asList("tsv", "tsv.gz");

Expand All @@ -53,6 +55,8 @@ public class EncodeTrackChooserFactory {
static HashSet<String> ucscSupportedGenomes = new HashSet<>(Arrays.asList("hg19", "mm9"));
static HashSet<String> supportedGenomes = new HashSet<>(
Arrays.asList("ce10", "ce11", "dm3", "dm6", "GRCh38", "hg19", "mm10", "mm9"));
static HashSet<String> hicGenomes = new HashSet<>(
Arrays.asList("GRCh38", "hg19", "mm10", "mm9"));

/**
* Return a new or cached instance of a track chooser for the given genome and type.
Expand All @@ -79,14 +83,15 @@ public synchronized static TrackChooser getInstance(String genomeId, BrowseEncod
instance = new TrackChooser(parent, headings, rows, title);
instanceMap.put(key, instance);
}

return instance;
}

private static String getDialogTitle(String genomeId, BrowseEncodeAction.Type type) {

if (type == BrowseEncodeAction.Type.UCSC) {
return "ENCODE data hosted at UCSC (2012)";
} else if (type == BrowseEncodeAction.Type.FOUR_DN) {
return "4DN";
} else {
switch (type) {
case SIGNALS_CHIP:
Expand All @@ -103,6 +108,10 @@ public static boolean genomeSupportedUCSC(String genomeId) {
return genomeId != null && ucscSupportedGenomes.contains(getEncodeGenomeID(genomeId));
}

public static boolean hicSupportedUCSC(String genomeId) {
return genomeId != null && hicGenomes.contains(getEncodeGenomeID(genomeId));
}

public static boolean genomeSupported(String genomeId) {
return genomeId != null && supportedGenomes.contains(getEncodeGenomeID(genomeId));
}
Expand All @@ -128,26 +137,16 @@ private static Pair<List<String>, List<FileRecord>> getEncodeFileRecords(String
if (is == null) {
return null;
}
Pair<List<String>, List<FileRecord>> headingRecordPair = parseRecords(is, type, genomeId);

if (IGV.hasInstance()) {
Set<String> loadedPaths = IGV.getInstance().getDataResourceLocators().stream()
.map(rl -> rl.getPath())
.collect(Collectors.toSet());

for (FileRecord fileRecord : headingRecordPair.getSecond()) {
if (loadedPaths.contains(fileRecord.getPath())) {
fileRecord.setSelected(true);
}
}
}
return headingRecordPair;
return parseRecords(is, type, genomeId);
}
}

private static InputStream getStreamFor(String genomeId, BrowseEncodeAction.Type type) throws IOException {
if (type == BrowseEncodeAction.Type.UCSC) {
return EncodeTrackChooserFactory.class.getResourceAsStream("encode." + genomeId + ".txt");
} else if (type == BrowseEncodeAction.Type.FOUR_DN) {
String url = PreferencesManager.getPreferences().get(Constants.FOUR_DN_FILELIST_URL) + "4dn_" + genomeId + "_tracks.txt";
return ParsingUtils.openInputStream(url);
} else {
String root = PreferencesManager.getPreferences().get(Constants.ENCODE_FILELIST_URL) + genomeId + ".";
String url = null;
Expand All @@ -158,6 +157,9 @@ private static InputStream getStreamFor(String genomeId, BrowseEncodeAction.Type
case SIGNALS_OTHER:
url = root + "signals.other.txt.gz";
break;
case HIC:
url = root + "hic.txt.gz";
break;
case OTHER:
url = root + "other.txt.gz";
break;
Expand All @@ -175,21 +177,27 @@ private static Pair parseRecords(InputStream is, BrowseEncodeAction.Type type, S

String[] headers = Globals.tabPattern.split(reader.readLine());

int pathColumn = type == BrowseEncodeAction.Type.UCSC ? 0 : Arrays.asList(headers).indexOf("HREF");
int pathColumn = switch (type) {
case UCSC, FOUR_DN -> 0;
default -> Arrays.asList(headers).indexOf("HREF");
};

List<FileRecord> records = new ArrayList<>(20000);
String nextLine;
while ((nextLine = reader.readLine()) != null) {
if (!nextLine.startsWith("#")) {

String[] tokens = Globals.tabPattern.split(nextLine, -1);
String path = type == BrowseEncodeAction.Type.UCSC ? tokens[pathColumn] : ENCODE_HOST + tokens[pathColumn];
String path = switch (type) {
case UCSC, FOUR_DN -> tokens[pathColumn];
default -> ENCODE_HOST + tokens[pathColumn];
};

if (filteredExtensions.stream().anyMatch(e -> path.endsWith(e))) {
continue;
}

Map<String, String> attributes = new LinkedHashMap<>();
Map<String, String> attributes = new HashMap<>();
for (int i = 0; i < headers.length; i++) {
String value = i < tokens.length ? tokens[i] : "";
if (value.length() > 0) {
Expand All @@ -198,7 +206,6 @@ private static Pair parseRecords(InputStream is, BrowseEncodeAction.Type type, S
}
final FileRecord record = new FileRecord(path, attributes);
records.add(record);

}
}

Expand Down
4 changes: 0 additions & 4 deletions src/main/java/org/igv/encode/FileRecord.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,6 @@ public String getAttributeValue(String name) {
return value;
}

public Collection<String> getAttributeNames() {
return attributes.keySet();
}

public Map<String, String> getAttributes() {
return attributes;
}
Expand Down
14 changes: 14 additions & 0 deletions src/main/java/org/igv/encode/TrackChooser.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.igv.Globals;
import org.igv.logging.LogManager;
import org.igv.logging.Logger;
import org.igv.ui.IGV;
import org.igv.util.Pair;

import javax.swing.*;
Expand All @@ -24,6 +25,7 @@
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -109,6 +111,18 @@ public List<FileRecord> getAllRecords() {
return model.getRecords();
}

public void updateRecordSelectionState() {

Set<String> loadedPaths = IGV.getInstance().getDataResourceLocators().stream()
.map(rl -> rl.getPath())
.collect(Collectors.toSet());

for (FileRecord fileRecord : model.getRecords()) {
if (loadedPaths.contains(fileRecord.getPath())) {
fileRecord.setSelected(true);
}
}
}

private class RegexFilter extends RowFilter {

Expand Down
5 changes: 2 additions & 3 deletions src/main/java/org/igv/encode/TrackChooserModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,9 @@ public void updateSelections() {

for (int row = 0; row < records.size(); row++) {
FileRecord record = records.get(row);
if (loadedPaths.contains(record.getPath())) {
record.setSelected(true);
}
record.setSelected(loadedPaths.contains(record.getPath()));
}
fireTableDataChanged();
}

public List<FileRecord> getRecords() {
Expand Down
42 changes: 29 additions & 13 deletions src/main/java/org/igv/hic/HicFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.igv.logging.LogManager;
import org.igv.logging.Logger;
import org.igv.util.CompressionUtils;
import org.igv.util.collections.CaseInsensitiveMap;
import org.igv.util.collections.LRUCache;
import org.igv.util.stream.IGVSeekableStreamFactory;

Expand Down Expand Up @@ -56,7 +57,8 @@ public int getByteSize() {
private Map<String, Long> expectedValueVectors;
private Map<String, Object> attributes;
private List<Chromosome> chromosomes = new ArrayList<>();
private Map<String, Integer> chromosomeIndexMap = new HashMap<>();
private Map<String, Integer> chromosomeIndexMap = new CaseInsensitiveMap<Integer>();
private Integer wgResolution = null;
private List<Integer> bpResolutions = new ArrayList<>();
private List<Integer> fragResolutions = new ArrayList<>();
private Map<String, String> chrAliasTable = new HashMap<>();
Expand Down Expand Up @@ -90,7 +92,7 @@ public int getVersion() {
}

public String getNVIString() {
if(this.normVectorIndexPosition > 0 && this.normVectorIndexSize > 0) {
if (this.normVectorIndexPosition > 0 && this.normVectorIndexSize > 0) {
return this.normVectorIndexPosition + "," + this.normVectorIndexSize;
} else {
return null;
Expand Down Expand Up @@ -158,17 +160,19 @@ private void readHeaderAndFooter() throws IOException {

// chromosomes
this.chromosomes = new ArrayList<>();
this.chromosomeIndexMap = new HashMap<>();
this.chromosomeIndexMap = new CaseInsensitiveMap<>();
int nChrs = bodyParser.getInt();
for (int i = 0; i < nChrs; i++) {
String name = getString(bodyParser);
long size = this.version < 9 ? bodyParser.getInt() : bodyParser.getLong();
Chromosome chr = new Chromosome(i, name, (int) size);
if ("all".equalsIgnoreCase(name)) {
// whole genome handling omitted other fields
}
this.chromosomes.add(chr);

String canonicalName = genome == null ? name : genome.getCanonicalChrName(name);
chrAliasTable.put(canonicalName, name);

this.chromosomeIndexMap.put(name, i);

}

// bp resolutions
Expand All @@ -185,12 +189,6 @@ private void readHeaderAndFooter() throws IOException {
this.fragResolutions.add(bodyParser.getInt());
}
}

// build alias table
for (String chrName : chromosomeIndexMap.keySet()) {
String canonicalName = genome == null ? chrName : genome.getCanonicalChrName(chrName);
chrAliasTable.put(canonicalName, chrName);
}
}

private void readFooter() throws IOException {
Expand Down Expand Up @@ -280,7 +278,7 @@ public List<ContactRecord> getContactRecords(Region region1,
if (block == null) continue;

for (ContactRecord rec : block.records) {
if (allRecords || (rec.bin1() >= x1 && rec.bin1() < x2 && rec.bin2() >= y1 && rec.bin2() < y2) && rec.counts() > 1) {
if (allRecords || (rec.bin1() >= x1 && rec.bin1() < x2 && rec.bin2() >= y1 && rec.bin2() < y2) && rec.counts() > 1) {
contactRecords.add(rec);
}
}
Expand All @@ -289,6 +287,24 @@ public List<ContactRecord> getContactRecords(Region region1,
return contactRecords;
}

public int getWGResolution() {
if (wgResolution == null) {
try {
Integer idx = chromosomeIndexMap.get("all");
if (idx == null) return -1;
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential ArrayIndexOutOfBoundsException. On line 294, the code checks if idx == null but does not validate that idx is within the valid bounds of the chromosomes list before using it to call getMatrix(idx, idx). If the chromosome index is corrupted or invalid, this could cause an exception. Consider adding bounds checking or additional validation.

Suggested change
if (idx == null) return -1;
if (idx == null) return -1;
if (idx < 0 || idx >= chromosomes.size()) {
log.error("Chromosome index for 'all' is out of bounds: " + idx);
return -1;
}

Copilot uses AI. Check for mistakes.
Matrix matrix = getMatrix(idx, idx);
if (matrix == null) return -1;
List<MatrixZoomData> zdArray = matrix.getBpZoomData();
if (zdArray.isEmpty()) return -1;
wgResolution = zdArray.get(0).getZoom().binSize();
} catch (IOException e) {
log.error(e.getMessage());
wgResolution = -1;
}
}
return wgResolution;
}

private List<Block> getBlocks(Region region1, Region region2, String unit, int binSize) throws IOException {
init();
String chr1 = getFileChrName(region1.chr());
Expand Down
1 change: 1 addition & 0 deletions src/main/java/org/igv/prefs/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ private Constants() {

// Misc URLS
public static final String ENCODE_FILELIST_URL = "ENCODE_FILELIST_URL";
public static final String FOUR_DN_FILELIST_URL = "FOUR_DN_FILELIST_URL";


/**
Expand Down
Loading
Loading