Beispiel #1
0
    def mouseMoved(self, viewPos):
        """ Updates the probe text with the values under the cursor.
            Draws a vertical line and a symbol at the position of the probe.
        """
        try:
            check_class(viewPos, QtCore.QPointF)
            show_data_point = False  # shows the data point as a circle in the cross hair plots
            self.crossPlotRow, self.crossPlotCol = None, None

            self.probeLabel.setText(
                "<span style='color: #808080'>No data at cursor</span>")
            self.crossLineHorizontal.setVisible(False)
            self.crossLineVertical.setVisible(False)
            self.crossLineHorShadow.setVisible(False)
            self.crossLineVerShadow.setVisible(False)

            self.horCrossPlotItem.clear()
            self.verCrossPlotItem.clear()

            if self.slicedArray is not None and self.viewBox.sceneBoundingRect(
            ).contains(viewPos):

                # Calculate the row and column at the cursor.
                scenePos = self.viewBox.mapSceneToView(viewPos)
                row, col = round(scenePos.y()), round(scenePos.x())
                row, col = int(row), int(col)  # Needed in Python 2
                nRows, nCols = self.slicedArray.shape

                if (0 <= row < nRows) and (0 <= col < nCols):
                    self.viewBox.setCursor(Qt.CrossCursor)

                    self.crossPlotRow, self.crossPlotCol = row, col
                    index = tuple([row, col])
                    valueStr = to_string(self.slicedArray.data[index],
                                         masked=self.slicedArray.maskAt(index),
                                         maskFormat='&lt;masked&gt;')

                    txt = "({}, {}) = ({:d}, {:d}) {} {} = {}".format(
                        self.collector.rtiInfo['x-dim'],
                        self.collector.rtiInfo['y-dim'], col, row, RIGHT_ARROW,
                        self.collector.rtiInfo['name'], valueStr)
                    self.probeLabel.setText(txt)

                    # Show cross section at the cursor pos in the line plots
                    if self.config.horCrossPlotCti.configValue:
                        self.crossLineHorShadow.setVisible(True)
                        self.crossLineHorizontal.setVisible(True)
                        self.crossLineHorShadow.setPos(row)
                        self.crossLineHorizontal.setPos(row)

                        # Line plot of cross section row.
                        # First determine which points are connected or separated by masks/nans.
                        rowData = self.slicedArray.data[row, :]
                        connected = np.isfinite(rowData)
                        if is_an_array(self.slicedArray.mask):
                            connected = np.logical_and(
                                connected, ~self.slicedArray.mask[row, :])
                        else:
                            connected = (np.zeros_like(rowData) if
                                         self.slicedArray.mask else connected)

                        # Replace mask by Nans. Only doing when not showing lines to hack around PyQtGraph issue 1057
                        # See comment in PgLinePlot1d._drawContents for a more detailed explanation
                        # TODO: reuse imageItem data array when this hack is no longer necessary
                        if not self.config.crossPenCti.lineCti.configValue:
                            rowData = replaceMaskedValueWithFloat(
                                rowData,
                                np.logical_not(connected),
                                np.nan,
                                copyOnReplace=True)

                        # Replace infinite value with nans because PyQtGraph can't handle them
                        rowData = replaceMaskedValueWithFloat(
                            rowData,
                            np.isinf(rowData),
                            np.nan,
                            copyOnReplace=True)

                        horPlotDataItem = self.config.crossPenCti.createPlotDataItem(
                        )
                        # TODO: try to use connect='finite' when the hack above is no longer necessary. In that case
                        # test with array_masked test data
                        horPlotDataItem.setData(rowData, connect=connected)
                        self.horCrossPlotItem.addItem(horPlotDataItem)

                        # Vertical line in hor-cross plot
                        crossLineShadow90 = pg.InfiniteLine(
                            angle=90, movable=False, pen=self.crossShadowPen)
                        crossLineShadow90.setPos(col)
                        self.horCrossPlotItem.addItem(crossLineShadow90,
                                                      ignoreBounds=True)
                        crossLine90 = pg.InfiniteLine(angle=90,
                                                      movable=False,
                                                      pen=self.crossPen)
                        crossLine90.setPos(col)
                        self.horCrossPlotItem.addItem(crossLine90,
                                                      ignoreBounds=True)

                        if show_data_point:
                            crossPoint90 = pg.PlotDataItem(
                                symbolPen=self.crossPen)
                            crossPoint90.setSymbolBrush(
                                QtGui.QBrush(self.config.crossPenCti.penColor))
                            crossPoint90.setSymbolSize(10)
                            crossPoint90.setData((col, ), (rowData[col], ))
                            self.horCrossPlotItem.addItem(crossPoint90,
                                                          ignoreBounds=True)

                        self.config.horCrossPlotRangeCti.updateTarget(
                        )  # update auto range
                        del rowData  # defensive programming

                    if self.config.verCrossPlotCti.configValue:
                        self.crossLineVerShadow.setVisible(True)
                        self.crossLineVertical.setVisible(True)
                        self.crossLineVerShadow.setPos(col)
                        self.crossLineVertical.setPos(col)

                        # Line plot of cross section row.
                        # First determine which points are connected or separated by masks/nans.
                        colData = self.slicedArray.data[:, col]
                        connected = np.isfinite(colData)
                        if is_an_array(self.slicedArray.mask):
                            connected = np.logical_and(
                                connected, ~self.slicedArray.mask[:, col])
                        else:
                            connected = (np.zeros_like(colData) if
                                         self.slicedArray.mask else connected)

                        # Replace mask by Nans. Only doing when not showing lines to hack around PyQtGraph issue 1057
                        # See comment in PgLinePlot1d._drawContents for a more detailed explanation
                        if not self.config.crossPenCti.lineCti.configValue:
                            colData = replaceMaskedValueWithFloat(
                                colData,
                                np.logical_not(connected),
                                np.nan,
                                copyOnReplace=True)

                        # Replace infinite value with nans because PyQtGraph can't handle them
                        colData = replaceMaskedValueWithFloat(
                            colData,
                            np.isinf(colData),
                            np.nan,
                            copyOnReplace=True)

                        verPlotDataItem = self.config.crossPenCti.createPlotDataItem(
                        )
                        verPlotDataItem.setData(colData,
                                                np.arange(nRows),
                                                connect=connected)
                        self.verCrossPlotItem.addItem(verPlotDataItem)

                        # Horizontal line in ver-cross plot
                        crossLineShadow0 = pg.InfiniteLine(
                            angle=0, movable=False, pen=self.crossShadowPen)
                        crossLineShadow0.setPos(row)
                        self.verCrossPlotItem.addItem(crossLineShadow0,
                                                      ignoreBounds=True)
                        crossLine0 = pg.InfiniteLine(angle=0,
                                                     movable=False,
                                                     pen=self.crossPen)
                        crossLine0.setPos(row)
                        self.verCrossPlotItem.addItem(crossLine0,
                                                      ignoreBounds=True)

                        if show_data_point:
                            crossPoint0 = pg.PlotDataItem(
                                symbolPen=self.crossPen)
                            crossPoint0.setSymbolBrush(
                                QtGui.QBrush(self.config.crossPenCti.penColor))
                            crossPoint0.setSymbolSize(10)
                            crossPoint0.setData((colData[row], ), (row, ))
                            self.verCrossPlotItem.addItem(crossPoint0,
                                                          ignoreBounds=True)

                        self.config.verCrossPlotRangeCti.updateTarget(
                        )  # update auto range
                        del colData  # defensive programming

        except Exception as ex:
            # In contrast to _drawContents, this function is a slot and thus must not throw
            # exceptions. The exception is logged. Perhaps we should clear the cross plots, but
            # this could, in turn, raise exceptions.
            if DEBUGGING:
                raise
            else:
                logger.exception(ex)
