use of qupath.lib.gui.dialogs.ParameterPanelFX in project qupath by qupath.
the class ClassifierBuilderPane method initializeBuildPanel.
private void initializeBuildPanel() {
Button btnUpdateClassifier = new Button("Build & Apply");
btnUpdateClassifier.setTooltip(new Tooltip("Build classifier & apply to objects in the current image"));
tbAutoUpdate.setTooltip(new Tooltip("Automatically update the classification when changes are made to the data - only recommended if the classifier is fast & the amount of training data is small"));
tbAutoUpdate.setOnAction(e -> {
if (!tbAutoUpdate.isDisabled() && tbAutoUpdate.isSelected())
updateClassification(true);
});
panelUpdate = new ParameterPanelFX(paramsUpdate);
// panelUpdate.getPane().setPadding(new Insets(0, 10, 0, 10));
comboClassifiers.setOnAction(e -> {
maybeUpdate();
// WekaClassifierBuilder builder = (WekaClassifierBuilder)comboClassifiers.getSelectedItem();
// We can't auto-update if we don't have a valid (non-advanced) classifier builder
// cbAutoUpdate.setEnabled(builder != null && builder.getClassifierClass() != null);
classifier = (T) comboClassifiers.getSelectionModel().getSelectedItem();
// Enable/disable edit button
if (btnEdit != null)
btnEdit.setDisable(!(classifier instanceof Parameterizable));
tbAutoUpdate.setDisable(classifier == null || !classifier.supportsAutoUpdate());
});
// Make panel to create a classifier
GridPane panelClassifierType = new GridPane();
panelClassifierType.add(new Label("Classifier type: "), 0, 0);
panelClassifierType.add(comboClassifiers, 1, 0);
comboClassifiers.setMaxWidth(Double.MAX_VALUE);
comboClassifiers.setTooltip(new Tooltip("Choose classifier type"));
GridPane.setHgrow(comboClassifiers, Priority.ALWAYS);
panelClassifierType.setHgap(5);
panelClassifierType.setVgap(5);
// Add in options button
btnEdit = new Button("Edit");
btnEdit.setTooltip(new Tooltip("Edit advanced classifier options"));
btnEdit.setDisable(!(classifier instanceof Parameterizable));
btnEdit.setOnAction(e -> {
if (!(classifier instanceof Parameterizable)) {
Dialogs.showErrorMessage("Classifier settings", "No options available for selected classifier!");
return;
}
Parameterizable parameterizable = (Parameterizable) classifier;
ParameterPanelFX panel = new ParameterPanelFX(parameterizable.getParameterList());
// JDialog dialog = new JDialog(qupath.getFrame(), "Classifier settings", ModalityType.APPLICATION_MODAL);
BorderPane pane = new BorderPane();
pane.setCenter(panel.getPane());
Button btnRun = new Button("Rebuild classifier");
btnRun.setOnAction(e2 -> updateClassification(true));
pane.setBottom(btnRun);
Dialogs.showMessageDialog("Classifier settings", pane);
});
panelClassifierType.add(btnEdit, 2, 0);
panelClassifierType.add(tbAutoUpdate, 3, 0);
panelClassifierType.add(btnUpdateClassifier, 4, 0);
panelClassifierType.setPadding(new Insets(10, 10, 10, 10));
// Make feature panel
GridPane panelFeatures = new GridPane();
Button btnFeatures = new Button("Select...");
btnFeatures.setTooltip(new Tooltip("Select features to use for classification - this is required before any classifier can be made"));
btnFeatures.setOnAction(e -> {
qupath.submitShortTask(() -> featurePanel.ensureMeasurementsUpdated());
Dialogs.showMessageDialog("Select Features", featurePanel.getPanel());
updateSelectedFeaturesLabel();
});
Button btnUseAllFeatures = new Button("Use all");
btnUseAllFeatures.setTooltip(new Tooltip("Update feature list to use all available features"));
btnUseAllFeatures.setOnAction(e -> selectAllFeatures());
panelFeatures.add(labelSelectedFeatures, 0, 0);
GridPane.setHgrow(labelSelectedFeatures, Priority.ALWAYS);
labelSelectedFeatures.setMaxWidth(Double.MAX_VALUE);
// labelSelectedFeatures.setTextAlignment(TextAlignment.CENTER);
// labelSelectedFeatures.setAlignment(Pos.CENTER);
panelFeatures.add(btnFeatures, 1, 0);
panelFeatures.add(btnUseAllFeatures, 2, 0);
panelFeatures.setHgap(5);
// Multi-image stuff
GridPane panelSouth = new GridPane();
// Tooltip.install(btnResetTrainingObjects, new Tooltip("Reset all the retained objects, so that the classifier only uses the training objects from the current image"));
miResetTrainingObjects.setOnAction(e -> {
if (retainedObjectsMap == null || retainedObjectsMap.isEmpty())
return;
int nObjects = retainedObjectsMap.countRetainedObjects();
String message = nObjects == 1 ? "Remove one retained object from classifier training?" : "Remove " + nObjects + " retained objects from classifier training?";
if (Dialogs.showYesNoDialog("Remove retained objects", message)) {
retainedObjectsMap.clear();
updateRetainedObjectsLabel();
}
});
final String trainingExtension = "qptrain";
miLoadTrainingObjects.setOnAction(e -> {
File fileTraining = Dialogs.promptForFile("Load objects", null, trainingExtension, new String[] { trainingExtension });
if (fileTraining == null)
return;
if (!loadRetainedObjects(fileTraining)) {
Dialogs.showErrorMessage("Load training objects", "There was an error loading training objects from \n" + fileTraining);
}
});
// btnSaveTrainingObjects.setTooltip(new Tooltip("Load training objects saved in a previous session"));
miSaveTrainingObjects.setOnAction(e -> {
File fileTraining = Dialogs.promptToSaveFile("Save objects", null, null, trainingExtension, trainingExtension);
if (fileTraining == null)
return;
if (!saveRetainedObjects(fileTraining)) {
Dialogs.showErrorMessage("Save training objects", "There was an error saving training objects to \n" + fileTraining);
}
});
// btnSaveTrainingObjects.setTooltip(new Tooltip("Save training objects for reloading in another session"));
miExportTrainingFeatures.setOnAction(e -> {
File fileTraining = Dialogs.promptToSaveFile("Export features", null, null, "Text file", "txt");
if (fileTraining == null)
return;
if (!exportTrainingFeatures(fileTraining)) {
Dialogs.showErrorMessage("Export features", "There was an exporting the training features to \n" + fileTraining);
}
});
// btnExportTrainingFeatures.setTooltip(new Tooltip("Export training features to a text file (e.g. for analysis elsewhere"));
// btnRebuildTrainingFromProject.setTooltip(new Tooltip("Load training objects from all images in the project to use these to create a single classifier"));
miRebuildTrainingFromProject.setOnAction(e -> {
loadAllTrainingSamplesForProject();
});
miClassifyAllImagesInProject.setOnAction(e -> {
classifyAllImagesInProject();
});
miCrossValidateAcrossImages.setOnAction(e -> {
crossValidateAcrossImages();
});
labelRetainedObjects.setTooltip(new Tooltip("The total number of objects last used for training - including from other images not currently open"));
// labelRetainedObjects.setAlignment(Pos.CENTER);
labelRetainedObjects.setMaxWidth(Double.MAX_VALUE);
// labelRetainedObjects.setPadding(new Insets(5, 5, 5, 5));
panelSouth.add(labelRetainedObjects, 0, 0);
GridPane.setHgrow(labelRetainedObjects, Priority.ALWAYS);
// panelSouth.setStyle("-fx-background-color: red;");
MenuItem miShowTrainingObjectMatrix = new MenuItem("Show training object counts");
miShowTrainingObjectMatrix.setOnAction(e -> {
updateRetainedObjectsMap();
showRetainedTrainingMap(retainedObjectsMap);
});
ContextMenu context = new ContextMenu();
context.getItems().addAll(miLoadTrainingObjects, miSaveTrainingObjects, miRebuildTrainingFromProject, new SeparatorMenuItem(), miShowTrainingObjectMatrix, miResetTrainingObjects, new SeparatorMenuItem(), miExportTrainingFeatures, miCrossValidateAcrossImages, miClassifyAllImagesInProject);
context.setOnShowing(e -> {
boolean hasRetainedObjects = !retainedObjectsMap.isEmpty();
boolean hasAnyObjects = hasRetainedObjects || (getHierarchy() != null && !getHierarchy().isEmpty());
miResetTrainingObjects.setDisable(!hasRetainedObjects);
miCrossValidateAcrossImages.setDisable(!hasRetainedObjects);
miSaveTrainingObjects.setDisable(!hasAnyObjects);
miExportTrainingFeatures.setDisable(!hasAnyObjects);
miRebuildTrainingFromProject.setVisible(qupath.getProject() != null);
miClassifyAllImagesInProject.setVisible(qupath.getProject() != null);
});
Button buttonMore = new Button("More...");
buttonMore.setOnMouseClicked(e -> {
context.show(buttonMore, e.getScreenX(), e.getScreenY());
});
panelSouth.add(buttonMore, 1, 0);
// panelSouth.setBottom(panelRetainingButtons);
updateRetainedObjectsLabel();
// TitledPane multiImage = new TitledPane("Multi-image training", panelSouth);
// labelRetainedObjects.prefWidthProperty().bind(multiImage.widthProperty());
// panelClassifier.getChildren().add(multiImage);
// panelSouth.add(panelRetaining, BorderLayout.NORTH);
// panelSouth.add(btnSaveClassifier, BorderLayout.SOUTH);
// panelFeatures.setStyle("-fx-background-color: blue;");
GridPane paneAdvancedMain = new GridPane();
paneAdvancedMain.add(panelFeatures, 0, 0);
paneAdvancedMain.add(panelSouth, 0, 1);
paneAdvancedMain.add(panelUpdate.getPane(), 0, 2);
paneAdvancedMain.setVgap(5);
panelUpdate.getPane().setMaxWidth(Double.MAX_VALUE);
GridPane.setHgrow(panelFeatures, Priority.ALWAYS);
GridPane.setHgrow(panelSouth, Priority.ALWAYS);
GridPane.setHgrow(panelUpdate.getPane(), Priority.ALWAYS);
// panelUpdate.getPane().setStyle("-fx-background-color: green;");
TitledPane paneAdvanced = new TitledPane("Advanced options", paneAdvancedMain);
paneAdvanced.setMaxWidth(Double.MAX_VALUE);
paneAdvanced.setExpanded(false);
// Really, I should probably just use a CSS stylesheet somewhere... here is an inelegant way to change things...
Platform.runLater(() -> {
try {
paneAdvanced.lookup(".title").setStyle("-fx-background-color: transparent");
paneAdvanced.lookup(".title").setEffect(null);
paneAdvanced.lookup(".content").setStyle("-fx-border-color: null");
} catch (Exception e) {
logger.error("Error setting Advanced options pane style", e);
}
});
panelClassifierType.add(paneAdvanced, 0, 1, 6, 1);
progressIndicator.setVisible(false);
progressIndicator.setPrefSize(30, 30);
panelClassifierType.add(progressIndicator, 5, 0, 1, 1);
// panelClassifierType.add(panelUpdate.getPane(), 0, 1, 4, 1);
GridPane.setHgrow(panelUpdate.getPane(), Priority.ALWAYS);
GridPane.setHgrow(paneAdvanced, Priority.ALWAYS);
// btnUpdateClassifier.setMaxWidth(Double.MAX_VALUE);
// panelClassifierType.add(btnUpdateClassifier, 0, 2, 3, 1);
panelClassifier.getChildren().add(new TitledPane("Classifier", panelClassifierType));
panelIntensities.intensityFeatureProperty().addListener((v, o, n) -> updateIntensityPanelCallback());
panelIntensities.addThresholdParameterChangeListener((p, k, a) -> updateIntensityPanelCallback());
panelClassifier.getChildren().add(new TitledPane("Intensity", panelIntensities.getPane()));
btnUpdateClassifier.setOnAction(e -> updateClassification(true));
}
use of qupath.lib.gui.dialogs.ParameterPanelFX in project qupath by qupath.
the class PathIntensityClassifierPane method initialize.
private void initialize() {
panelHistogram = new HistogramPanelFX();
panelHistogram.setShowTickLabels(false);
panelHistogram.getChart().getXAxis().setVisible(false);
panelHistogram.getChart().getXAxis().setTickMarkVisible(false);
panelHistogram.getChart().getYAxis().setVisible(false);
panelHistogram.getChart().getYAxis().setTickMarkVisible(false);
panelHistogram.getChart().setMinHeight(10);
panelHistogram.getChart().setMinWidth(10);
panelHistogram.getChart().setVisible(false);
panelHistogram.getChart().setAnimated(false);
thresholdWrapper = new ThresholdedChartWrapper(panelHistogram.getChart());
comboIntensities = new ComboBox<>();
comboIntensities.setOnAction(e -> {
String selected = comboIntensities.getSelectionModel().getSelectedItem();
logger.trace("Intensities selected: {}", selected);
updateIntensityHistogram();
});
comboIntensities.setTooltip(new Tooltip("Select an intensity feature for thresholding, e.g. to sub-classify objects according to levels of positive staining"));
double threshold_1 = 0.2;
double threshold_2 = 0.4;
double threshold_3 = 0.6;
paramsIntensity = new ParameterList().addDoubleParameter("threshold_1", "Threshold 1+", threshold_1, null, 0, 1.5, "Set first intensity threshold, if required (lowest)").addDoubleParameter("threshold_2", "Threshold 2+", threshold_2, null, 0, 1.5, "Set second intensity threshold, if required (intermediate)").addDoubleParameter("threshold_3", "Threshold 3+", threshold_3, null, 0, 1.5, "Set third intensity threshold, if required (highest)").addBooleanParameter("single_threshold", "Use single threshold", false, "Use only the first intensity threshold to separate positive & negative objects");
pane.add(new Label("Intensity feature: "), 0, 0);
pane.add(comboIntensities, 1, 0);
comboIntensities.setMaxWidth(Double.MAX_VALUE);
GridPane.setHgrow(comboIntensities, Priority.ALWAYS);
this.panelParameters = new ParameterPanelFX(paramsIntensity);
this.panelParameters.addParameterChangeListener(new ParameterChangeListener() {
@Override
public void parameterChanged(ParameterList parameterList, String key, boolean isAdjusting) {
if ("single_threshold".equals(key)) {
boolean single = paramsIntensity.getBooleanParameterValue("single_threshold");
panelParameters.setParameterEnabled("threshold_2", !single);
panelParameters.setParameterEnabled("threshold_3", !single);
}
updateHistogramThresholdLines();
}
});
// pane.add(panelParameters.getPane(), 0, 1, 2, 1);
// GridPane.setFillWidth(panelParameters.getPane(), Boolean.FALSE);
//
// pane.add(thresholdWrapper.getPane(), 2, 1, 1, 1);
// // thresholdWrapper.getPane().setMinSize(10, 10);
// // GridPane.setHgrow(thresholdWrapper.getPane(), Priority.ALWAYS);
// GridPane.setFillHeight(thresholdWrapper.getPane(), Boolean.TRUE);
BorderPane paneBorder = new BorderPane();
paneBorder.setLeft(panelParameters.getPane());
paneBorder.setCenter(thresholdWrapper.getPane());
pane.add(paneBorder, 0, 1, 2, 1);
pane.setVgap(5);
pane.setHgap(5);
// if (addTitle)
// setBorder(BorderFactory.createTitledBorder("Intensity feature"));
}
use of qupath.lib.gui.dialogs.ParameterPanelFX in project qupath by qupath.
the class QuPathGUI method showSetupDialog.
/**
* Show a dialog requesting setup parameters
*
* @return
*/
public boolean showSetupDialog() {
// Show a setup message
Dialog<ButtonType> dialog = new Dialog<>();
dialog.setTitle("QuPath setup");
dialog.initOwner(getStage());
// Try to get an image to display
Image img = loadIcon(128);
BorderPane pane = new BorderPane();
if (img != null) {
StackPane imagePane = new StackPane(new ImageView(img));
imagePane.setPadding(new Insets(10, 10, 10, 10));
pane.setLeft(imagePane);
}
Map<String, Locale> localeMap = Arrays.stream(Locale.getAvailableLocales()).collect(Collectors.toMap(l -> l.getDisplayName(Locale.US), l -> l));
localeMap.remove("");
List<String> localeList = new ArrayList<>(localeMap.keySet());
Collections.sort(localeList);
long maxMemoryMB = Runtime.getRuntime().maxMemory() / 1024 / 1024;
String maxMemoryString = String.format("Current maximum memory is %.2f GB.", maxMemoryMB / 1024.0);
boolean canSetMemory = PathPrefs.hasJavaPreferences();
ParameterList paramsSetup = new ParameterList().addTitleParameter("Memory");
double originalMaxMemory = Math.ceil(maxMemoryMB / 1024.0);
if (canSetMemory) {
paramsSetup.addEmptyParameter("Set the maximum memory used by QuPath.");
// .addEmptyParameter(maxMemoryString);
boolean lowMemory = maxMemoryMB < 1024 * 6;
if (lowMemory) {
paramsSetup.addEmptyParameter("It is suggested to increase the memory limit to approximately\nhalf of the RAM available on your computer.");
}
paramsSetup.addDoubleParameter("maxMemoryGB", "Maximum memory", originalMaxMemory, "GB", "Set the maximum memory for Java.\n" + "Note that some commands (e.g. pixel classification) may still use more memory when needed,\n" + "so this value should generally not exceed half the total memory available on the system.");
} else {
paramsSetup.addEmptyParameter(maxMemoryString).addEmptyParameter("Sorry, I can't access the config file needed to change the max memory.\n" + "See the QuPath installation instructions for more details.");
}
paramsSetup.addTitleParameter("Region").addEmptyParameter("Set the region for QuPath to use for displaying numbers and messages.\n" + "Note: It is *highly recommended* to keep the default (English, US) region settings.\n" + "Support for regions that use different number formatting (e.g. commas as decimal marks)\n" + "is still experimental, and may give unexpected results.").addChoiceParameter("localeFormatting", "Numbers & dates", Locale.getDefault(Category.FORMAT).getDisplayName(), localeList, "Choose region settings used to format numbers and dates").addTitleParameter("Updates").addBooleanParameter("checkForUpdates", "Check for updates on startup (recommended)", PathPrefs.doAutoUpdateCheckProperty().get(), "Specify whether to automatically prompt to download the latest QuPath on startup (required internet connection)");
ParameterPanelFX parameterPanel = new ParameterPanelFX(paramsSetup);
pane.setCenter(parameterPanel.getPane());
Label labelMemory;
if (canSetMemory) {
labelMemory = new Label("You will need to restart QuPath for memory changes to take effect");
labelMemory.setStyle("-fx-font-weight: bold;");
labelMemory.setMaxWidth(Double.MAX_VALUE);
labelMemory.setAlignment(Pos.CENTER);
labelMemory.setFont(Font.font("Arial"));
labelMemory.setPadding(new Insets(10, 10, 10, 10));
pane.setBottom(labelMemory);
}
// dialog.initStyle(StageStyle.UNDECORATED);
dialog.getDialogPane().setContent(pane);
dialog.getDialogPane().getButtonTypes().setAll(ButtonType.APPLY, ButtonType.CANCEL);
Optional<ButtonType> result = dialog.showAndWait();
if (!result.isPresent() || !ButtonType.APPLY.equals(result.get()))
return false;
Locale localeFormatting = localeMap.get(paramsSetup.getChoiceParameterValue("localeFormatting"));
// Locale localeDisplay = localeMap.get(paramsSetup.getChoiceParameterValue("localeDisplay"));
PathPrefs.defaultLocaleFormatProperty().set(localeFormatting);
// PathPrefs.defaultLocaleDisplayProperty().set(localeDisplay);
PathPrefs.doAutoUpdateCheckProperty().set(paramsSetup.getBooleanParameterValue("checkForUpdates"));
if (canSetMemory && paramsSetup.containsKey("maxMemoryGB")) {
int maxMemorySpecifiedMB = (int) (Math.round(paramsSetup.getDoubleParameterValue("maxMemoryGB") * 1024));
if (maxMemorySpecifiedMB >= 1024) {
PathPrefs.maxMemoryMBProperty().set(maxMemorySpecifiedMB);
} else {
if (maxMemorySpecifiedMB >= 0)
Dialogs.showErrorNotification("Max memory setting", "Specified maximum memory setting too low - it must be at least 1 GB");
else
logger.warn("Requested max memory must be at least 1 GB - specified value {} will be ignored", paramsSetup.getDoubleParameterValue("maxMemoryGB"));
// PathPrefs.maxMemoryMBProperty().set(-1);
}
}
// Try to update display
if (getStage() != null && getStage().isShowing())
updateListsAndTables(getStage().getScene().getRoot());
return true;
}
Aggregations