List of usage examples for javafx.scene.control Tooltip Tooltip
public Tooltip(String text)
From source file:org.pdfsam.ui.selection.LoadingStatusIndicator.java
private void indicator(AwesomeIcon icon, String tooltip) { setRotate(0);/* w ww . j ava 2 s .c om*/ this.icon.setText(icon.toString()); if (isNotBlank(tooltip)) { this.setTooltip(new Tooltip(tooltip)); } else { this.setTooltip(null); } }
From source file:org.pdfsam.ui.selection.LoadingStatusIndicatorUpdater.java
public void accept(PdfDescriptorLoadingStatus t) { indicator.setText(textValueFor(t));/*from ww w. j a v a 2 s .c o m*/ if (t != null && isNotBlank(t.getDescription())) { indicator.setTooltip(new Tooltip(t.getDescription())); } else { indicator.setTooltip(null); } }
From source file:org.sleuthkit.autopsy.imagegallery.gui.navpanel.GroupCellFactory.java
private <X extends Cell<?> & GroupCell<?>> void updateGroup(X cell, DrawableGroup group) { addListeners(cell.getGroupListener(), group); //and use icon corresponding to group type final Node graphic = (group.getGroupByAttribute() == DrawableAttribute.TAGS) ? controller.getTagsManager().getGraphic((TagName) group.getGroupByValue()) : group.getGroupKey().getGraphic(); final String text = getCellText(cell); final String style = getSeenStyleClass(cell); Platform.runLater(() -> {/*from www.jav a 2 s . com*/ cell.setTooltip(new Tooltip(text)); cell.setGraphic(graphic); cell.setText(text); cell.setStyle(style); }); }
From source file:org.sleuthkit.autopsy.imagegallery.gui.navpanel.GroupTreeCell.java
/** * {@inheritDoc }/* www . j av a2 s . c o m*/ */ @Override protected synchronized void updateItem(final TreeNode treeNode, boolean empty) { //if there was a previous group, remove the listeners Optional.ofNullable(getItem()).map(TreeNode::getGroup).ifPresent(group -> { group.fileIds().removeListener(fileCountListener); group.seenProperty().removeListener(seenListener); }); super.updateItem(treeNode, empty); if (isNull(treeNode) || empty) { Platform.runLater(() -> { setTooltip(null); setText(null); setGraphic(null); setStyle(""); }); } else { if (isNull(treeNode.getGroup())) { final String groupName = getGroupName(); //"dummy" group in file system tree <=> a folder with no drawables Platform.runLater(() -> { setTooltip(new Tooltip(groupName)); setText(groupName); setGraphic(new ImageView(EMPTY_FOLDER_ICON)); setStyle(""); }); } else { //if number of files in this group changes (eg a file is recategorized), update counts via listener treeNode.getGroup().fileIds().addListener(fileCountListener); //if the seen state of this group changes update its style treeNode.getGroup().seenProperty().addListener(seenListener); //and use icon corresponding to group type final Image icon = treeNode.getGroup().groupKey.getAttribute().getIcon(); final String text = getGroupName() + getCountsText(); final String style = getSeenStyleClass(); Platform.runLater(() -> { setTooltip(new Tooltip(text)); setGraphic(new ImageView(icon)); setText(text); setStyle(style); }); } } }
From source file:org.sleuthkit.autopsy.timeline.ui.detailview.AggregateEventNode.java
private void installTooltip() { Tooltip.install(AggregateEventNode.this, new Tooltip(NbBundle.getMessage(this.getClass(), "AggregateEventNode.installTooltip.text", getEvent().getEventIDs().size(), getEvent().getType(), getEvent().getDescription(), getEvent().getSpan().getStart().toString(TimeLineController.getZonedFormatter()), getEvent().getSpan().getEnd().toString(TimeLineController.getZonedFormatter())))); }
From source file:org.ykc.usbcx.MainWindowController.java
@Override public void initialize(URL arg0, ResourceBundle arg1) { Preferences.genTempFolders(); Preferences.loadPreferences(); bOpen.setGraphic(new ImageView(new Image("/open.png"))); bOpen.setTooltip(new Tooltip("Open ucx1 file")); bSave.setGraphic(new ImageView(new Image("/save.png"))); bSave.setTooltip(new Tooltip("Save ucx1 file")); bStartStop.setGraphic(new ImageView(new Image("/start_stop.png"))); bStartStop.setTooltip(new Tooltip("Start/Stop Capture")); bReset.setGraphic(new ImageView(new Image("/reset.png"))); bReset.setTooltip(new Tooltip("Reset and clear")); bTrigger.setGraphic(new ImageView(new Image("/trigger.png"))); bTrigger.setTooltip(new Tooltip("Set Trigger")); bGetVersion.setGraphic(new ImageView(new Image("/version.png"))); bGetVersion.setTooltip(new Tooltip("Get Version")); bDownload.setGraphic(new ImageView(new Image("/download.png"))); bDownload.setTooltip(new Tooltip("Download FW")); bAbout.setGraphic(new ImageView(new Image("/info.png"))); bAbout.setTooltip(new Tooltip("About USBCx")); bFirstPage.setGraphic(new ImageView(new Image("/double_arrow_left.png"))); bFirstPage.setTooltip(new Tooltip("Go to First Page")); bPrevPage.setGraphic(new ImageView(new Image("/arrow_left.png"))); bPrevPage.setTooltip(new Tooltip("Go to Previous Page")); bNextPage.setGraphic(new ImageView(new Image("/arrow_right.png"))); bNextPage.setTooltip(new Tooltip("Go to Next Page")); bLastPage.setGraphic(new ImageView(new Image("/double_arrow_right.png"))); bLastPage.setTooltip(new Tooltip("Go to Last Page")); bCollapse.setGraphic(new ImageView(new Image("/collapse.png"))); bCollapse.setTooltip(new Tooltip("Collapse Items")); bExpand.setGraphic(new ImageView(new Image("/expand.png"))); bExpand.setTooltip(new Tooltip("Expand Items")); bGraphScrollLeft.setGraphic(new ImageView(new Image("/arrow_left.png"))); bGraphScrollLeft.setTooltip(new Tooltip("Previous plot")); bGraphScrollRight.setGraphic(new ImageView(new Image("/arrow_right.png"))); bGraphScrollRight.setTooltip(new Tooltip("Next plot")); ttColPVName.setCellValueFactory(new TreeItemPropertyValueFactory<DetailsRow, String>("name")); ttColPVValue.setCellValueFactory(new TreeItemPropertyValueFactory<DetailsRow, String>("value")); ttColPVDecimal.setCellValueFactory(new TreeItemPropertyValueFactory<DetailsRow, String>("decval")); ttColPVHex.setCellValueFactory(new TreeItemPropertyValueFactory<DetailsRow, String>("hexval")); ttColPVBinary.setCellValueFactory(new TreeItemPropertyValueFactory<DetailsRow, String>("binaryval")); ttColPVLength.setCellValueFactory(new TreeItemPropertyValueFactory<DetailsRow, String>("len")); ttColPVOffset.setCellValueFactory(new TreeItemPropertyValueFactory<DetailsRow, String>("offset")); TreeItem<DetailsRow> rootItem = new TreeItem<DetailsRow>(); ttViewParseViewer.setRoot(rootItem); ttColPVName.setCellFactory((TreeTableColumn<DetailsRow, String> param) -> { TreeTableCell<DetailsRow, String> cell = new TreeTableCell<DetailsRow, String>() { @Override//from w ww . ja v a2 s .c o m protected void updateItem(String item, boolean empty) { super.updateItem(item, empty); setText(empty ? "" : getItem().toString()); TreeTableRow<DetailsRow> ttr = getTreeTableRow(); DetailsRow x = ttr.getItem(); DetailsRow.BG bg = BG.NORMAL; String style = ""; if (x != null) { bg = x.getBcolor(); style += x.getBold() ? "-fx-font-weight:bold;-fx-font-style:italic;" : ""; } switch (bg) { case RED: style += "-fx-text-fill:red;"; break; case GREEN: style += "-fx-text-fill:green;"; break; case BLUE: style += "-fx-text-fill:blue;"; break; case YELLOW: style += "-fx-text-fill:yellow;"; break; case PINK: style += "-fx-text-fill:pink;"; break; default: style += "-fx-text-fill:white;" + "-fx-highlight-fill:dodgerblue;" + "-fx-highlight-text-fill:white"; break; } setStyle(style); } }; return cell; }); tColMViewSno.setCellValueFactory(new PropertyValueFactory<MainViewRow, String>("sno")); tColMViewOk.setCellValueFactory(new PropertyValueFactory<MainViewRow, String>("ok")); tColMViewSop.setCellValueFactory(new PropertyValueFactory<MainViewRow, String>("sop")); tColMViewMsg.setCellValueFactory(new PropertyValueFactory<MainViewRow, String>("msg")); tColMViewId.setCellValueFactory(new PropertyValueFactory<MainViewRow, String>("id")); tColMViewDrole.setCellValueFactory(new PropertyValueFactory<MainViewRow, String>("drole")); tColMViewProle.setCellValueFactory(new PropertyValueFactory<MainViewRow, String>("prole")); tColMViewCount.setCellValueFactory(new PropertyValueFactory<MainViewRow, String>("count")); tColMViewRev.setCellValueFactory(new PropertyValueFactory<MainViewRow, String>("rev")); tColMViewDuration.setCellValueFactory(new PropertyValueFactory<MainViewRow, String>("duration")); tColMViewDelta.setCellValueFactory(new PropertyValueFactory<MainViewRow, String>("delta")); tColMViewVbus.setCellValueFactory(new PropertyValueFactory<MainViewRow, String>("vbus")); tColMViewData.setCellValueFactory(new PropertyValueFactory<MainViewRow, String>("data")); tColMViewStartTime.setCellValueFactory(new PropertyValueFactory<MainViewRow, String>("stime")); tColMViewEndTime.setCellValueFactory(new PropertyValueFactory<MainViewRow, String>("etime")); tColDataViewIndex.setCellValueFactory(new PropertyValueFactory<DataViewRow, Integer>("index")); tColDataViewValue.setCellValueFactory(new PropertyValueFactory<DataViewRow, String>("value")); cBoxMsgClass.getItems().addAll(PDUtils.MSG_CLASS); cBoxMsgClass.getSelectionModel().select(0); cBoxMsgType.getItems().addAll(PDUtils.CTRL_MSG_TYPE); cBoxMsgType.getSelectionModel().select(1); cBoxSop.getItems().addAll(PDUtils.SOP_TYPE); cBoxSop.getSelectionModel().select(0); bFirstPage.setDisable(true); bLastPage.setDisable(true); bPrevPage.setDisable(true); bNextPage.setDisable(true); lGraph = new XScope(lchartData, xAxis, yAxis, cboxGraphXScale, bGraphScrollLeft, bGraphScrollRight, chkGraphCC1, chkGraphCC2, chkGraphVbus, chkGraphAmp, lblGraphYValue, lblGraphXValue, lblGraphDeltaY, lblGraphDeltaX); usbcontrol = new USBControl(cBoxDeviceList, statusBar, lblVolt, lblCur, lblCC1, lblCC2); cordinator = new Cordinator(usbcontrol, tViewMain, tViewData, ttViewParseViewer, lblStartDelta, lGraph); Platform.runLater(() -> { handleArgs(); }); }
From source file:pl.baczkowicz.mqttspy.ui.controllers.NewPublicationController.java
public void initialize(URL location, ResourceBundle resources) { timeBasedFilter = new TimeBasedKeyEventFilter(500); publicationTopicText.setItems(publicationTopics); formatGroup.getToggles().get(0).setUserData(ConversionMethod.PLAIN); formatGroup.getToggles().get(1).setUserData(ConversionMethod.HEX_DECODE); formatGroup.getToggles().get(2).setUserData(ConversionMethod.BASE_64_DECODE); formatGroup.selectToggle(formatGroup.getToggles().get(0)); formatGroup.selectedToggleProperty().addListener(new ChangeListener<Toggle>() { @Override//from w w w. j ava 2s .com public void changed(ObservableValue<? extends Toggle> observable, Toggle oldValue, Toggle newValue) { // If plain has been selected if (newValue != null) { switch ((ConversionMethod) formatGroup.getSelectedToggle().getUserData()) { case BASE_64_DECODE: showAsBase64(); break; case HEX_DECODE: showAsHex(); break; case PLAIN: showAsPlain(); break; default: break; } } } }); publicationTopicText.addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() { @Override public void handle(KeyEvent keyEvent) { switch (keyEvent.getCode()) { case ENTER: { if (connected && timeBasedFilter.processEvent(keyEvent)) { publish(); keyEvent.consume(); } break; } case DIGIT0: { restoreFromKeypress(keyEvent, 0); break; } case DIGIT1: { restoreFromKeypress(keyEvent, 1); break; } case DIGIT2: { restoreFromKeypress(keyEvent, 2); break; } case DIGIT3: { restoreFromKeypress(keyEvent, 3); break; } case DIGIT4: { restoreFromKeypress(keyEvent, 4); break; } case DIGIT5: { restoreFromKeypress(keyEvent, 5); break; } case DIGIT6: { restoreFromKeypress(keyEvent, 6); break; } case DIGIT7: { restoreFromKeypress(keyEvent, 7); break; } case DIGIT8: { restoreFromKeypress(keyEvent, 8); break; } case DIGIT9: { restoreFromKeypress(keyEvent, 9); break; } default: break; } } }); publicationData.setWrapText(true); publicationData.setOnKeyReleased(new EventHandler<Event>() { @Override public void handle(Event event) { final BaseMqttMessage values = readMessage(false, true); String payload = ""; if (values != null) { payload = values.getPayload(); } MqttMessageController.populatePayloadLength(lengthLabel, null, payload.length()); lengthLabel.getStyleClass().removeAll("newLinesPresent", "noNewLines"); if (payload.contains(ConversionUtils.LINE_SEPARATOR_LINUX) || payload.contains(ConversionUtils.LINE_SEPARATOR_WIN) || payload.contains(ConversionUtils.LINE_SEPARATOR_MAC)) { lengthLabel.getStyleClass().add("newLinesPresent"); } else { lengthLabel.getStyleClass().add("noNewLines"); } } }); publishScript.getToggles().get(0).setUserData(null); publishScript.selectedToggleProperty().addListener(new ChangeListener<Toggle>() { @Override public void changed(ObservableValue<? extends Toggle> observable, Toggle oldValue, Toggle newValue) { if (newValue.getUserData() == null) { publishButton.setText("Publish"); } else { publishButton.setText( "Publish" + System.lineSeparator() + "with" + System.lineSeparator() + "script"); } } }); publishButton.setTooltip( new Tooltip("Publish message [" + MqttViewManager.newPublication.getDisplayText() + "]")); }
From source file:poe.trade.assist.Main.java
@Override public void start(Stage stage) { // try { // fh = new FileHandler("D:\\MxDownload\\POE\\poe.trade.assist\\assist.log"); // } catch (IOException e) { // e.printStackTrace(); // }/* ww w .j ava2 s .c om*/ // logger.addHandler(fh); // SimpleFormatter formatter = new SimpleFormatter(); // fh.setFormatter(formatter); // logger.info("Init application."); BorderPane root = new BorderPane(); config = Config.load(); config.get(Config.SEARCH_FILE).ifPresent(searchFileTextField::setText); searchFileTextField.setPromptText("Search CSV File URL or blank"); searchFileTextField.setTooltip(new Tooltip( "Any url to a valid poe.trade.assist CSV search file. Can be googlespreadsheet URL. If left blank, will load search.csv file instead")); searchFileTextField.setMinWidth(330); HBox.setHgrow(searchFileTextField, Priority.ALWAYS); List<Search> searchList = loadSearchListFromFile(); AutoSearchService autoSearchService = new AutoSearchService( Boolean.parseBoolean(config.get(Config.AUTO_ENABLE).get()), Float.parseFloat(config.get(Config.SEARCH_MINUTES).get())); searchPane = new SearchPane(searchList); resultPane = new ResultPane(searchFileTextField, this); autoSearchService.searchesProperty().bind(searchPane.dataProperty()); EventHandler<ActionEvent> reloadAction = e -> { System.out.println("Loading search file: " + searchFileTextField.getText()); List<Search> newList = loadSearchListFromFile(); searchPane.dataProperty().clear(); searchPane.dataProperty().addAll(newList); autoSearchService.restart(); if (searchPane.dataProperty().size() > 0) searchPane.searchTable.getSelectionModel().select(0); }; searchFileTextField.setOnAction(reloadAction); resultPane.loadButton.setOnAction(reloadAction); resultPane.defaultButton.setOnAction(e -> { searchFileTextField.setText(DEFAULT_SEARCH_CSV_FILE); resultPane.loadButton.fire(); }); resultPane.runNowButton.setOnAction(e -> autoSearchService.restart()); // autoSearchService.minsToSleepProperty().bind(resultPane.noOfMinsTextField.textProperty()); setupResultPaneBinding(searchPane, resultPane, autoSearchService); if (searchList.size() > 0) searchPane.searchTable.getSelectionModel().select(0); stage.setOnCloseRequest(we -> { saveSearchList(searchPane); config.setProperty(Config.SEARCH_FILE, searchFileTextField.getText()); config.setProperty(Config.SOUND_FILE, resultPane.soundButton.getUserData().toString()); config.save(); }); config.get(Config.SOUND_FILE).ifPresent(resultPane.soundButton::setUserData); autoSearchService.restart(); // HBox container = new HBox(5, searchPane, resultPane); SplitPane container = new SplitPane(searchPane, resultPane); container.setDividerPositions(0.1); HBox.setHgrow(searchPane, Priority.ALWAYS); HBox.setHgrow(resultPane, Priority.ALWAYS); container.setMaxWidth(Double.MAX_VALUE); // root.getChildren().addAll(container); root.setCenter(container); Scene scene = new Scene(root); stage.getIcons().add(new Image("/48px-Durian.png")); stage.titleProperty().bind(new SimpleStringProperty("poe.trade.assist v5 (Durian) - ") .concat(autoSearchService.messageProperty())); // stage.setWidth(1200); // stage.setHeight(550); stage.setMaximized(true); stage.setScene(scene); stage.show(); searchPane.searchTable.requestFocus(); }
From source file:qupath.lib.gui.panels.classify.RandomTrainingRegionSelector.java
private void createDialog() { dialog = new Stage(); dialog.initOwner(qupath.getStage()); dialog.setTitle("Training sample selector"); pointCreator = new RandomPointCreator(); for (PathClass pathClass : pathClassListModel) { if (pathClass != null && pathClass.getName() != null) pointCreator.addPathClass(pathClass, KeyCode.getKeyCode(pathClass.getName().toUpperCase().substring(0, 1))); // pointCreator.addPathClass(pathClass, KeyStroke.getKeyStroke(new pathClass.getName().toLowerCase().charAt(0), 0).getKeyCode()); }/*from ww w. j av a 2 s. co m*/ // PathClass tumourClass = PathClassFactory.getDefaultPathClass(PathClasses.TUMOR); // PathClass stromaClass = PathClassFactory.getDefaultPathClass(PathClasses.STROMA); // pointCreator.addPathClass(tumourClass, KeyCode.T); // pointCreator.addPathClass(stromaClass, KeyCode.S); QuPathViewer viewer = qupath.getViewer(); pointCreator.registerViewer(viewer); // Adapt to changing active viewers ImageDataChangeListener<BufferedImage> listener = new ImageDataChangeListener<BufferedImage>() { @Override public void imageDataChanged(ImageDataWrapper<BufferedImage> source, ImageData<BufferedImage> imageDataOld, ImageData<BufferedImage> imageDataNew) { if (pointCreator != null) { QuPathViewer viewer = qupath.getViewer(); pointCreator.registerViewer(viewer); updateObjectCache(viewer); } refreshList(); updateLabel(); } }; qupath.addImageDataChangeListener(listener); // Remove listeners for cleanup dialog.setOnCloseRequest(e -> { pointCreator.deregisterViewer(); qupath.removeImageDataChangeListener(listener); dialog.setOnCloseRequest(null); dialog = null; // Re-enable mode switching qupath.setModeSwitchingEnabled(true); }); ParameterPanelFX paramPanel = new ParameterPanelFX(params); paramPanel.getPane().setPadding(new Insets(2, 5, 5, 5)); list = new ListView<PathClass>(pathClassListModel); list.setPrefSize(400, 200); // TODO: ADD A SENSIBLE RENDERER! // For now, this is simply duplicated from PathAnnotationPanel list.setCellFactory(new Callback<ListView<PathClass>, ListCell<PathClass>>() { @Override public ListCell<PathClass> call(ListView<PathClass> p) { ListCell<PathClass> cell = new ListCell<PathClass>() { @Override protected void updateItem(PathClass value, boolean bln) { super.updateItem(value, bln); int size = 10; if (value == null) { setText(null); setGraphic(null); } else if (value.getName() == null) { setText("None"); setGraphic(new Rectangle(size, size, ColorToolsFX.getCachedColor(0, 0, 0, 0))); } else { setText(value.getName()); setGraphic(new Rectangle(size, size, ColorToolsFX.getPathClassColor(value))); } } }; return cell; } }); // list.setCellRenderer(new PathClassListCellRendererPoints()); list.setTooltip(new Tooltip("Available classes")); labelCount = new Label(); labelCount.setTextAlignment(TextAlignment.CENTER); labelCount.setPadding(new Insets(5, 0, 5, 0)); BorderPane panelTop = new BorderPane(); panelTop.setTop(paramPanel.getPane()); panelTop.setCenter(list); panelTop.setBottom(labelCount); labelCount.prefWidthProperty().bind(panelTop.widthProperty()); updateLabel(); // panelButtons.add(new JButton(new UndoAction("Undo"))); Action actionAdd = new Action("Add to class", e -> { if (list == null || pointCreator == null) return; PathClass pathClass = list.getSelectionModel().getSelectedItem(); pointCreator.addPoint(pathClass); }); Action actionSkip = new Action("Skip", e -> { if (pointCreator != null) pointCreator.addPoint(null); }); GridPane panelButtons = PanelToolsFX.createColumnGridControls(ActionUtils.createButton(actionAdd), ActionUtils.createButton(actionSkip)); BorderPane pane = new BorderPane(); pane.setCenter(panelTop); pane.setBottom(panelButtons); pane.setPadding(new Insets(10, 10, 10, 10)); Scene scene = new Scene(pane); dialog.setScene(scene); }
From source file:qupath.lib.gui.panels.survival.KaplanMeierDisplay.java
@SuppressWarnings("unchecked") private void generatePlot() { KaplanMeierDisplay.ScoreData newScoreData = scoreData; // If we have a hierarchy, update the scores with the most recent data if (hierarchy != null) { List<TMACoreObject> cores = PathObjectTools.getTMACoreObjects(hierarchy, false); double[] survival = new double[cores.size()]; boolean[] censored = new boolean[cores.size()]; double[] scores = new double[cores.size()]; // // Optionally sort by scores... helps a bit when debugging e.g. p-values, Hazard ratios etc. // cores.sort((c1, c2) -> Double.compare(c1.getMeasurementList().getMeasurementValue(scoreColumn), c2.getMeasurementList().getMeasurementValue(scoreColumn))); // scoreColumn = "Positive %"; // scoreColumn = "RoughScore"; for (int i = 0; i < cores.size(); i++) { TMACoreObject core = cores.get(i); MeasurementList ml = core.getMeasurementList(); survival[i] = core.getMeasurementList().getMeasurementValue(survivalColumn); double censoredValue = core.getMeasurementList().getMeasurementValue(censoredColumn); boolean hasCensoredValue = !Double.isNaN(censoredValue) && (censoredValue == 0 || censoredValue == 1); censored[i] = censoredValue != 0; if (!hasCensoredValue) { // If we don't have a censored value, ensure we mask out everything else scores[i] = Double.NaN; survival[i] = Double.NaN; } else if (ml.containsNamedMeasurement(scoreColumn)) // Get the score if we can scores[i] = ml.getMeasurementValue(scoreColumn); else { // // Try to compute score if we need to // Map<String, Number> map = ROIMeaningfulMeasurements.getPathClassSummaryMeasurements(core.getChildObjects(), true); // Number value = map.get(scoreColumn); // if (value == null) scores[i] = Double.NaN; // else // scores[i] = value.doubleValue(); }//from w w w . j a v a 2 s . com } // Mask out any scores that don't have associated survival data for (int i = 0; i < survival.length; i++) { if (Double.isNaN(survival[i])) scores[i] = Double.NaN; } newScoreData = new ScoreData(scores, survival, censored); } if (newScoreData == null || newScoreData.scores.length == 0) return; // KaplanMeier kmHigh = new KaplanMeier("Above threshold"); // KaplanMeier kmLow = new KaplanMeier("Below threshold"); double[] quartiles = StatisticsHelper.getQuartiles(newScoreData.scores); double q1 = quartiles[0]; double median = quartiles[1]; double q3 = quartiles[2]; double[] thresholds; if (params != null) { Object thresholdMethod = params.getChoiceParameterValue("scoreThresholdMethod"); if (thresholdMethod.equals("Median")) { // panelParams.setNumericParameterValue("scoreThreshold", median); // ((DoubleParameter)params.getParameters().get("scoreThreshold")).setValue(median); // TODO: UPDATE DIALOG! thresholds = new double[] { median }; } else if (thresholdMethod.equals("Tertiles")) { // ((DoubleParameter)params.getParameters().get("scoreThreshold")).setValue(median); // TODO: UPDATE DIALOG! thresholds = StatisticsHelper.getTertiles(newScoreData.scores); } else if (thresholdMethod.equals("Quartiles")) { // ((DoubleParameter)params.getParameters().get("scoreThreshold")).setValue(median); // TODO: UPDATE DIALOG! thresholds = new double[] { q1, median, q3 }; } else if (thresholdMethod.equals("Manual (1)")) { thresholds = new double[] { params.getDoubleParameterValue("threshold1") }; } else if (thresholdMethod.equals("Manual (2)")) { thresholds = new double[] { params.getDoubleParameterValue("threshold1"), params.getDoubleParameterValue("threshold2") }; } else //if (thresholdMethod.equals("Manual (3)")) { thresholds = new double[] { params.getDoubleParameterValue("threshold1"), params.getDoubleParameterValue("threshold2"), params.getDoubleParameterValue("threshold3") }; } else thresholds = new double[] { median }; double minVal = Double.POSITIVE_INFINITY; double maxVal = Double.NEGATIVE_INFINITY; int numNonNaN = 0; for (double d : newScoreData.scores) { if (Double.isNaN(d)) continue; if (d < minVal) minVal = d; if (d > maxVal) maxVal = d; numNonNaN++; } boolean scoresValid = maxVal > minVal; // If not this, we don't have valid scores that we can work with double maxTimePoint = 0; for (double d : newScoreData.survival) { if (Double.isNaN(d)) continue; if (d > maxTimePoint) maxTimePoint = d; } if (panelParams != null && maxTimePoint > ((IntParameter) params.getParameters().get("censorTimePoints")).getUpperBound()) { panelParams.setNumericParameterValueRange("censorTimePoints", 0, Math.ceil(maxTimePoint)); } // Optionally censor at specified time double censorThreshold = params == null ? maxTimePoint : params.getIntParameterValue("censorTimePoints"); // Compute log-rank p-values for *all* possible thresholds // Simultaneously determine the threshold that yields the lowest p-value, // resolving ties in favour of a more even split between high/low numbers of events boolean pValuesChanged = false; if (calculateAllPValues) { if (!(pValues != null && pValueThresholds != null && newScoreData.equals(scoreData) && censorThreshold == lastPValueCensorThreshold)) { Map<Double, Double> mapLogRank = new TreeMap<>(); Set<Double> setObserved = new HashSet<>(); for (int i = 0; i < newScoreData.scores.length; i++) { Double d = newScoreData.scores[i]; boolean observed = !newScoreData.censored[i] && newScoreData.survival[i] < censorThreshold; if (observed) setObserved.add(d); if (mapLogRank.containsKey(d)) continue; List<KaplanMeierData> kmsTemp = splitByThresholds(newScoreData, new double[] { d }, censorThreshold, false); // if (kmsTemp.get(1).nObserved() == 0 || kmsTemp.get(1).nObserved() == 0) // continue; LogRankResult test = LogRankTest.computeLogRankTest(kmsTemp.get(0), kmsTemp.get(1)); double pValue = test.getPValue(); // double pValue = test.hazardRatio < 1 ? test.hazardRatio : 1.0/test.hazardRatio; // Checking usefulness of Hazard ratios... if (!Double.isFinite(pValue)) continue; // if (!Double.isFinite(test.getHazardRatio())) { //// continue; // pValue = Double.NaN; // } mapLogRank.put(d, pValue); } pValueThresholds = new double[mapLogRank.size()]; pValues = new double[mapLogRank.size()]; pValueThresholdsObserved = new boolean[mapLogRank.size()]; int count = 0; for (Entry<Double, Double> entry : mapLogRank.entrySet()) { pValueThresholds[count] = entry.getKey(); pValues[count] = entry.getValue(); if (setObserved.contains(entry.getKey())) pValueThresholdsObserved[count] = true; count++; } // Find the longest 'significant' stretch int maxSigCount = 0; int maxSigInd = -1; int sigCurrent = 0; int[] sigCount = new int[pValues.length]; for (int i = 0; i < pValues.length; i++) { if (pValues[i] < 0.05) { sigCurrent++; sigCount[i] = sigCurrent; if (sigCurrent > maxSigCount) { maxSigCount = sigCurrent; maxSigInd = i; } } else sigCurrent = 0; } if (maxSigCount == 0) { logger.info("No p-values < 0.05"); } else { double minThresh = maxSigInd - maxSigCount < 0 ? pValueThresholds[0] - 0.0000001 : pValueThresholds[maxSigInd - maxSigCount]; double maxThresh = pValueThresholds[maxSigInd]; int nBetween = 0; int nBetweenObserved = 0; for (int i = 0; i < newScoreData.scores.length; i++) { if (newScoreData.scores[i] > minThresh && newScoreData.scores[i] <= maxThresh) { nBetween++; if (newScoreData.survival[i] < censorThreshold && !newScoreData.censored[i]) nBetweenObserved++; } } logger.info("Longest stretch of p-values < 0.05: {} - {} ({} entries, {} observed)", minThresh, maxThresh, nBetween, nBetweenObserved); } pValuesSmoothed = new double[pValues.length]; Arrays.fill(pValuesSmoothed, Double.NaN); int n = (pValues.length / 20) * 2 + 1; logger.info("Smoothing log-rank test p-values by " + n); for (int i = n / 2; i < pValues.length - n / 2; i++) { double sum = 0; for (int k = i - n / 2; k < i - n / 2 + n; k++) { sum += pValues[k]; } pValuesSmoothed[i] = sum / n; } // for (int i = 0; i < pValues.length; i++) { // double sum = 0; // for (int k = Math.max(0, i-n/2); k < Math.min(pValues.length, i-n/2+n); k++) { // sum += pValues[k]; // } // pValuesSmoothed[i] = sum/n; // } // pValues = pValuesSmoothed; lastPValueCensorThreshold = censorThreshold; pValuesChanged = true; } } else { lastPValueCensorThreshold = Double.NaN; pValueThresholds = null; pValues = null; } // if (params != null && !Double.isNaN(bestThreshold) && (params.getChoiceParameterValue("scoreThresholdMethod").equals("Lowest p-value"))) if (params != null && (params.getChoiceParameterValue("scoreThresholdMethod").equals("Lowest p-value"))) { int bestIdx = -1; double bestPValue = Double.POSITIVE_INFINITY; for (int i = pValueThresholds.length / 10; i < pValueThresholds.length * 9 / 10; i++) { if (pValues[i] < bestPValue) { bestIdx = i; bestPValue = pValues[i]; } } thresholds = bestIdx >= 0 ? new double[] { pValueThresholds[bestIdx] } : new double[0]; } else if (params != null && (params.getChoiceParameterValue("scoreThresholdMethod").equals("Lowest smoothed p-value"))) { int bestIdx = -1; double bestPValue = Double.POSITIVE_INFINITY; for (int i = pValueThresholds.length / 10; i < pValueThresholds.length * 9 / 10; i++) { if (pValuesSmoothed[i] < bestPValue) { bestIdx = i; bestPValue = pValuesSmoothed[i]; } } thresholds = bestIdx >= 0 ? new double[] { pValueThresholds[bestIdx] } : new double[0]; } // Split into different curves using the provided thresholds List<KaplanMeierData> kms = splitByThresholds(newScoreData, thresholds, censorThreshold, params != null && "Quartiles".equals(params.getChoiceParameterValue("scoreThresholdMethod"))); // for (KaplanMeier km : kms) // km.censorAtTime(censorThreshold); //// kmHigh.censorAtTime(censorThreshold); //// kmLow.censorAtTime(censorThreshold); // logger.info("High: " + kmHigh.toString()); // logger.info("Low: " + kmLow.toString()); // logger.info("Log rank comparison: {}", LogRankTest.computeLogRankTest(kmLow, kmHigh)); if (plotter == null) { plotter = new KaplanMeierChartWrapper(survivalColumn + " time"); // plotter.setBorder(BorderFactory.createTitledBorder("Survival plot")); // plotter.getCanvas().setWidth(300); // plotter.getCanvas().setHeight(300); } KaplanMeierData[] kmArray = new KaplanMeierData[kms.size()]; plotter.setKaplanMeierCurves(survivalColumn + " time", kms.toArray(kmArray)); tableModel.setSurvivalCurves(thresholds, params != null && params.getChoiceParameterValue("scoreThresholdMethod").equals("Lowest p-value"), kmArray); // Bar width determined using 'Freedman and Diaconis' rule' (but overridden if this gives < 16 bins...) double barWidth = (2 * q3 - q1) * Math.pow(numNonNaN, -1.0 / 3.0); int nBins = 100; if (!Double.isNaN(barWidth)) barWidth = (int) Math.max(16, Math.ceil((maxVal - minVal) / barWidth)); Histogram histogram = scoresValid ? new Histogram(newScoreData.scores, nBins) : null; if (histogramPanel == null) { GridPane paneHistogram = new GridPane(); histogramPanel = new HistogramPanelFX(); histogramPanel.getChart().setAnimated(false); histogramWrapper = new ThresholdedChartWrapper(histogramPanel.getChart()); for (ObservableNumberValue val : threshProperties) histogramWrapper.addThreshold(val, ColorToolsFX.getCachedColor(240, 0, 0, 128)); histogramWrapper.getPane().setPrefHeight(150); paneHistogram.add(histogramWrapper.getPane(), 0, 0); Tooltip.install(histogramPanel.getChart(), new Tooltip("Distribution of scores")); GridPane.setHgrow(histogramWrapper.getPane(), Priority.ALWAYS); GridPane.setVgrow(histogramWrapper.getPane(), Priority.ALWAYS); NumberAxis xAxis = new NumberAxis(); xAxis.setLabel("Score threshold"); NumberAxis yAxis = new NumberAxis(); yAxis.setLowerBound(0); yAxis.setUpperBound(1); yAxis.setTickUnit(0.1); yAxis.setAutoRanging(false); yAxis.setLabel("P-value"); chartPValues = new LineChart<>(xAxis, yAxis); chartPValues.setAnimated(false); chartPValues.setLegendVisible(false); // Make chart so it can be navigated ChartToolsFX.makeChartInteractive(chartPValues, xAxis, yAxis); pValuesChanged = true; Tooltip.install(chartPValues, new Tooltip( "Distribution of p-values (log-rank test) comparing low vs. high for all possible score thresholds")); // chartPValues.getYAxis().setAutoRanging(false); pValuesWrapper = new ThresholdedChartWrapper(chartPValues); for (ObservableNumberValue val : threshProperties) pValuesWrapper.addThreshold(val, ColorToolsFX.getCachedColor(240, 0, 0, 128)); pValuesWrapper.getPane().setPrefHeight(150); paneHistogram.add(pValuesWrapper.getPane(), 0, 1); GridPane.setHgrow(pValuesWrapper.getPane(), Priority.ALWAYS); GridPane.setVgrow(pValuesWrapper.getPane(), Priority.ALWAYS); ContextMenu popup = new ContextMenu(); ChartToolsFX.addChartExportMenu(chartPValues, popup); RadioMenuItem miZoomY1 = new RadioMenuItem("0-1"); miZoomY1.setOnAction(e -> { yAxis.setAutoRanging(false); yAxis.setUpperBound(1); yAxis.setTickUnit(0.2); }); RadioMenuItem miZoomY05 = new RadioMenuItem("0-0.5"); miZoomY05.setOnAction(e -> { yAxis.setAutoRanging(false); yAxis.setUpperBound(0.5); yAxis.setTickUnit(0.1); }); RadioMenuItem miZoomY02 = new RadioMenuItem("0-0.2"); miZoomY02.setOnAction(e -> { yAxis.setAutoRanging(false); yAxis.setUpperBound(0.2); yAxis.setTickUnit(0.05); }); RadioMenuItem miZoomY01 = new RadioMenuItem("0-0.1"); miZoomY01.setOnAction(e -> { yAxis.setAutoRanging(false); yAxis.setUpperBound(0.1); yAxis.setTickUnit(0.05); }); RadioMenuItem miZoomY005 = new RadioMenuItem("0-0.05"); miZoomY005.setOnAction(e -> { yAxis.setAutoRanging(false); yAxis.setUpperBound(0.05); yAxis.setTickUnit(0.01); }); RadioMenuItem miZoomY001 = new RadioMenuItem("0-0.01"); miZoomY001.setOnAction(e -> { yAxis.setAutoRanging(false); yAxis.setUpperBound(0.01); yAxis.setTickUnit(0.005); }); ToggleGroup tgZoom = new ToggleGroup(); miZoomY1.setToggleGroup(tgZoom); miZoomY05.setToggleGroup(tgZoom); miZoomY02.setToggleGroup(tgZoom); miZoomY01.setToggleGroup(tgZoom); miZoomY005.setToggleGroup(tgZoom); miZoomY001.setToggleGroup(tgZoom); Menu menuZoomY = new Menu("Set y-axis range"); menuZoomY.getItems().addAll(miZoomY1, miZoomY05, miZoomY02, miZoomY01, miZoomY005, miZoomY001); MenuItem miCopyData = new MenuItem("Copy chart data"); miCopyData.setOnAction(e -> { String dataString = ChartToolsFX.getChartDataAsString(chartPValues); ClipboardContent content = new ClipboardContent(); content.putString(dataString); Clipboard.getSystemClipboard().setContent(content); }); popup.getItems().addAll(miCopyData, menuZoomY); chartPValues.setOnContextMenuRequested(e -> { popup.show(chartPValues, e.getScreenX(), e.getScreenY()); }); for (int col = 0; col < tableModel.getColumnCount(); col++) { TableColumn<Integer, String> column = new TableColumn<>(tableModel.getColumnName(col)); int colNumber = col; column.setCellValueFactory( new Callback<CellDataFeatures<Integer, String>, ObservableValue<String>>() { @Override public ObservableValue<String> call(CellDataFeatures<Integer, String> p) { return new SimpleStringProperty( (String) tableModel.getValueAt(p.getValue(), colNumber)); } }); column.setCellFactory(new Callback<TableColumn<Integer, String>, TableCell<Integer, String>>() { @Override public TableCell<Integer, String> call(TableColumn<Integer, String> param) { TableCell<Integer, String> cell = new TableCell<Integer, String>() { @Override protected void updateItem(String item, boolean empty) { super.updateItem(item, empty); setText(item); setTooltip(new Tooltip(item)); } }; return cell; } }); table.getColumns().add(column); } table.setPrefHeight(250); table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); table.maxHeightProperty().bind(table.prefHeightProperty()); params = new ParameterList(); // maxTimePoint = 0; // for (TMACoreObject core : hierarchy.getTMAGrid().getTMACoreList()) { // double os = core.getMeasurementList().getMeasurementValue(TMACoreObject.KEY_OVERALL_SURVIVAL); // double rfs = core.getMeasurementList().getMeasurementValue(TMACoreObject.KEY_RECURRENCE_FREE_SURVIVAL); // if (os > maxTimePoint) // maxTimePoint = os; // if (rfs > maxTimePoint) // maxTimePoint = rfs; // } params.addIntParameter("censorTimePoints", "Max censored time", (int) (censorThreshold + 0.5), null, 0, (int) Math.ceil(maxTimePoint), "Latest time point beyond which data will be censored"); // params.addChoiceParameter("scoreThresholdMethod", "Threshold method", "Manual", Arrays.asList("Manual", "Median", "Log-rank test")); if (calculateAllPValues) // Don't include "Lowest smoothed p-value" - it's not an established method and open to misinterpretation... params.addChoiceParameter("scoreThresholdMethod", "Threshold method", "Median", Arrays.asList("Manual (1)", "Manual (2)", "Manual (3)", "Median", "Tertiles", "Quartiles", "Lowest p-value")); // params.addChoiceParameter("scoreThresholdMethod", "Threshold method", "Median", Arrays.asList("Manual (1)", "Manual (2)", "Manual (3)", "Median", "Tertiles", "Quartiles", "Lowest p-value", "Lowest smoothed p-value")); else params.addChoiceParameter("scoreThresholdMethod", "Threshold method", "Median", Arrays.asList("Manual (1)", "Manual (2)", "Manual (3)", "Median", "Tertiles", "Quartiles")); params.addDoubleParameter("threshold1", "Threshold 1", thresholds.length > 0 ? thresholds[0] : (minVal + maxVal) / 2, null, "Threshold to distinguish between patient groups"); params.addDoubleParameter("threshold2", "Threshold 2", thresholds.length > 1 ? thresholds[1] : (minVal + maxVal) / 2, null, "Threshold to distinguish between patient groups"); params.addDoubleParameter("threshold3", "Threshold 3", thresholds.length > 2 ? thresholds[2] : (minVal + maxVal) / 2, null, "Threshold to distinguish between patient groups"); params.addBooleanParameter("showAtRisk", "Show at risk", plotter.getShowAtRisk(), "Show number of patients at risk below the plot"); params.addBooleanParameter("showTicks", "Show censored ticks", plotter.getShowCensoredTicks(), "Show ticks to indicate censored data"); params.addBooleanParameter("showKey", "Show key", plotter.getShowKey(), "Show key indicating display of each curve"); // params.addBooleanParameter("useColor", "Use color", plotter.getUseColor(), "Show each curve in a different color"); // params.addBooleanParameter("useStrokes", "Use strokes", plotter.getUseStrokes(), "Show each curve with a differed line stroke"); // Hide threshold parameters if threshold can't be used if (!scoresValid) { // params.setHiddenParameters(true, "scoreThresholdMethod", "scoreThreshold"); histogramPanel.getChart().setVisible(false); } panelParams = new ParameterPanelFX(params); panelParams.addParameterChangeListener(this); updateThresholdsEnabled(); for (int i = 0; i < threshProperties.length; i++) { String p = "threshold" + (i + 1); threshProperties[i].addListener((v, o, n) -> { if (interactiveThresholds()) { // Need to do a decent double check with tolerance to text field value changing while typing if (!GeneralTools.almostTheSame(params.getDoubleParameterValue(p), n.doubleValue(), 0.0001)) panelParams.setNumericParameterValue(p, n); } }); } BorderPane paneBottom = new BorderPane(); TitledPane paneOptions = new TitledPane("Options", panelParams.getPane()); // paneOptions.setCollapsible(false); Pane paneCanvas = new StackPane(); paneCanvas.getChildren().add(plotter.getCanvas()); GridPane paneLeft = new GridPane(); paneLeft.add(paneOptions, 0, 0); paneLeft.add(table, 0, 1); GridPane.setHgrow(paneOptions, Priority.ALWAYS); GridPane.setHgrow(table, Priority.ALWAYS); paneBottom.setLeft(paneLeft); paneBottom.setCenter(paneHistogram); paneMain.setCenter(paneCanvas); paneMain.setBottom(paneBottom); paneMain.setPadding(new Insets(10, 10, 10, 10)); } else if (thresholds.length > 0) { // Ensure the sliders/text fields are set sensibly if (!GeneralTools.almostTheSame(thresholds[0], params.getDoubleParameterValue("threshold1"), 0.0001)) { panelParams.setNumericParameterValue("threshold1", thresholds[0]); } if (thresholds.length > 1 && !GeneralTools.almostTheSame(thresholds[1], params.getDoubleParameterValue("threshold2"), 0.0001)) { panelParams.setNumericParameterValue("threshold2", thresholds[1]); } if (thresholds.length > 2 && !GeneralTools.almostTheSame(thresholds[2], params.getDoubleParameterValue("threshold3"), 0.0001)) { panelParams.setNumericParameterValue("threshold3", thresholds[2]); } } if (histogram != null) { histogramPanel.getHistogramData() .setAll(HistogramPanelFX.createHistogramData(histogram, false, (Color) null)); histogramPanel.getChart().getXAxis().setLabel(scoreColumn); histogramPanel.getChart().getYAxis().setLabel("Count"); ChartToolsFX.addChartExportMenu(histogramPanel.getChart(), null); // histogramWrapper.setVerticalLines(thresholds, ColorToolsFX.getCachedColor(240, 0, 0, 128)); // Deal with threshold adjustment // histogramWrapper.getThresholds().addListener((Observable o) -> generatePlot()); } if (pValues != null) { // TODO: Raise earlier where p-value calculation is if (pValuesChanged) { ObservableList<XYChart.Data<Number, Number>> data = FXCollections.observableArrayList(); for (int i = 0; i < pValueThresholds.length; i++) { double pValue = pValues[i]; if (Double.isNaN(pValue)) continue; data.add(new XYChart.Data<>(pValueThresholds[i], pValue, pValueThresholdsObserved[i])); } ObservableList<XYChart.Data<Number, Number>> dataSmoothed = null; if (pValuesSmoothed != null) { dataSmoothed = FXCollections.observableArrayList(); for (int i = 0; i < pValueThresholds.length; i++) { double pValueSmoothed = pValuesSmoothed[i]; if (Double.isNaN(pValueSmoothed)) continue; dataSmoothed.add(new XYChart.Data<>(pValueThresholds[i], pValueSmoothed)); } } // Don't bother showing the smoothed data... it tends to get in the way... // if (dataSmoothed != null) // chartPValues.getData().setAll(new XYChart.Series<>("P-values", data), new XYChart.Series<>("Smoothed P-values", dataSmoothed)); // else chartPValues.getData().setAll(new XYChart.Series<>("P-values", data)); // Add line to show 0.05 significance threshold if (pValueThresholds.length > 1) { Data<Number, Number> sigData1 = new Data<>(pValueThresholds[0], 0.05); Data<Number, Number> sigData2 = new Data<>(pValueThresholds[pValueThresholds.length - 1], 0.05); XYChart.Series<Number, Number> dataSignificant = new XYChart.Series<>("Signficance 0.05", FXCollections.observableArrayList(sigData1, sigData2)); chartPValues.getData().add(dataSignificant); sigData1.getNode().setVisible(false); sigData2.getNode().setVisible(false); } // chartPValues.getData().get(0).getNode().setVisible(true); // pValuesWrapper.clearThresholds(); for (XYChart.Data<Number, Number> dataPoint : data) { if (!Boolean.TRUE.equals(dataPoint.getExtraValue())) dataPoint.getNode().setVisible(false); } // if (dataSmoothed != null) { // for (XYChart.Data<Number, Number> dataPoint : dataSmoothed) { // dataPoint.getNode().setVisible(false); // } // chartPValues.getData().get(1).getNode().setOpacity(0.5); // } // int count = 0; // for (int i = 0; i < pValueThresholds.length; i++) { // double pValue = pValues[i]; // if (Double.isNaN(pValue)) // continue; // boolean observed = pValueThresholdsObserved[i]; //// if (observed) //// pValuesWrapper.addThreshold(new ReadOnlyDoubleWrapper(pValueThresholds[i]), Color.rgb(0, 0, 0, 0.05)); // // if (!observed) { //// StackPane pane = (StackPane)data.get(count).getNode(); //// pane.setEffect(new DropShadow()); // data.get(count).getNode().setVisible(false); // } // count++; // } } for (int i = 0; i < threshProperties.length; i++) { if (i < thresholds.length) threshProperties[i].set(thresholds[i]); else threshProperties[i].set(Double.NaN); } boolean isInteractive = interactiveThresholds(); histogramWrapper.setIsInteractive(isInteractive); pValuesWrapper.setIsInteractive(isInteractive); chartPValues.setVisible(true); } // else // chartPValues.setVisible(false); // Store values for next time scoreData = newScoreData; }