Skip to content
Merged

Panels #1825

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
2caa3e0
1 track panel per track
jrobinso Jan 23, 2026
ca3f708
checkpoint. Feature & seg tracks are working
jrobinso Jan 26, 2026
3770970
checkpoint
jrobinso Jan 27, 2026
23d9e85
checkpoint
jrobinso Jan 28, 2026
b02b455
misc
jrobinso Jan 28, 2026
644396f
Set track height to zero if "isVisible" is false
jrobinso Feb 1, 2026
1e0e8ee
Filtering and grouping VCFs working mostly
jrobinso Feb 12, 2026
f308563
* Restore basic sessions (no track properties)
jrobinso Feb 13, 2026
cfad315
Session "Panel" sections parsed.
jrobinso Feb 14, 2026
26c64c8
checkpoint
jrobinso Feb 16, 2026
643c4e3
Add preference to autosort alignments. See #1788
jrobinso Feb 16, 2026
f489cc7
support drag and drop of files & urls
jrobinso Feb 16, 2026
e6e77db
Add drag & drop handles for track reordering
jrobinso Feb 16, 2026
3982788
align header and track panels, accounting for drag handle panel
jrobinso Feb 16, 2026
8bd76a1
pin sequence track to top. Add new tracks to top, but under sequenc…
jrobinso Feb 16, 2026
8cdcc45
JSON session writing partly working. Many missing attributes.
jrobinso Feb 17, 2026
b2daa00
export igv.js compatible sessions
jrobinso Feb 17, 2026
38bc39d
Support merged tracks in session
jrobinso Feb 17, 2026
02753be
Add missing class
jrobinso Feb 17, 2026
47c0907
handle "Combined" data tracks in session
jrobinso Feb 17, 2026
c51095c
more session edge cases
jrobinso Feb 18, 2026
bbb6ce9
* Support blat track in session
jrobinso Feb 18, 2026
a1c1528
support multi-locus reading in session
jrobinso Feb 18, 2026
db40f54
Fix multilocus bug
jrobinso Feb 18, 2026
f9cefa7
Support "order" property from igv.js to order tracks.
jrobinso Feb 19, 2026
c9e4d26
reduce redundancy between "ResourceLocator" and "TrackConfig"
jrobinso Feb 19, 2026
e2e65a5
Implement all remaining json marshaling
jrobinso Feb 19, 2026
00b7acc
Support "motif" track from session
jrobinso Feb 19, 2026
c4aa82c
complete sessions for all track types
jrobinso Feb 19, 2026
964d0af
fix DataRange marshaling
jrobinso Feb 19, 2026
4d580aa
Add track selection checkboxes
jrobinso Feb 19, 2026
6aacda1
Fix problem with sample attribute painting.
jrobinso Feb 20, 2026
5d868a7
sample info fixes
jrobinso Feb 23, 2026
94a3e1b
Fix sample filtering & grouping. Other misc fixes
jrobinso Feb 24, 2026
ed42872
fix grouped attribute rendering
jrobinso Feb 25, 2026
d8a1dd7
store / restore sampleinfo in sessions
jrobinso Feb 25, 2026
a9ed5e8
support rois in session
jrobinso Feb 25, 2026
f160e5b
Restore "filter" state from sessions
jrobinso Feb 25, 2026
b13ed78
checkpoint - sort by attribute working
jrobinso Feb 27, 2026
3bd2ddf
filter samples working
jrobinso Mar 2, 2026
35ceda9
Restore attribute header click sorting
jrobinso Mar 3, 2026
99fefb1
cleanup
jrobinso Mar 3, 2026
f14781a
Add genelists and hidden attributes to json session.
jrobinso Mar 3, 2026
37d3c5c
reconcile IGV and igv.js json property names
jrobinso Mar 3, 2026
9511bdc
...
jrobinso Mar 4, 2026
abcdbd5
Remove track-name selection artifacts
jrobinso Mar 5, 2026
eeb102f
Support drag & drop track and session files
jrobinso Mar 5, 2026
c7cb461
Bug fix -- reference sequence added twice from XML sessions
jrobinso Mar 5, 2026
8613c5e
Fix alignment, coverage, splice junction hide/show menu items.
jrobinso Mar 5, 2026
2532295
fix alignment auto-sort
jrobinso Mar 6, 2026
5ddc5a7
Dynamically compute the max depth for feature tracks.
jrobinso Mar 7, 2026
09f2611
attribute painting fix
jrobinso Mar 9, 2026
ef4f1d4
fix y offset issue in data panel snapshots
jrobinso Mar 12, 2026
c667f50
Fix name panel backgrounds on snapshots
jrobinso Mar 12, 2026
09b9fb1
fix name wrapping on snapshots
jrobinso Mar 12, 2026
50415a3
Remove border from TrackPanelScrollPane
jrobinso Mar 12, 2026
0ead0cb
fix initial track selection state
jrobinso Mar 12, 2026
ada3197
Account for insets when computing track preferred size
jrobinso Mar 13, 2026
42756c2
Refactor menus -- tracks now return a list of menu items to be compos…
jrobinso Mar 14, 2026
e35766f
Refactor menus
jrobinso Mar 18, 2026
87fbbde
Add track dividers
jrobinso Mar 18, 2026
bd4a889
draggable dividers - don't resize tracks below
jrobinso Mar 18, 2026
bd70cae
Tweak divider behavior
jrobinso Mar 19, 2026
840dea0
mutation track
jrobinso Mar 26, 2026
a565f52
Label sample groups. Also add divider line.
jrobinso Mar 26, 2026
40b5d5c
minor issues with group labels
jrobinso Mar 30, 2026
cf06b53
Fix arrow click on sequence track. Implement expand/squish on seg t…
jrobinso Mar 31, 2026
41667ee
misc
jrobinso Apr 3, 2026
c2419bc
fix sample name in seg track popup menu
jrobinso Apr 3, 2026
164d177
Give sequence track a little more space
jrobinso Apr 3, 2026
4bed873
rearrange menu items
jrobinso Apr 3, 2026
a7934ff
track menu issues
jrobinso Apr 6, 2026
7428e97
Support overlay (merged) tracks in session json and from batch commands
jrobinso Apr 7, 2026
dfeead7
remove track divider lines
jrobinso Apr 7, 2026
abb67df
fix menu bar update from session reload
jrobinso Apr 7, 2026
6cda8d0
remove dead code
jrobinso Apr 7, 2026
23bdcd5
fix issues with drag handle
jrobinso Apr 7, 2026
6dea51c
dark mode for panel dividers
jrobinso Apr 7, 2026
a2ebc29
remove test output
jrobinso Apr 7, 2026
451d703
fix platinum genome references
jrobinso Apr 8, 2026
8842a9c
fix broken batch genome load from local relative path (not a new prob…
jrobinso Apr 8, 2026
30d6e9e
display zoom in notice for bigbed tracks at whole genome view
jrobinso Apr 8, 2026
872643d
border cleanup -- remove vertical lines
jrobinso Apr 8, 2026
459fd0c
add gap between name, attribute, and data panels
jrobinso Apr 8, 2026
cf84d64
fix backgrounds and divider lines
jrobinso Apr 9, 2026
8905015
Fix MAFParser, unit tests.
jrobinso Apr 9, 2026
5292a49
motif finder improvements
jrobinso Apr 9, 2026
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@

#JENV local config file
.java-version
/test/batch/snapshots/
68 changes: 68 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Overview

IGV (Integrative Genomics Viewer) is a desktop Java application for visualizing genomic data. It supports Mac, Windows, and Linux. Requires Java 21.

## Build & Run Commands

```bash
# Build distribution (output: build/IGV-dist/)
./gradlew createDist

# Run all tests (headless, 2GB max heap)
./gradlew test

# Run a single test class or method
./gradlew test --tests org.igv.ucsc.TrixTest
./gradlew test --tests org.igv.ucsc.TrixTest.testMethod

# Build jar only
./gradlew jar

# Platform-specific distributions
./gradlew createMacDistZip
./gradlew createLinuxDistZip
./gradlew createWinDist
```

After `createDist`, launch with `build/IGV-dist/igv.sh` (Linux), `igv.command` (Mac), or `igv.bat` (Windows).

## Test Notes

- Tests run headless (`java.awt.headless=true`); long-running tests excluded by default
- Large test data (~1GB) available separately from ftp://ftp.broadinstitute.org/pub/igv/largedata.zip — unzip to `test/largedata/`

## Architecture

**Entry point:** `org.igv.ui.Main` → creates the Swing JFrame and calls `open()` which initializes the singleton `org.igv.ui.IGV`.

**Core singleton:** `org.igv.ui.IGV` manages the main window, genome, data model, and track list. Only one IGV instance is allowed per JVM.

**Key subsystems:**

| Package | Responsibility |
|---|---|
| `org.igv.ui` | Swing GUI: main window, panels, dialogs, menus |
| `org.igv.track` | Track abstraction — all data types extend `Track`; `TrackMenuUtils` builds context menus |
| `org.igv.renderer` | Rendering engine; each track type has a corresponding renderer |
| `org.igv.feature.genome` | Reference genome management (`Genome`, `GenomeManager`) |
| `org.igv.session` | Session save/load (XML and JSON formats) |
| `org.igv.data` | Data loading and caching layer |
| `org.igv.sam` | SAM/BAM alignment handling |
| `org.igv.variant` | VCF/variant track (`VariantTrack`) |
| `org.igv.seg` | Segmentation data (`SegTrack`) |
| `org.igv.ucsc` | UCSC formats: BigBed, BigWig, TwoBit, TDF |
| `org.igv.batch` | Headless batch mode command execution |
| `org.igv.event` | Pub/sub event bus (`IGVEventBus`, `IGVEventObserver`) |
| `org.igv.prefs` | User preferences (`PreferencesManager`) |
| `org.igv.util` | HTTP, file I/O, stream utilities |
| `org.igv.aws` | AWS S3 / Cognito integration |

**UI panel hierarchy:** `MainPanel` contains a `DataPanel` (the scrollable genome view) composed of `TrackPanel` rows. Each `TrackPanel` has a `TrackNamePanel` (left label area) and a `DataPanelContainer` (right drawing area). Panels communicate via `IGVEventBus`.

**Track rendering:** `Track.render(Graphics2D g, RenderContext context)` is the core drawing method. `RenderContext` carries the current viewport locus, scale, and panel dimensions.

**Session files:** Supported in both XML (legacy `.xml`) and JSON (`.json`) formats. The `session/` package handles serialization; example sessions are in `test/sessions/`.
4 changes: 2 additions & 2 deletions examples/web/StaticLinkExamples.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ <h2>IGV desktop links</h2>
Load with name -- allow dups</a>
</p>
<p>
<a href="http://localhost:60151/load?file=gs://genomics-public-data/platinum-genomes/bam/NA12877_S1.bam&locus=myc&dup=true">
<a href="http://localhost:60151/load?file=https://ftp.1000genomes.ebi.ac.uk/vol1/ftp/data_collections/illumina_platinum_pedigree/data/CEU/NA12877/alignment/NA12877.alt_bwamem_GRCh38DH.20150706.CEU.illumina_platinum_ped.cram&locus=myc&dup=true">
Load BAM -- allow dups</a>
</p>
<p>
Expand All @@ -52,7 +52,7 @@ <h2>IGV desktop links</h2>
Load with index</a>
</p>
<p>
<a href="http://localhost:60151/load?file=https://data.broadinstitute.org/igvdata/annotations/hg19/dbSnp/snp137.hg19.bed.gz,gs://genomics-public-data/platinum-genomes/bam/NA12877_S1.bam&index=https://data.broadinstitute.org/igvdata/annotations/hg19/dbSnp/snp137.hg19.bed.gz.tbi,gs://genomics-public-data/platinum-genomes/bam/NA12877_S1.bam.bai&locus=chr1&name=SNPs,Alignments&locus=myc">
<a href="http://localhost:60151/load?file=https://data.broadinstitute.org/igvdata/annotations/hg19/dbSnp/snp137.hg19.bed.gz,https://ftp.1000genomes.ebi.ac.uk/vol1/ftp/data_collections/illumina_platinum_pedigree/data/CEU/NA12877/alignment/NA12877.alt_bwamem_GRCh38DH.20150706.CEU.illumina_platinum_ped.cram&index=https://data.broadinstitute.org/igvdata/annotations/hg19/dbSnp/snp137.hg19.bed.gz.tbi,https://ftp.1000genomes.ebi.ac.uk/vol1/ftp/data_collections/illumina_platinum_pedigree/data/CEU/NA12877/alignment/NA12877.alt_bwamem_GRCh38DH.20150706.CEU.illumina_platinum_ped.cram.bai&locus=chr1&name=SNPs,Alignments&locus=myc">
Load with index - multiple files</a>
</p>
<p>
Expand Down
6 changes: 5 additions & 1 deletion src/main/java/org/igv/Globals.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
* Date: Feb 3, 2010
*/
public class Globals {

public static final long JS_MAX_SAFE_INTEGER = 9007199254740991L;
public static final long JS_MIN_SAFE_INTEGER = -9007199254740991L;

public static final Color DULL_BLUE = new Color(0, 0, 200);
public static final Color DULL_RED = new Color(200, 0, 0);
private static Logger log = LogManager.getLogger(Globals.class);
Expand All @@ -37,7 +41,7 @@ public class Globals {
/**
* Field description
*/
final public static String SESSION_FILE_EXTENSION = ".xml";
final public static String SESSION_FILE_EXTENSION = ".json";
/**
* GENOME ARCHIVE CONSTANTS
*/
Expand Down
18 changes: 11 additions & 7 deletions src/main/java/org/igv/batch/CommandExecutor.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import org.igv.sam.SortOption;
import org.igv.session.Session;
import org.igv.session.SessionReader;
import org.igv.session.SessionWriter;
import org.igv.session.JSONSessionWriter;
import org.igv.track.*;
import org.igv.ui.IGV;
import org.igv.ui.action.OverlayTracksMenuAction;
Expand Down Expand Up @@ -159,7 +159,7 @@ public String execute(String commandLine) throws IOException {
String trackName = parseTrackName(param1);
result = removeTrack(trackName);
} else if (cmd.equalsIgnoreCase("tweakdivider")) {
igv.tweakPanelDivider();
//igv.tweakPanelDivider();
} else if (cmd.equalsIgnoreCase("setDataRange")) {
result = this.setDataRange(param1, param2);
} else if (cmd.equalsIgnoreCase("setLogScale")) {
Expand Down Expand Up @@ -530,7 +530,7 @@ private String setTrackHeight(String param1, String param2) {
List<Track> tracks = tracksMatchingName(trackName);
if (tracks.size() > 0) {
for (Track track : tracks) {
track.setHeight(height, true);
track.setHeight(height);
igv.repaint(track);
}
return "OK";
Expand Down Expand Up @@ -628,6 +628,10 @@ private String genome(String param1) {
String genomeIDorPath = param1;

try {
File file = new File(resolveFileReference(genomeIDorPath));
if (file.exists()) {
genomeIDorPath = file.getAbsolutePath();
}
GenomeManager.getInstance().loadGenomeById(genomeIDorPath);
result = "OK";
} catch (IOException e) {
Expand Down Expand Up @@ -1126,7 +1130,7 @@ private String createSnapshot(String filename, String region) {
if (region == null || region.trim().length() == 0) {
target = this.igv.getContentPane().getMainPanel();
} else if ("trackpanels".equalsIgnoreCase(region)) {
target = this.igv.getMainPanel().getCenterSplitPane();
target = this.igv.getMainPanel().getTrackPanelContainer();
}

if (target == null) {
Expand All @@ -1145,14 +1149,14 @@ private String createSnapshot(String filename, String region) {

private String saveSession(String filename) {
Session currentSession = igv.getSession();
if (!filename.endsWith(".xml")) {
filename = filename + ".xml";
if (!filename.endsWith(".json")) {
filename = filename + ".json";
}
File targetFile = getFile(filename);
if (targetFile.getParentFile().exists()) {
currentSession.setPath(targetFile.getAbsolutePath());
try {
(new SessionWriter()).saveSession(currentSession, targetFile);
(new JSONSessionWriter(igv)).saveSession(currentSession, targetFile);
return "OK";
} catch (Exception e) {
return "Error writingin sesssion: " + e.getMessage();
Expand Down
3 changes: 1 addition & 2 deletions src/main/java/org/igv/bedpe/BedPERenderer.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@

import org.igv.track.RenderContext;

import java.awt.*;
import java.util.List;

public interface BedPERenderer {
void render(List<BedPE> features, RenderContext context, Rectangle trackRectangle, InteractionTrack.ArcOption arcOption);
void render(List<BedPE> features, RenderContext context, InteractionTrack.ArcOption arcOption);

}
50 changes: 33 additions & 17 deletions src/main/java/org/igv/bedpe/HicInteractionTrack.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.igv.ui.panel.IGVPopupMenu;
import org.igv.ui.panel.ReferenceFrame;
import org.igv.util.ResourceLocator;
import org.json.JSONObject;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

Expand All @@ -31,6 +32,7 @@ public HicInteractionTrack(ResourceLocator locator, HicSource source) {
maxFeatureCount = 5000;
graphType = GraphType.NESTED_ARC;
isHIC = true;
transparency = 0.1f;
setUseScore(false); // Alpha score is set in the renderer based
setDefaultColor(Color.red);
}
Expand All @@ -55,7 +57,7 @@ protected List<BedPE> filterFeaturesForZoom(List<BedPE> features, LoadedInterval
return features;
}

void addHICItems(TrackClickEvent te, IGVPopupMenu menu) {
void addHICItems(TrackClickEvent te, List<Component> items) {

final JMenuItem transparencyItem = new JMenuItem("Set Transparency...");
transparencyItem.addActionListener(e -> {
Expand All @@ -81,7 +83,7 @@ void addHICItems(TrackClickEvent te, IGVPopupMenu menu) {
final Frame parent = IGV.hasInstance() ? IGV.getInstance().getMainFrame() : null;
JOptionPane.showMessageDialog(parent, panel, "Set Transparency for " + this.getDisplayName(), JOptionPane.PLAIN_MESSAGE);
});
menu.add(transparencyItem);
items.add(transparencyItem);


final JMenuItem maxFeatureCountItem = new JMenuItem("Set Maximum Feature Count...");
Expand All @@ -108,13 +110,13 @@ void addHICItems(TrackClickEvent te, IGVPopupMenu menu) {
final Frame parent = IGV.hasInstance() ? IGV.getInstance().getMainFrame() : null;
JOptionPane.showMessageDialog(parent, panel, "Set Max Feature Count for " + this.getDisplayName(), JOptionPane.PLAIN_MESSAGE);
});
menu.add(maxFeatureCountItem);
items.add(maxFeatureCountItem);

// Add normalization options for HiC tracks
List<String> normalizationTypes = featureSource.getNormalizationTypes();
if (normalizationTypes != null && normalizationTypes.size() > 1) {
menu.addSeparator();
menu.add(new JLabel("<html><b>Normalization</b>"));
items.add(new JPopupMenu.Separator());
items.add(new JLabel("<html><b>Normalization</b>"));
ButtonGroup normGroup = new ButtonGroup();
for (String type : normalizationTypes) {
String label = normalizationLabels.getOrDefault(type, type);
Expand All @@ -128,11 +130,11 @@ void addHICItems(TrackClickEvent te, IGVPopupMenu menu) {
this.repaint();
});
normGroup.add(normItem);
menu.add(normItem);
items.add(normItem);
}
}

menu.addSeparator();
items.add(new JPopupMenu.Separator());
JMenuItem mapItem = new JMenuItem("Contact Map View...");
mapItem.setEnabled(contactMapView == null && !FrameManager.isGeneListMode());
mapItem.addActionListener(e -> {
Expand All @@ -143,18 +145,9 @@ void addHICItems(TrackClickEvent te, IGVPopupMenu menu) {
ContactMapView.showPopup(this, hicFile, normalization, frame, colorScale.getMaxColor());
}
});
menu.add(mapItem);
items.add(mapItem);
}

@Override
public void marshalXML(Document document, Element element) {
super.marshalXML(document, element);

String nviString = ((HicSource) featureSource).getNVIString();
if (nviString != null) {
element.setAttribute("nvi", nviString);
}
}

@Override
public void unmarshalXML(Element element, Integer version) {
Expand All @@ -165,5 +158,28 @@ public void unmarshalXML(Element element, Integer version) {
((HicSource) featureSource).setNVIString(nviString);
}
}

@Override
public void marshalJSON(JSONObject json) {
super.marshalJSON(json);
String nviString = ((HicSource) featureSource).getNVIString();
if (nviString != null) {
json.put("nvi", nviString);
}
if(!"NONE".equals(normalization)) {
json.put("normalization", normalization);
}
}

public void unmarshalJSON(JSONObject jsonObject) {
super.unmarshalJSON(jsonObject);
if (jsonObject.has("nvi")) {
String nviString = jsonObject.getString("nvi");
((HicSource) featureSource).setNVIString(nviString);
}
if(jsonObject.has("normalization")) {
this.normalization = jsonObject.getString("normalization");
}
}
}

Loading
Loading