Beispiel #2
0
    def _drawContents(self, reason=None, initiator=None):
        """ Draws the plot contents from the sliced array of the collected repo tree item.

            The reason parameter is used to determine if the axes will be reset (the initiator
            parameter is ignored). See AbstractInspector.updateContents for their description.
        """

        # If auto-reset is true, reset config complete or partially, depending on the mode.
        if self._resetRequired(reason, initiator):
            self.resetConfig()

        self.crossPlotRow = None  # reset because the sliced array shape may change
        self.crossPlotCol = None  # idem dito

        gridLayout = self.graphicsLayoutWidget.ci.layout  # A QGraphicsGridLayout

        if self.config.horCrossPlotCti.configValue:
            gridLayout.setRowStretchFactor(ROW_HOR_LINE, 1)
            if not self.horPlotAdded:
                self.graphicsLayoutWidget.addItem(self.horCrossPlotItem,
                                                  ROW_HOR_LINE, COL_HOR_LINE)
                self.horPlotAdded = True
                gridLayout.activate()
        else:
            gridLayout.setRowStretchFactor(ROW_HOR_LINE, 0)
            if self.horPlotAdded:
                self.graphicsLayoutWidget.removeItem(self.horCrossPlotItem)
                self.horPlotAdded = False
                gridLayout.activate()

        if self.config.verCrossPlotCti.configValue:
            gridLayout.setColumnStretchFactor(COL_VER_LINE, 1)
            if not self.verPlotAdded:
                self.graphicsLayoutWidget.addItem(self.verCrossPlotItem,
                                                  ROW_VER_LINE, COL_VER_LINE)
                self.verPlotAdded = True
                gridLayout.activate()
        else:
            gridLayout.setColumnStretchFactor(COL_VER_LINE, 0)
            if self.verPlotAdded:
                self.graphicsLayoutWidget.removeItem(self.verCrossPlotItem)
                self.verPlotAdded = False
                gridLayout.activate()

        slicedArray = self.collector.getSlicedArray()
        if slicedArray is None:
            self._clearContents()
            raise InvalidDataError()  # Don't show message, to common.
        elif not array_has_real_numbers(slicedArray.data):
            self._clearContents()
            raise InvalidDataError("Selected item contains {} data.".format(
                array_kind_label(slicedArray.data)))
        else:
            self.slicedArray = slicedArray

        # -- Valid plot data from here on --

        if self.config.crossPlotGroupCti.checkState != Qt.Unchecked:
            tempPlotDataItem = self.config.crossPenCti.createPlotDataItem()
            if tempPlotDataItem.opts['pen'] is None and tempPlotDataItem.opts[
                    'symbol'] is None:
                self.sigShowMessage.emit(
                    "The cross-hair pen 'line' and 'symbol' config options are both unchecked!"
                )

        numElem = np.prod(self.slicedArray.data.shape)
        if numElem == 0:
            self.sigShowMessage.emit(
                "Current slice is empty.")  # Not expected to happen.
        elif numElem == 1:
            self.sigShowMessage.emit(
                "Current slice contains only a single data point.")

        # PyQtGraph doesn't handle masked arrays so we convert the masked values to Nans. Missing
        # data values are replaced by NaNs. The PyQtGraph image plot shows this as the color at the
        # lowest end of the color scale. Unfortunately we cannot choose a missing-value color, but
        # at least the Nans do not influence for the histogram and color range.
        # We don't update self.slicedArray here because the data probe should still be able to
        # print the actual value.
        imageArray = replaceMaskedValueWithFloat(self.slicedArray.data,
                                                 self.slicedArray.mask,
                                                 np.nan,
                                                 copyOnReplace=True)

        # Replace infinite value with Nans because PyQtGraph fails on them. Note that the CTIs of
        # the cross plots (e.g. horCrossPlotRangeCti) are still connected to self.slicedArray, so
        # if the cross section consists of only infs, they may not able to update the autorange.
        # A warning is issued in that case.
        # We don't update self.slicedArray here because the data probe should still be able to
        # print the actual value.
        imageArray = replaceMaskedValueWithFloat(imageArray,
                                                 np.isinf(
                                                     self.slicedArray.data),
                                                 np.nan,
                                                 copyOnReplace=True)

        # PyQtGraph uses the following dimension order: T, X, Y, Color.
        # We need to transpose the slicedArray ourselves because axes = {'x':1, 'y':0}
        # doesn't seem to do anything.
        imageArray = imageArray.transpose()

        # Set the _wasIntegerData to True if the original data type was a signed or unsigned. This
        # allows the ArgosColorLegendItem to make histogram bins as if it were an integer
        self.imageItem._wasIntegerData = self.slicedArray.data.dtype.kind in 'ui'
        self.imageItem.setAutoDownsample(
            self.config.autoDownSampleCti.configValue)
        self.imageItem.setImage(
            imageArray, autoLevels=False)  # Do after _wasIntegerData is set!

        self.imagePlotItem.setRectangleZoomOn(
            self.config.zoomModeCti.configValue)

        # Always use pan mode in the cross plots. Rectangle zoom is akward there and it's nice to
        # still be able to pan.
        #self.horCrossPlotItem.setRectangleZoomOn(self.config.zoomModeCti.configValue)
        #self.verCrossPlotItem.setRectangleZoomOn(self.config.zoomModeCti.configValue)

        self.horCrossPlotItem.invertX(self.config.xFlippedCti.configValue)
        self.verCrossPlotItem.invertY(self.config.yFlippedCti.configValue)

        self.probeLabel.setVisible(self.config.probeCti.configValue)

        self.titleLabel.setText(
            self.configValue('title').format(**self.collector.rtiInfo))

        # self.config.logBranch()
        self.config.updateTarget()
