Example usage for javafx.scene.control Tooltip Tooltip

List of usage examples for javafx.scene.control Tooltip Tooltip

Introduction

In this page you can find the example usage for javafx.scene.control Tooltip Tooltip.

Prototype

public Tooltip(String text) 

Source Link

Document

Creates a tooltip with the specified text.

Usage

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;
}