summaryrefslogtreecommitdiff
path: root/silx/gui/plot/Profile.py
diff options
context:
space:
mode:
Diffstat (limited to 'silx/gui/plot/Profile.py')
-rw-r--r--silx/gui/plot/Profile.py109
1 files changed, 66 insertions, 43 deletions
diff --git a/silx/gui/plot/Profile.py b/silx/gui/plot/Profile.py
index 182cf60..46e4523 100644
--- a/silx/gui/plot/Profile.py
+++ b/silx/gui/plot/Profile.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2004-2018 European Synchrotron Radiation Facility
+# Copyright (c) 2004-2019 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -180,7 +180,8 @@ def createProfile(roiInfo, currentData, origin, scale, lineWidth, method):
:type scale: 2-tuple of float
:param int lineWidth: width of the profile line
:param str method: method to compute the profile. Can be 'mean' or 'sum'
- :return: `profile, area, profileName, xLabel`, where:
+ :return: `coords, profile, area, profileName, xLabel`, where:
+ - coords is the X coordinate to use to display the profile
- profile is a 2D array of the profiles of the stack of images.
For a single image, the profile is a curve, so this parameter
has a shape *(1, len(curve))*
@@ -188,10 +189,9 @@ def createProfile(roiInfo, currentData, origin, scale, lineWidth, method):
the effective ROI area corners in plot coords.
- profileName is a string describing the ROI, meant to be used as
title of the profile plot
- - xLabel is a string describing the meaning of the X axis on the
- profile plot ("rows", "columns", "distance")
+ - xLabel the label for X in the profile window
- :rtype: tuple(ndarray, (ndarray, ndarray), str, str)
+ :rtype: tuple(ndarray,ndarray,(ndarray,ndarray),str)
"""
if currentData is None or roiInfo is None or lineWidth is None:
raise ValueError("createProfile called with invalide arguments")
@@ -212,12 +212,15 @@ def createProfile(roiInfo, currentData, origin, scale, lineWidth, method):
axis=0,
method=method)
+ coords = numpy.arange(len(profile[0]), dtype=numpy.float32)
+ coords = coords * scale[0] + origin[0]
+
yMin, yMax = min(area[1]), max(area[1]) - 1
if roiWidth <= 1:
profileName = 'Y = %g' % yMin
else:
profileName = 'Y = [%g, %g]' % (yMin, yMax)
- xLabel = 'Columns'
+ xLabel = 'X'
elif lineProjectionMode == 'Y': # Vertical profile on the whole image
profile, area = _alignedFullProfile(currentData3D,
@@ -226,12 +229,15 @@ def createProfile(roiInfo, currentData, origin, scale, lineWidth, method):
axis=1,
method=method)
+ coords = numpy.arange(len(profile[0]), dtype=numpy.float32)
+ coords = coords * scale[1] + origin[1]
+
xMin, xMax = min(area[0]), max(area[0]) - 1
if roiWidth <= 1:
profileName = 'X = %g' % xMin
else:
profileName = 'X = [%g, %g]' % (xMin, xMax)
- xLabel = 'Rows'
+ xLabel = 'Y'
else: # Free line profile
@@ -306,35 +312,52 @@ def createProfile(roiInfo, currentData, origin, scale, lineWidth, method):
dCol = (endPt[1] - startPt[1]) / length
# Extend ROI with half a pixel on each end
- startPt = startPt[0] - 0.5 * dRow, startPt[1] - 0.5 * dCol
- endPt = endPt[0] + 0.5 * dRow, endPt[1] + 0.5 * dCol
+ roiStartPt = startPt[0] - 0.5 * dRow, startPt[1] - 0.5 * dCol
+ roiEndPt = endPt[0] + 0.5 * dRow, endPt[1] + 0.5 * dCol
# Rotate deltas by 90 degrees to apply line width
dRow, dCol = dCol, -dRow
area = (
- numpy.array((startPt[1] - 0.5 * roiWidth * dCol,
- startPt[1] + 0.5 * roiWidth * dCol,
- endPt[1] + 0.5 * roiWidth * dCol,
- endPt[1] - 0.5 * roiWidth * dCol),
+ numpy.array((roiStartPt[1] - 0.5 * roiWidth * dCol,
+ roiStartPt[1] + 0.5 * roiWidth * dCol,
+ roiEndPt[1] + 0.5 * roiWidth * dCol,
+ roiEndPt[1] - 0.5 * roiWidth * dCol),
dtype=numpy.float32) * scale[0] + origin[0],
- numpy.array((startPt[0] - 0.5 * roiWidth * dRow,
- startPt[0] + 0.5 * roiWidth * dRow,
- endPt[0] + 0.5 * roiWidth * dRow,
- endPt[0] - 0.5 * roiWidth * dRow),
+ numpy.array((roiStartPt[0] - 0.5 * roiWidth * dRow,
+ roiStartPt[0] + 0.5 * roiWidth * dRow,
+ roiEndPt[0] + 0.5 * roiWidth * dRow,
+ roiEndPt[0] - 0.5 * roiWidth * dRow),
dtype=numpy.float32) * scale[1] + origin[1])
- y0, x0 = startPt
- y1, x1 = endPt
- if x1 == x0 or y1 == y0:
- profileName = 'From (%g, %g) to (%g, %g)' % (x0, y0, x1, y1)
+ # Convert start and end points back to plot coords
+ y0 = startPt[0] * scale[1] + origin[1]
+ x0 = startPt[1] * scale[0] + origin[0]
+ y1 = endPt[0] * scale[1] + origin[1]
+ x1 = endPt[1] * scale[0] + origin[0]
+
+ if startPt[1] == endPt[1]:
+ profileName = 'X = %g; Y = [%g, %g]' % (x0, y0, y1)
+ coords = numpy.arange(len(profile[0]), dtype=numpy.float32)
+ coords = coords * scale[1] + y0
+ xLabel = 'Y'
+
+ elif startPt[0] == endPt[0]:
+ profileName = 'Y = %g; X = [%g, %g]' % (y0, x0, x1)
+ coords = numpy.arange(len(profile[0]), dtype=numpy.float32)
+ coords = coords * scale[0] + x0
+ xLabel = 'X'
+
else:
m = (y1 - y0) / (x1 - x0)
b = y0 - m * x0
profileName = 'y = %g * x %+g ; width=%d' % (m, b, roiWidth)
- xLabel = 'Distance'
+ coords = numpy.linspace(x0, x1, len(profile[0]),
+ endpoint=True,
+ dtype=numpy.float32)
+ xLabel = 'X'
- return profile, area, profileName, xLabel
+ return coords, profile, area, profileName, xLabel
# ProfileToolBar ##############################################################
@@ -458,7 +481,7 @@ class ProfileToolBar(qt.QToolBar):
self.addWidget(self.lineWidthSpinBox)
self.methodsButton = ProfileOptionToolButton(parent=self, plot=self)
- self.addWidget(self.methodsButton)
+ self.__profileOptionToolAction = self.addWidget(self.methodsButton)
# TODO: add connection with the signal
self.methodsButton.sigMethodChanged.connect(self.setProfileMethod)
@@ -650,7 +673,7 @@ class ProfileToolBar(qt.QToolBar):
if self._roiInfo is None:
return
- profile, area, profileName, xLabel = createProfile(
+ coords, profile, area, profileName, xLabel = createProfile(
roiInfo=self._roiInfo,
currentData=currentData,
origin=origin,
@@ -658,28 +681,25 @@ class ProfileToolBar(qt.QToolBar):
lineWidth=self.lineWidthSpinBox.value(),
method=method)
- self.getProfilePlot().setGraphTitle(profileName)
+ profilePlot = self.getProfilePlot()
+
+ profilePlot.setGraphTitle(profileName)
+ profilePlot.getXAxis().setLabel(xLabel)
dataIs3D = len(currentData.shape) > 2
if dataIs3D:
- self.getProfilePlot().addImage(profile,
- legend=profileName,
- xlabel=xLabel,
- ylabel="Frame index (depth)",
- colormap=colormap)
+ profileScale = (coords[-1] - coords[0]) / profile.shape[1], 1
+ profilePlot.addImage(profile,
+ legend=profileName,
+ colormap=colormap,
+ origin=(coords[0], 0),
+ scale=profileScale)
+ profilePlot.getYAxis().setLabel("Frame index (depth)")
else:
- coords = numpy.arange(len(profile[0]), dtype=numpy.float32)
- # Scale horizontal and vertical profile coordinates
- if self._roiInfo[2] == 'X':
- coords = coords * scale[0] + origin[0]
- elif self._roiInfo[2] == 'Y':
- coords = coords * scale[1] + origin[1]
-
- self.getProfilePlot().addCurve(coords,
- profile[0],
- legend=profileName,
- xlabel=xLabel,
- color=self.overlayColor)
+ profilePlot.addCurve(coords,
+ profile[0],
+ legend=profileName,
+ color=self.overlayColor)
self.plot.addItem(area[0], area[1],
legend=self._POLYGON_LEGEND,
@@ -732,6 +752,9 @@ class ProfileToolBar(qt.QToolBar):
def getProfileMethod(self):
return self._method
+ def getProfileOptionToolAction(self):
+ return self.__profileOptionToolAction
+
class Profile3DToolBar(ProfileToolBar):
def __init__(self, parent=None, stackview=None,