Beispiel #3
0
    def _drawContents(self, reason=None, initiator=None):
        """ Draws the plot contents from the sliced array of the collected repo tree item.

            The reason parameter is used to determine if the axes will be reset (the initiator
            parameter is ignored). See AbstractInspector.updateContents for their description.
        """
        self.crossPlotRow = None # reset because the sliced array shape may change
        self.crossPlotCol = None # idem dito

        gridLayout = self.graphicsLayoutWidget.ci.layout # A QGraphicsGridLayout

        if self.config.horCrossPlotCti.configValue:
            gridLayout.setRowStretchFactor(ROW_HOR_LINE, 1)
            if not self.horPlotAdded:
                self.graphicsLayoutWidget.addItem(self.horCrossPlotItem, ROW_HOR_LINE, COL_HOR_LINE)
                self.horPlotAdded = True
                gridLayout.activate()
        else:
            gridLayout.setRowStretchFactor(ROW_HOR_LINE, 0)
            if self.horPlotAdded:
                self.graphicsLayoutWidget.removeItem(self.horCrossPlotItem)
                self.horPlotAdded = False
                gridLayout.activate()

        if self.config.verCrossPlotCti.configValue:
            gridLayout.setColumnStretchFactor(COL_VER_LINE, 1)
            if not self.verPlotAdded:
                self.graphicsLayoutWidget.addItem(self.verCrossPlotItem, ROW_VER_LINE, COL_VER_LINE)
                self.verPlotAdded = True
                gridLayout.activate()
        else:
            gridLayout.setColumnStretchFactor(COL_VER_LINE, 0)
            if self.verPlotAdded:
                self.graphicsLayoutWidget.removeItem(self.verCrossPlotItem)
                self.verPlotAdded = False
                gridLayout.activate()

        self.slicedArray = self.collector.getSlicedArray()

        if not self._hasValidData():
            self._clearContents()
            raise InvalidDataError("No data available or it does not contain real numbers")

        # -- Valid plot data from here on --

        # PyQtGraph doesn't handle masked array so we convert the masked values to Nans. Missing
        # data values are replaced by NaNs. The PyQtGraph image plot shows this as the color at the
        # lowest end of the color scale. Unfortunately we cannot choose a missing-value color, but
        # at least the Nans do not influence for the histogram and color range.
        # We don't update self.slicedArray here because the data probe should still be able to
        # print the actual value.
        imageArray = replaceMaskedValueWithFloat(self.slicedArray.data, self.slicedArray.mask,
                                                 np.nan, copyOnReplace=True)

        # Replace infinite value with Nans because PyQtGraph fails on them. WNote that the CTIs of
        # the cross plots (e.g. horCrossPlotRangeCti) are still connected to self.slicedArray, so
        # if the cross section consists of only infs, they may not able to update the autorange.
        # A warning is issued in that case.
        # We don't update self.slicedArray here because the data probe should still be able to
        # print the actual value.
        imageArray = replaceMaskedValueWithFloat(imageArray, np.isinf(self.slicedArray.data),
                                                 np.nan, copyOnReplace=True)

        # Reset the axes ranges (via the config)
        if (reason == UpdateReason.RTI_CHANGED or
            reason == UpdateReason.COLLECTOR_COMBO_BOX):
            self.config.xAxisRangeCti.autoRangeCti.data = True
            self.config.yAxisRangeCti.autoRangeCti.data = True
            self.config.histColorRangeCti.autoRangeCti.data = True
            self.config.histRangeCti.autoRangeCti.data = True
            self.config.horCrossPlotRangeCti.autoRangeCti.data = True
            self.config.verCrossPlotRangeCti.autoRangeCti.data = True

        # PyQtGraph uses the following dimension order: T, X, Y, Color.
        # We need to transpose the slicedArray ourselves because axes = {'x':1, 'y':0}
        # doesn't seem to do anything.
        imageArray = imageArray.transpose()
        self.imageItem.setImage(imageArray, autoLevels=False)

        self.horCrossPlotItem.invertX(self.config.xFlippedCti.configValue)
        self.verCrossPlotItem.invertY(self.config.yFlippedCti.configValue)

        self.probeLabel.setVisible(self.config.probeCti.configValue)

        self.titleLabel.setText(self.configValue('title').format(**self.collector.rtiInfo))

        # Update the config tree from the (possibly) new state of the PgImagePlot2d inspector,
        # e.g. the axis range or color range may have changed while drawing.
        self.config.updateTarget()
