use of qupath.lib.gui.charts.HistogramDisplay in project qupath by qupath.
the class TMASummaryViewer method initialize.
private void initialize() {
model = new TMATableModel();
groupByIDProperty.addListener((v, o, n) -> refreshTableData());
MenuBar menuBar = new MenuBar();
Menu menuFile = new Menu("File");
MenuItem miOpen = new MenuItem("Open...");
miOpen.setAccelerator(new KeyCodeCombination(KeyCode.O, KeyCombination.SHORTCUT_DOWN));
miOpen.setOnAction(e -> {
File file = Dialogs.getChooser(stage).promptForFile(null, null, "TMA data files", new String[] { "qptma" });
if (file == null)
return;
setInputFile(file);
});
MenuItem miSave = new MenuItem("Save As...");
miSave.setAccelerator(new KeyCodeCombination(KeyCode.S, KeyCombination.SHORTCUT_DOWN, KeyCombination.SHIFT_DOWN));
miSave.setOnAction(e -> SummaryMeasurementTableCommand.saveTableModel(model, null, Collections.emptyList()));
MenuItem miImportFromImage = new MenuItem("Import from current image...");
miImportFromImage.setAccelerator(new KeyCodeCombination(KeyCode.I, KeyCombination.SHORTCUT_DOWN, KeyCombination.SHIFT_DOWN));
miImportFromImage.setOnAction(e -> setTMAEntriesFromOpenImage());
MenuItem miImportFromProject = new MenuItem("Import from current project... (experimental)");
miImportFromProject.setAccelerator(new KeyCodeCombination(KeyCode.P, KeyCombination.SHORTCUT_DOWN, KeyCombination.SHIFT_DOWN));
miImportFromProject.setOnAction(e -> setTMAEntriesFromOpenProject());
MenuItem miImportClipboard = new MenuItem("Import from clipboard...");
miImportClipboard.setOnAction(e -> {
String text = Clipboard.getSystemClipboard().getString();
if (text == null) {
Dialogs.showErrorMessage("Import scores", "Clipboard is empty!");
return;
}
int n = importScores(text);
if (n > 0) {
setTMAEntries(new ArrayList<>(entriesBase));
}
Dialogs.showMessageDialog("Import scores", "Number of scores imported: " + n);
});
Menu menuEdit = new Menu("Edit");
MenuItem miCopy = new MenuItem("Copy table to clipboard");
miCopy.setOnAction(e -> {
SummaryMeasurementTableCommand.copyTableContentsToClipboard(model, Collections.emptyList());
});
combinedPredicate.addListener((v, o, n) -> {
// We want any other changes triggered by this to have happened,
// so that the data has already been updated
Platform.runLater(() -> handleTableContentChange());
});
// Reset the scores for missing cores - this ensures they will be NaN and not influence subsequent results
MenuItem miResetMissingScores = new MenuItem("Reset scores for missing cores");
miResetMissingScores.setOnAction(e -> {
int changes = 0;
for (TMAEntry entry : entriesBase) {
if (!entry.isMissing())
continue;
boolean changed = false;
for (String m : entry.getMeasurementNames().toArray(new String[0])) {
if (!TMASummaryEntry.isSurvivalColumn(m) && !Double.isNaN(entry.getMeasurementAsDouble(m))) {
entry.putMeasurement(m, null);
changed = true;
}
}
if (changed)
changes++;
}
if (changes == 0) {
logger.info("No changes made when resetting scores for missing cores!");
return;
}
logger.info("{} change(s) made when resetting scores for missing cores!", changes);
table.refresh();
updateSurvivalCurves();
if (scatterPane != null)
scatterPane.updateChart();
if (histogramDisplay != null)
histogramDisplay.refreshHistogram();
});
menuEdit.getItems().add(miResetMissingScores);
MenuTools.addMenuItems(menuFile, miOpen, miSave, null, miImportClipboard, null, miImportFromImage, miImportFromProject);
menuBar.getMenus().add(menuFile);
menuEdit.getItems().add(miCopy);
menuBar.getMenus().add(menuEdit);
menuFile.setOnShowing(e -> {
boolean imageDataAvailable = QuPathGUI.getInstance() != null && QuPathGUI.getInstance().getImageData() != null && QuPathGUI.getInstance().getImageData().getHierarchy().getTMAGrid() != null;
miImportFromImage.setDisable(!imageDataAvailable);
boolean projectAvailable = QuPathGUI.getInstance() != null && QuPathGUI.getInstance().getProject() != null && !QuPathGUI.getInstance().getProject().getImageList().isEmpty();
miImportFromProject.setDisable(!projectAvailable);
});
// Double-clicking previously used for comments... but conflicts with tree table expansion
// table.setOnMouseClicked(e -> {
// if (!e.isPopupTrigger() && e.getClickCount() > 1)
// promptForComment();
// });
table.setPlaceholder(new Text("Drag TMA data folder onto window, or choose File -> Open"));
table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
BorderPane pane = new BorderPane();
pane.setTop(menuBar);
menuBar.useSystemMenuBarProperty().bindBidirectional(PathPrefs.useSystemMenubarProperty());
// menuBar.setUseSystemMenuBar(true);
// Create options
ToolBar toolbar = new ToolBar();
Label labelMeasurementMethod = new Label("Combination method");
labelMeasurementMethod.setLabelFor(comboMeasurementMethod);
labelMeasurementMethod.setTooltip(new Tooltip("Method whereby measurements for multiple cores with the same " + TMACoreObject.KEY_UNIQUE_ID + " will be combined"));
CheckBox cbHidePane = new CheckBox("Hide pane");
cbHidePane.setSelected(hidePaneProperty.get());
cbHidePane.selectedProperty().bindBidirectional(hidePaneProperty);
CheckBox cbGroupByID = new CheckBox("Group by ID");
entriesBase.addListener((Change<? extends TMAEntry> event) -> {
if (!event.getList().stream().anyMatch(e -> e.getMetadataValue(TMACoreObject.KEY_UNIQUE_ID) != null)) {
cbGroupByID.setSelected(false);
cbGroupByID.setDisable(true);
} else {
cbGroupByID.setDisable(false);
}
});
cbGroupByID.setSelected(groupByIDProperty.get());
cbGroupByID.selectedProperty().bindBidirectional(groupByIDProperty);
CheckBox cbUseSelected = new CheckBox("Use selection only");
cbUseSelected.selectedProperty().bindBidirectional(useSelectedProperty);
CheckBox cbSkipMissing = new CheckBox("Hide missing cores");
cbSkipMissing.selectedProperty().bindBidirectional(skipMissingCoresProperty);
skipMissingCoresProperty.addListener((v, o, n) -> {
table.refresh();
updateSurvivalCurves();
if (histogramDisplay != null)
histogramDisplay.refreshHistogram();
updateSurvivalCurves();
if (scatterPane != null)
scatterPane.updateChart();
});
toolbar.getItems().addAll(labelMeasurementMethod, comboMeasurementMethod, new Separator(Orientation.VERTICAL), cbHidePane, new Separator(Orientation.VERTICAL), cbGroupByID, new Separator(Orientation.VERTICAL), cbUseSelected, new Separator(Orientation.VERTICAL), cbSkipMissing);
comboMeasurementMethod.getItems().addAll(TMAEntries.MeasurementCombinationMethod.values());
comboMeasurementMethod.getSelectionModel().select(TMAEntries.MeasurementCombinationMethod.MEDIAN);
selectedMeasurementCombinationProperty.addListener((v, o, n) -> table.refresh());
ContextMenu popup = new ContextMenu();
MenuItem miSetMissing = new MenuItem("Set missing");
miSetMissing.setOnAction(e -> setSelectedMissingStatus(true));
MenuItem miSetAvailable = new MenuItem("Set available");
miSetAvailable.setOnAction(e -> setSelectedMissingStatus(false));
MenuItem miExpand = new MenuItem("Expand all");
miExpand.setOnAction(e -> {
if (table.getRoot() == null)
return;
for (TreeItem<?> item : table.getRoot().getChildren()) {
item.setExpanded(true);
}
});
MenuItem miCollapse = new MenuItem("Collapse all");
miCollapse.setOnAction(e -> {
if (table.getRoot() == null)
return;
for (TreeItem<?> item : table.getRoot().getChildren()) {
item.setExpanded(false);
}
});
popup.getItems().addAll(miSetMissing, miSetAvailable, new SeparatorMenuItem(), miExpand, miCollapse);
table.setContextMenu(popup);
table.setRowFactory(e -> {
TreeTableRow<TMAEntry> row = new TreeTableRow<>();
// // Make rows invisible if they don't pass the predicate
// row.visibleProperty().bind(Bindings.createBooleanBinding(() -> {
// TMAEntry entry = row.getItem();
// if (entry == null || (entry.isMissing() && skipMissingCoresProperty.get()))
// return false;
// return entries.getPredicate() == null || entries.getPredicate().test(entry);
// },
// skipMissingCoresProperty,
// entries.predicateProperty()));
// Style rows according to what they contain
row.styleProperty().bind(Bindings.createStringBinding(() -> {
if (row.isSelected())
return "";
TMAEntry entry = row.getItem();
if (entry == null || entry instanceof TMASummaryEntry)
return "";
else if (entry.isMissing())
return "-fx-background-color:rgb(225,225,232)";
else
return "-fx-background-color:rgb(240,240,245)";
}, row.itemProperty(), row.selectedProperty()));
// });
return row;
});
BorderPane paneTable = new BorderPane();
paneTable.setTop(toolbar);
paneTable.setCenter(table);
MasterDetailPane mdTablePane = new MasterDetailPane(Side.RIGHT, paneTable, createSidePane(), true);
mdTablePane.showDetailNodeProperty().bind(Bindings.createBooleanBinding(() -> !hidePaneProperty.get() && !entriesBase.isEmpty(), hidePaneProperty, entriesBase));
mdTablePane.setDividerPosition(2.0 / 3.0);
pane.setCenter(mdTablePane);
model.getItems().addListener(new ListChangeListener<TMAEntry>() {
@Override
public void onChanged(ListChangeListener.Change<? extends TMAEntry> c) {
if (histogramDisplay != null)
histogramDisplay.refreshHistogram();
updateSurvivalCurves();
if (scatterPane != null)
scatterPane.updateChart();
}
});
Label labelPredicate = new Label();
labelPredicate.setPadding(new Insets(5, 5, 5, 5));
labelPredicate.setAlignment(Pos.CENTER);
// labelPredicate.setStyle("-fx-background-color: rgba(20, 120, 20, 0.15);");
labelPredicate.setStyle("-fx-background-color: rgba(120, 20, 20, 0.15);");
labelPredicate.textProperty().addListener((v, o, n) -> {
if (n.trim().length() > 0)
pane.setBottom(labelPredicate);
else
pane.setBottom(null);
});
labelPredicate.setMaxWidth(Double.MAX_VALUE);
labelPredicate.setMaxHeight(labelPredicate.getPrefHeight());
labelPredicate.setTextAlignment(TextAlignment.CENTER);
predicateMeasurements.addListener((v, o, n) -> {
if (n == null)
labelPredicate.setText("");
else if (n instanceof TablePredicate) {
TablePredicate tp = (TablePredicate) n;
if (tp.getOriginalCommand().trim().isEmpty())
labelPredicate.setText("");
else
labelPredicate.setText("Predicate: " + tp.getOriginalCommand());
} else
labelPredicate.setText("Predicate: " + n.toString());
});
// predicate.set(new TablePredicate("\"Tumor\" > 100"));
scene = new Scene(pane);
scene.addEventHandler(KeyEvent.KEY_PRESSED, e -> {
KeyCode code = e.getCode();
if ((code == KeyCode.SPACE || code == KeyCode.ENTER) && entrySelected != null) {
promptForComment();
return;
}
});
}
use of qupath.lib.gui.charts.HistogramDisplay in project qupath by qupath.
the class SummaryMeasurementTableCommand method showTable.
/**
* Show a measurement table for the specified image data.
* @param imageData the image data
* @param type the object type to show
*/
public void showTable(ImageData<BufferedImage> imageData, Class<? extends PathObject> type) {
if (imageData == null) {
Dialogs.showNoImageError("Show measurement table");
return;
}
final PathObjectHierarchy hierarchy = imageData.getHierarchy();
ObservableMeasurementTableData model = new ObservableMeasurementTableData();
model.setImageData(imageData, imageData == null ? Collections.emptyList() : imageData.getHierarchy().getObjects(null, type));
SplitPane splitPane = new SplitPane();
HistogramDisplay histogramDisplay = new HistogramDisplay(model, true);
// table.setTableMenuButtonVisible(true);
TableView<PathObject> table = new TableView<>();
table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
table.getSelectionModel().getSelectedItems().addListener(new ListChangeListener<PathObject>() {
@Override
public void onChanged(ListChangeListener.Change<? extends PathObject> c) {
synchronizeSelectionModelToTable(hierarchy, c, table);
}
});
StringProperty displayedName = new SimpleStringProperty(ServerTools.getDisplayableImageName(imageData.getServer()));
var title = Bindings.createStringBinding(() -> {
if (type == null)
return "Results " + displayedName.get();
else
return PathObjectTools.getSuitableName(type, false) + " results - " + displayedName.get();
}, displayedName);
// Handle double-click as a way to center on a ROI
// var enter = new KeyCodeCombination(KeyCode.ENTER);
table.setRowFactory(params -> {
var row = new TableRow<PathObject>();
row.setOnMouseClicked(e -> {
if (e.getClickCount() == 2) {
maybeCenterROI(row.getItem());
}
});
// });
return row;
});
// Create columns according to the table model
// for (int i = 0; i < model.getColumnCount(); i++) {
// // Add string column
// if (model.getColumnClass(i).equals(String.class)) {
// TableColumn<PathObject, String> col = null;
// col = new TableColumn<>(model.getColumnName(i));
// col.setCellValueFactory(new Callback<CellDataFeatures<PathObject, String>, ObservableValue<String>>() {
// public ObservableValue<String> call(CellDataFeatures<PathObject, String> val) {
// return new SimpleStringProperty(val.getValue().getDisplayedName());
// }
// });
// col.setCellFactory(column -> new BasicTableCell<String>());
// table.getColumns().add(col);
// }
// }
boolean tmaCoreList = TMACoreObject.class.isAssignableFrom(type);
// Add TMA core columns, if suitable
if (tmaCoreList) {
TableColumn<PathObject, ROI> col = new TableColumn<>("Image");
col.setCellValueFactory(val -> new SimpleObjectProperty<>(val.getValue().getROI()));
double maxWidth = maxDimForTMACore;
double padding = 10;
col.setCellFactory(column -> new TMACoreTableCell(table, imageData.getServer(), maxWidth, padding));
col.widthProperty().addListener((v, o, n) -> table.refresh());
col.setMaxWidth(maxWidth + padding * 2);
table.getColumns().add(col);
// While here, make sure we have fewer bins - don't usually have all that many cores
histogramDisplay.setNumBins(10);
}
// Create numeric columns
for (String columnName : model.getAllNames()) {
// Add column
if (model.isStringMeasurement(columnName)) {
TableColumn<PathObject, String> col = new TableColumn<>(columnName);
col.setCellValueFactory(column -> model.createStringMeasurement(column.getValue(), column.getTableColumn().getText()));
col.setCellFactory(column -> new BasicTableCell<>());
table.getColumns().add(col);
} else {
TableColumn<PathObject, Number> col = new TableColumn<>(columnName);
col.setCellValueFactory(column -> model.createNumericMeasurement(column.getValue(), column.getTableColumn().getText()));
col.setCellFactory(column -> new NumericTableCell<PathObject>(histogramDisplay));
table.getColumns().add(col);
}
}
// Set the PathObjects - need to deal with sorting, since a FilteredList won't handle it directly
SortedList<PathObject> items = new SortedList<>(model.getItems());
items.comparatorProperty().bind(table.comparatorProperty());
table.setItems(items);
List<ButtonBase> buttons = new ArrayList<>();
ToggleButton btnHistogram = new ToggleButton("Show histograms");
btnHistogram.selectedProperty().addListener((v, o, n) -> {
if (n) {
Pane paneHistograms = histogramDisplay.getPane();
splitPane.getItems().add(paneHistograms);
} else if (histogramDisplay != null)
splitPane.getItems().remove(histogramDisplay.getPane());
});
buttons.add(btnHistogram);
// Button btnScatterplot = new Button("Show scatterplots");
// btnScatterplot.setOnAction(e -> {
// SwingUtilities.invokeLater(() -> {
// JDialog dialog = new ScatterplotDisplay(null, "Scatterplots: " + displayedName, model).getDialog();
// dialog.setLocationRelativeTo(null);
// dialog.setVisible(true);
// });
// });
// buttons.add(btnScatterplot);
Button btnCopy = new Button("Copy to clipboard");
btnCopy.setOnAction(e -> {
// TODO: Deal with repetition immediately below...
Set<String> excludeColumns = new HashSet<>();
for (TableColumn<?, ?> col : table.getColumns()) {
if (!col.isVisible())
excludeColumns.add(col.getText());
}
copyTableContentsToClipboard(model, excludeColumns);
});
buttons.add(btnCopy);
Button btnSave = new Button("Save");
btnSave.setOnAction(e -> {
Set<String> excludeColumns = new HashSet<>();
for (TableColumn<?, ?> col : table.getColumns()) {
if (!col.isVisible())
excludeColumns.add(col.getText());
}
File fileOutput = promptForOutputFile();
if (fileOutput == null)
return;
if (saveTableModel(model, fileOutput, excludeColumns)) {
WorkflowStep step;
String includeColumns;
if (excludeColumns.isEmpty())
includeColumns = "";
else {
List<String> includeColumnList = new ArrayList<>(model.getAllNames());
includeColumnList.removeAll(excludeColumns);
includeColumns = ", " + includeColumnList.stream().map(s -> "'" + s + "'").collect(Collectors.joining(", "));
}
String path = qupath.getProject() == null ? fileOutput.toURI().getPath() : fileOutput.getParentFile().toURI().getPath();
if (type == TMACoreObject.class) {
step = new DefaultScriptableWorkflowStep("Save TMA measurements", String.format("saveTMAMeasurements('%s'%s)", path, includeColumns));
} else if (type == PathAnnotationObject.class) {
step = new DefaultScriptableWorkflowStep("Save annotation measurements", String.format("saveAnnotationMeasurements('%s\'%s)", path, includeColumns));
} else if (type == PathDetectionObject.class) {
step = new DefaultScriptableWorkflowStep("Save detection measurements", String.format("saveDetectionMeasurements('%s'%s)", path, includeColumns));
} else {
step = new DefaultScriptableWorkflowStep("Save measurements", String.format("saveMeasurements('%s', %s%s)", path, type == null ? null : type.getName(), includeColumns));
}
imageData.getHistoryWorkflow().addStep(step);
}
});
buttons.add(btnSave);
Stage frame = new Stage();
frame.initOwner(qupath.getStage());
frame.titleProperty().bind(title);
BorderPane paneTable = new BorderPane();
paneTable.setCenter(table);
// Add text field to filter visible columns
TextField tfColumnFilter = new TextField();
GridPane paneFilter = new GridPane();
paneFilter.add(new Label("Column filter"), 0, 0);
paneFilter.add(tfColumnFilter, 1, 0);
GridPane.setHgrow(tfColumnFilter, Priority.ALWAYS);
paneFilter.setHgap(5);
if (tmaCoreList) {
CheckBox cbHideMissing = new CheckBox("Hide missing cores");
paneFilter.add(cbHideMissing, 2, 0);
cbHideMissing.selectedProperty().addListener((v, o, n) -> {
if (n) {
model.setPredicate(p -> (!(p instanceof TMACoreObject)) || !((TMACoreObject) p).isMissing());
} else
model.setPredicate(null);
});
cbHideMissing.setSelected(true);
}
paneFilter.setPadding(new Insets(2, 5, 2, 5));
paneTable.setBottom(paneFilter);
StringProperty columnFilter = tfColumnFilter.textProperty();
columnFilter.addListener((v, o, n) -> {
String val = n.toLowerCase().trim();
if (val.isEmpty()) {
for (TableColumn<?, ?> col : table.getColumns()) {
if (!col.isVisible())
col.setVisible(true);
}
return;
}
for (TableColumn<?, ?> col : table.getColumns()) {
col.setVisible(col.getText().toLowerCase().contains(val));
}
});
BorderPane pane = new BorderPane();
// pane.setCenter(table);
splitPane.getItems().add(paneTable);
pane.setCenter(splitPane);
GridPane panelButtons = PaneTools.createColumnGridControls(buttons.toArray(new ButtonBase[0]));
pane.setBottom(panelButtons);
PathObjectHierarchyListener listener = new PathObjectHierarchyListener() {
@Override
public void hierarchyChanged(PathObjectHierarchyEvent event) {
if (event.isChanging())
return;
if (!Platform.isFxApplicationThread()) {
Platform.runLater(() -> hierarchyChanged(event));
return;
}
if (imageData != null)
displayedName.set(ServerTools.getDisplayableImageName(imageData.getServer()));
model.refreshEntries();
table.refresh();
if (histogramDisplay != null)
histogramDisplay.refreshHistogram();
}
};
QuPathViewer viewer = qupath.getViewer();
TableViewerListener tableViewerListener = new TableViewerListener(viewer, table);
frame.setOnShowing(e -> {
hierarchy.addPathObjectListener(listener);
viewer.addViewerListener(tableViewerListener);
});
frame.setOnHiding(e -> {
hierarchy.removePathObjectListener(listener);
viewer.removeViewerListener(tableViewerListener);
});
Scene scene = new Scene(pane, 600, 500);
frame.setScene(scene);
frame.show();
// Add ability to remove entries from table
ContextMenu menu = new ContextMenu();
Menu menuLimitClasses = new Menu("Show classes");
menu.setOnShowing(e -> {
Set<PathClass> representedClasses = model.getBackingListEntries().stream().map(p -> p.getPathClass() == null ? null : p.getPathClass().getBaseClass()).collect(Collectors.toCollection(() -> new HashSet<>()));
representedClasses.remove(null);
if (representedClasses.isEmpty()) {
menuLimitClasses.setVisible(false);
} else {
menuLimitClasses.setVisible(true);
}
menuLimitClasses.getItems().clear();
List<PathClass> sortedClasses = new ArrayList<>(representedClasses);
Collections.sort(sortedClasses);
MenuItem miClass = new MenuItem("All");
miClass.setOnAction(e2 -> {
model.setPredicate(null);
histogramDisplay.refreshHistogram();
});
menuLimitClasses.getItems().add(miClass);
for (PathClass pathClass : sortedClasses) {
miClass = new MenuItem(pathClass.getName());
miClass.setOnAction(e2 -> {
model.setPredicate(p -> pathClass.isAncestorOf(p.getPathClass()));
histogramDisplay.refreshHistogram();
});
menuLimitClasses.getItems().add(miClass);
}
});
if (type != TMACoreObject.class) {
menu.getItems().add(menuLimitClasses);
table.setContextMenu(menu);
}
}
use of qupath.lib.gui.charts.HistogramDisplay in project qupath by qupath.
the class TMASummaryViewer method createSidePane.
private Pane createSidePane() {
BorderPane pane = new BorderPane();
TabPane tabPane = new TabPane();
kmDisplay = new KaplanMeierDisplay(null, null, null, null);
BorderPane paneKaplanMeier = new BorderPane();
paneKaplanMeier.setCenter(kmDisplay.getView());
paneKaplanMeier.setPadding(new Insets(10, 10, 10, 10));
// comboMainMeasurement.prefWidthProperty().bind(paneKaplanMeier.widthProperty());
comboMainMeasurement.setMaxWidth(Double.MAX_VALUE);
comboMainMeasurement.setTooltip(new Tooltip("Measurement thresholded to create survival curves etc."));
GridPane kmTop = new GridPane();
kmTop.add(new Label("Score"), 0, 0);
kmTop.add(comboMainMeasurement, 1, 0);
kmTop.add(new Label("Survival type"), 0, 1);
kmTop.add(comboSurvival, 1, 1);
comboSurvival.setTooltip(new Tooltip("Specify overall or recurrence-free survival (if applicable)"));
comboSurvival.setMaxWidth(Double.MAX_VALUE);
GridPane.setHgrow(comboMainMeasurement, Priority.ALWAYS);
GridPane.setHgrow(comboSurvival, Priority.ALWAYS);
kmTop.setHgap(5);
paneKaplanMeier.setTop(kmTop);
// kmDisplay.setOrientation(Orientation.VERTICAL);
histogramDisplay = new HistogramDisplay(model, false);
comboMainMeasurement.getSelectionModel().selectedItemProperty().addListener((v, o, n) -> {
histogramDisplay.refreshCombo();
histogramDisplay.showHistogram(n);
updateSurvivalCurves();
});
comboMeasurementMethod.getSelectionModel().selectedItemProperty().addListener((v, o, n) -> {
histogramDisplay.refreshHistogram();
scatterPane.updateChart();
updateSurvivalCurves();
});
comboSurvival.getSelectionModel().selectedItemProperty().addListener((v, o, n) -> {
updateSurvivalCurves();
});
// Create a Tab for showing images
BorderPane paneImages = new BorderPane();
CheckBox cbShowOverlay = new CheckBox("Show overlay");
imageAvailability.addListener((c, v, n) -> {
if (n == ImageAvailability.OVERLAY_ONLY)
cbShowOverlay.setSelected(true);
else if (n == ImageAvailability.IMAGE_ONLY)
cbShowOverlay.setSelected(false);
cbShowOverlay.setDisable(n != ImageAvailability.BOTH);
});
ListView<TMAEntry> listImages = new ListView<>();
listImages.setCellFactory(v -> new ImageListCell(cbShowOverlay.selectedProperty(), imageCache));
listImages.widthProperty().addListener((v, o, n) -> listImages.refresh());
listImages.setStyle("-fx-control-inner-background-alt: -fx-control-inner-background ;");
table.getSelectionModel().getSelectedItems().addListener((Change<? extends TreeItem<TMAEntry>> e) -> {
List<TMAEntry> entries = new ArrayList<>();
for (TreeItem<TMAEntry> item : e.getList()) {
if (item.getChildren().isEmpty()) {
if (item.getValue().hasImage() || item.getValue().hasOverlay())
entries.add(item.getValue());
} else {
for (TreeItem<TMAEntry> item2 : item.getChildren()) {
if (item2.getValue().hasImage() || item2.getValue().hasOverlay())
entries.add(item2.getValue());
}
}
listImages.getItems().setAll(entries);
}
});
cbShowOverlay.setAlignment(Pos.CENTER);
cbShowOverlay.setMaxWidth(Double.MAX_VALUE);
cbShowOverlay.setPadding(new Insets(5, 5, 5, 5));
cbShowOverlay.selectedProperty().addListener((v, o, n) -> listImages.refresh());
paneImages.setCenter(listImages);
paneImages.setTop(cbShowOverlay);
// Determine visibility based upon whether there are any images to show
// Tab tabImages = new Tab("Images", paneImages);
ScrollPane scrollPane = new ScrollPane(paneKaplanMeier);
scrollPane.setFitToWidth(true);
scrollPane.setFitToHeight(true);
scrollPane.setVbarPolicy(ScrollBarPolicy.AS_NEEDED);
scrollPane.setHbarPolicy(ScrollBarPolicy.AS_NEEDED);
Tab tabSurvival = new Tab("Survival", scrollPane);
tabPane.getTabs().addAll(new Tab("Table", getCustomizeTablePane()), // tabImages,
new Tab("Histogram", histogramDisplay.getPane()), new Tab("Scatterplot", scatterPane.getPane()), tabSurvival);
tabPane.setTabClosingPolicy(TabClosingPolicy.UNAVAILABLE);
// if (imageAvailability.get() != ImageAvailability.NONE)
// tabPane.getTabs().add(1, tabImages);
//
// imageAvailability.addListener((c, v, n) -> {
// if (n == ImageAvailability.NONE)
// tabPane.getTabs().remove(tabImages);
// else if (!tabPane.getTabs().contains(tabImages))
// tabPane.getTabs().add(1, tabImages);
// });
// tabSurvival.visibleProperty().bind(
// Bindings.createBooleanBinding(() -> !survivalColumns.isEmpty(), survivalColumns)
// );
pane.setCenter(tabPane);
pane.setMinWidth(350);
return pane;
}
Aggregations