Beispiel #4
0
    def mouseMoved(self, viewPos):
        """ Updates the probe text with the values under the cursor.
            Draws a vertical line and a symbol at the position of the probe.
        """
        try:
            check_class(viewPos, QtCore.QPointF)
            show_data_point = False # shows the data point as a circle in the cross hair plots
            self.crossPlotRow, self.crossPlotCol = None, None

            self.probeLabel.setText("<span style='color: #808080'>no data at cursor</span>")
            self.crossLineHorizontal.setVisible(False)
            self.crossLineVertical.setVisible(False)
            self.crossLineHorShadow.setVisible(False)
            self.crossLineVerShadow.setVisible(False)

            self.horCrossPlotItem.clear()
            self.verCrossPlotItem.clear()

            if (self._hasValidData() and self.slicedArray is not None
                and self.viewBox.sceneBoundingRect().contains(viewPos)):

                # Calculate the row and column at the cursor. We use math.floor because the pixel
                # corners of the image lie at integer values (and not the centers of the pixels).
                scenePos = self.viewBox.mapSceneToView(viewPos)
                row, col = math.floor(scenePos.y()), math.floor(scenePos.x())
                row, col = int(row), int(col) # Needed in Python 2
                nRows, nCols = self.slicedArray.shape

                if (0 <= row < nRows) and (0 <= col < nCols):
                    self.viewBox.setCursor(Qt.CrossCursor)

                    self.crossPlotRow, self.crossPlotCol = row, col
                    index = tuple([row, col])
                    valueStr = to_string(self.slicedArray[index],
                                         masked=self.slicedArray.maskAt(index),
                                         maskFormat='&lt;masked&gt;')
                    txt = "pos = ({:d}, {:d}), value = {}".format(row, col, valueStr)
                    self.probeLabel.setText(txt)

                    # Show cross section at the cursor pos in the line plots
                    if self.config.horCrossPlotCti.configValue:
                        self.crossLineHorShadow.setVisible(True)
                        self.crossLineHorizontal.setVisible(True)
                        self.crossLineHorShadow.setPos(row)
                        self.crossLineHorizontal.setPos(row)

                        # Line plot of cross section row.
                        # First determine which points are connected or separated by masks/nans.
                        rowData = self.slicedArray.data[row, :]
                        connected = np.isfinite(rowData)
                        if is_an_array(self.slicedArray.mask):
                            connected = np.logical_and(connected, ~self.slicedArray.mask[row, :])
                        else:
                            connected = (np.zeros_like(rowData)
                                         if self.slicedArray.mask else connected)

                        # Replace infinite value with nans because PyQtGraph can't handle them
                        rowData = replaceMaskedValueWithFloat(rowData, np.isinf(rowData),
                                                              np.nan, copyOnReplace=True)

                        horPlotDataItem = self.config.crossPenCti.createPlotDataItem()
                        horPlotDataItem.setData(rowData, connect=connected)
                        self.horCrossPlotItem.addItem(horPlotDataItem)

                        # Vertical line in hor-cross plot
                        crossLineShadow90 = pg.InfiniteLine(angle=90, movable=False,
                                                            pen=self.crossShadowPen)
                        crossLineShadow90.setPos(col)
                        self.horCrossPlotItem.addItem(crossLineShadow90, ignoreBounds=True)
                        crossLine90 = pg.InfiniteLine(angle=90, movable=False, pen=self.crossPen)
                        crossLine90.setPos(col)
                        self.horCrossPlotItem.addItem(crossLine90, ignoreBounds=True)

                        if show_data_point:
                            crossPoint90 = pg.PlotDataItem(symbolPen=self.crossPen)
                            crossPoint90.setSymbolBrush(QtGui.QBrush(self.config.crossPenCti.penColor))
                            crossPoint90.setSymbolSize(10)
                            crossPoint90.setData((col,), (rowData[col],))
                            self.horCrossPlotItem.addItem(crossPoint90, ignoreBounds=True)

                        self.config.horCrossPlotRangeCti.updateTarget() # update auto range
                        del rowData # defensive programming

                    if self.config.verCrossPlotCti.configValue:
                        self.crossLineVerShadow.setVisible(True)
                        self.crossLineVertical.setVisible(True)
                        self.crossLineVerShadow.setPos(col)
                        self.crossLineVertical.setPos(col)

                        # Line plot of cross section row.
                        # First determine which points are connected or separated by masks/nans.
                        colData = self.slicedArray.data[:, col]
                        connected = np.isfinite(colData)
                        if is_an_array(self.slicedArray.mask):
                            connected = np.logical_and(connected, ~self.slicedArray.mask[:, col])
                        else:
                            connected = (np.zeros_like(colData)
                                         if self.slicedArray.mask else connected)

                        # Replace infinite value with nans because PyQtGraph can't handle them
                        colData = replaceMaskedValueWithFloat(colData, np.isinf(colData),
                                                              np.nan, copyOnReplace=True)

                        verPlotDataItem = self.config.crossPenCti.createPlotDataItem()
                        verPlotDataItem.setData(colData, np.arange(nRows), connect=connected)
                        self.verCrossPlotItem.addItem(verPlotDataItem)

                        # Horizontal line in ver-cross plot
                        crossLineShadow0 = pg.InfiniteLine(angle=0, movable=False,
                                                           pen=self.crossShadowPen)
                        crossLineShadow0.setPos(row)
                        self.verCrossPlotItem.addItem(crossLineShadow0, ignoreBounds=True)
                        crossLine0 = pg.InfiniteLine(angle=0, movable=False, pen=self.crossPen)
                        crossLine0.setPos(row)
                        self.verCrossPlotItem.addItem(crossLine0, ignoreBounds=True)

                        if show_data_point:
                            crossPoint0 = pg.PlotDataItem(symbolPen=self.crossPen)
                            crossPoint0.setSymbolBrush(QtGui.QBrush(self.config.crossPenCti.penColor))
                            crossPoint0.setSymbolSize(10)
                            crossPoint0.setData((colData[row],), (row,))
                            self.verCrossPlotItem.addItem(crossPoint0, ignoreBounds=True)

                        self.config.verCrossPlotRangeCti.updateTarget() # update auto range
                        del colData # defensive programming

        except Exception as ex:
            # In contrast to _drawContents, this function is a slot and thus must not throw
            # exceptions. The exception is logged. Perhaps we should clear the cross plots, but
            # this could, in turn, raise exceptions.
            if DEBUGGING:
                raise
            else:
                logger.exception(ex)
Beispiel #5
0
    def _drawContents(self, reason=None, initiator=None):
        """ Draws the plot contents from the sliced array of the collected repo tree item.

            The reason parameter is used to determine if the axes will be reset (the initiator
            parameter is ignored). See AbstractInspector.updateContents for their description.
        """
        self.crossPlotRow = None  # reset because the sliced array shape may change
        self.crossPlotCol = None  # idem dito

        gridLayout = self.graphicsLayoutWidget.ci.layout  # A QGraphicsGridLayout

        if self.config.horCrossPlotCti.configValue:
            gridLayout.setRowStretchFactor(ROW_HOR_LINE, 1)
            if not self.horPlotAdded:
                self.graphicsLayoutWidget.addItem(self.horCrossPlotItem,
                                                  ROW_HOR_LINE, COL_HOR_LINE)
                self.horPlotAdded = True
                gridLayout.activate()
        else:
            gridLayout.setRowStretchFactor(ROW_HOR_LINE, 0)
            if self.horPlotAdded:
                self.graphicsLayoutWidget.removeItem(self.horCrossPlotItem)
                self.horPlotAdded = False
                gridLayout.activate()

        if self.config.verCrossPlotCti.configValue:
            gridLayout.setColumnStretchFactor(COL_VER_LINE, 1)
            if not self.verPlotAdded:
                self.graphicsLayoutWidget.addItem(self.verCrossPlotItem,
                                                  ROW_VER_LINE, COL_VER_LINE)
                self.verPlotAdded = True
                gridLayout.activate()
        else:
            gridLayout.setColumnStretchFactor(COL_VER_LINE, 0)
            if self.verPlotAdded:
                self.graphicsLayoutWidget.removeItem(self.verCrossPlotItem)
                self.verPlotAdded = False
                gridLayout.activate()

        self.slicedArray = self.collector.getSlicedArray()

        if not self._hasValidData():
            self._clearContents()
            raise InvalidDataError(
                "No data available or it does not contain real numbers")

        # -- Valid plot data from here on --

        # PyQtGraph doesn't handle masked array so we convert the masked values to Nans. Missing
        # data values are replaced by NaNs. The PyQtGraph image plot shows this as the color at the
        # lowest end of the color scale. Unfortunately we cannot choose a missing-value color, but
        # at least the Nans do not influence for the histogram and color range.
        # We don't update self.slicedArray here because the data probe should still be able to
        # print the actual value.
        imageArray = replaceMaskedValueWithFloat(self.slicedArray.data,
                                                 self.slicedArray.mask,
                                                 np.nan,
                                                 copyOnReplace=True)

        # Replace infinite value with Nans because PyQtGraph fails on them. WNote that the CTIs of
        # the cross plots (e.g. horCrossPlotRangeCti) are still connected to self.slicedArray, so
        # if the cross section consists of only infs, they may not able to update the autorange.
        # A warning is issued in that case.
        # We don't update self.slicedArray here because the data probe should still be able to
        # print the actual value.
        imageArray = replaceMaskedValueWithFloat(imageArray,
                                                 np.isinf(
                                                     self.slicedArray.data),
                                                 np.nan,
                                                 copyOnReplace=True)

        # Reset the axes ranges (via the config)
        if (reason == UpdateReason.RTI_CHANGED
                or reason == UpdateReason.COLLECTOR_COMBO_BOX):
            self.config.xAxisRangeCti.autoRangeCti.data = True
            self.config.yAxisRangeCti.autoRangeCti.data = True
            self.config.histColorRangeCti.autoRangeCti.data = True
            self.config.histRangeCti.autoRangeCti.data = True
            self.config.horCrossPlotRangeCti.autoRangeCti.data = True
            self.config.verCrossPlotRangeCti.autoRangeCti.data = True

        # PyQtGraph uses the following dimension order: T, X, Y, Color.
        # We need to transpose the slicedArray ourselves because axes = {'x':1, 'y':0}
        # doesn't seem to do anything.
        imageArray = imageArray.transpose()
        self.imageItem.setImage(imageArray, autoLevels=False)

        self.horCrossPlotItem.invertX(self.config.xFlippedCti.configValue)
        self.verCrossPlotItem.invertY(self.config.yFlippedCti.configValue)

        self.probeLabel.setVisible(self.config.probeCti.configValue)

        self.titleLabel.setText(
            self.configValue('title').format(**self.collector.rtiInfo))

        # Update the config tree from the (possibly) new state of the PgImagePlot2d inspector,
        # e.g. the axis range or color range may have changed while drawing.
        self.config.updateTarget()