diff options
Diffstat (limited to 'silx/gui/plot/backends/glutils/GLPlotCurve.py')
-rw-r--r-- | silx/gui/plot/backends/glutils/GLPlotCurve.py | 165 |
1 files changed, 149 insertions, 16 deletions
diff --git a/silx/gui/plot/backends/glutils/GLPlotCurve.py b/silx/gui/plot/backends/glutils/GLPlotCurve.py index 5f8d652..3a0ebac 100644 --- a/silx/gui/plot/backends/glutils/GLPlotCurve.py +++ b/silx/gui/plot/backends/glutils/GLPlotCurve.py @@ -132,8 +132,7 @@ class _Fill2D(object): self.xData is not None and self.yData is not None): # Get slices of not NaN values longer than 1 element - isnan = numpy.logical_or(numpy.isnan(self.xData), - numpy.isnan(self.yData)) + isnan = numpy.logical_or(numpy.isnan(self.xData), numpy.isnan(self.yData)) notnan = numpy.logical_not(isnan) start = numpy.where(numpy.logical_and(isnan[:-1], notnan[1:]))[0] + 1 if notnan[0]: @@ -147,22 +146,25 @@ class _Fill2D(object): # Number of points: slice + 2 * leading and trailing points # Twice leading and trailing points to produce degenerated triangles - nbPoints = numpy.sum(numpy.diff(slices, axis=1)) + 4 * len(slices) + nbPoints = numpy.sum(numpy.diff(slices, axis=1)) * 2 + 4 * len(slices) points = numpy.empty((nbPoints, 2), dtype=numpy.float32) offset = 0 + # invert baseline for filling + new_y_data = numpy.append(self.yData, self.baseline) for start, end in slices: # Duplicate first point for connecting degenerated triangle - points[offset:offset+2] = self.xData[start], self.baseline + points[offset:offset+2] = self.xData[start], new_y_data[start] # 2nd point of the polygon is last point - points[offset+2] = self.xData[end-1], self.baseline + points[offset+2] = self.xData[start], self.baseline[start] - # Add all points from the data - indices = start + buildFillMaskIndices(end - start) + indices = numpy.append(numpy.arange(start, end), + numpy.arange(len(self.xData) + end-1, len(self.xData) + start-1, -1)) + indices = indices[buildFillMaskIndices(len(indices))] - points[offset+3:offset+3+len(indices), 0] = self.xData[indices] - points[offset+3:offset+3+len(indices), 1] = self.yData[indices] + points[offset+3:offset+3+len(indices), 0] = self.xData[indices % len(self.xData)] + points[offset+3:offset+3+len(indices), 1] = new_y_data[indices] # Duplicate last point for connecting degenerated triangle points[offset+3+len(indices)] = points[offset+3+len(indices)-1] @@ -526,7 +528,16 @@ def distancesFromArrays(xData, yData): DIAMOND, CIRCLE, SQUARE, PLUS, X_MARKER, POINT, PIXEL, ASTERISK = \ 'd', 'o', 's', '+', 'x', '.', ',', '*' -H_LINE, V_LINE = '_', '|' +H_LINE, V_LINE, HEART = '_', '|', u'\u2665' + +TICK_LEFT = "tickleft" +TICK_RIGHT = "tickright" +TICK_UP = "tickup" +TICK_DOWN = "tickdown" +CARET_LEFT = "caretleft" +CARET_RIGHT = "caretright" +CARET_UP = "caretup" +CARET_DOWN = "caretdown" class _Points2D(object): @@ -542,7 +553,8 @@ class _Points2D(object): """ MARKERS = (DIAMOND, CIRCLE, SQUARE, PLUS, X_MARKER, POINT, PIXEL, ASTERISK, - H_LINE, V_LINE) + H_LINE, V_LINE, HEART, TICK_LEFT, TICK_RIGHT, TICK_UP, TICK_DOWN, + CARET_LEFT, CARET_RIGHT, CARET_UP, CARET_DOWN) """List of supported markers""" _VERTEX_SHADER = """ @@ -640,7 +652,110 @@ class _Points2D(object): return 0.0; } } - """ + """, + HEART: """ + float alphaSymbol(vec2 coord, float size) { + coord = (coord - 0.5) * 2.; + coord *= 0.75; + coord.y += 0.25; + float a = atan(coord.x,-coord.y)/3.141593; + float r = length(coord); + float h = abs(a); + float d = (13.0*h - 22.0*h*h + 10.0*h*h*h)/(6.0-5.0*h); + float res = clamp(r-d, 0., 1.); + // antialiasing + res = smoothstep(0.1, 0.001, res); + return res; + } + """, + TICK_LEFT: """ + float alphaSymbol(vec2 coord, float size) { + coord = size * (coord - 0.5); + float dy = abs(coord.y); + if (dy < 0.5 && coord.x < 0.5) { + return 1.0; + } else { + return 0.0; + } + } + """, + TICK_RIGHT: """ + float alphaSymbol(vec2 coord, float size) { + coord = size * (coord - 0.5); + float dy = abs(coord.y); + if (dy < 0.5 && coord.x > -0.5) { + return 1.0; + } else { + return 0.0; + } + } + """, + TICK_UP: """ + float alphaSymbol(vec2 coord, float size) { + coord = size * (coord - 0.5); + float dx = abs(coord.x); + if (dx < 0.5 && coord.y < 0.5) { + return 1.0; + } else { + return 0.0; + } + } + """, + TICK_DOWN: """ + float alphaSymbol(vec2 coord, float size) { + coord = size * (coord - 0.5); + float dx = abs(coord.x); + if (dx < 0.5 && coord.y > -0.5) { + return 1.0; + } else { + return 0.0; + } + } + """, + CARET_LEFT: """ + float alphaSymbol(vec2 coord, float size) { + coord = size * (coord - 0.5); + float d = abs(coord.x) - abs(coord.y); + if (d >= -0.1 && coord.x > 0.5) { + return smoothstep(-0.1, 0.1, d); + } else { + return 0.0; + } + } + """, + CARET_RIGHT: """ + float alphaSymbol(vec2 coord, float size) { + coord = size * (coord - 0.5); + float d = abs(coord.x) - abs(coord.y); + if (d >= -0.1 && coord.x < 0.5) { + return smoothstep(-0.1, 0.1, d); + } else { + return 0.0; + } + } + """, + CARET_UP: """ + float alphaSymbol(vec2 coord, float size) { + coord = size * (coord - 0.5); + float d = abs(coord.y) - abs(coord.x); + if (d >= -0.1 && coord.y > 0.5) { + return smoothstep(-0.1, 0.1, d); + } else { + return 0.0; + } + } + """, + CARET_DOWN: """ + float alphaSymbol(vec2 coord, float size) { + coord = size * (coord - 0.5); + float d = abs(coord.y) - abs(coord.x); + if (d >= -0.1 && coord.y < 0.5) { + return smoothstep(-0.1, 0.1, d); + } else { + return 0.0; + } + } + """, } _FRAGMENT_SHADER_TEMPLATE = """ @@ -964,6 +1079,7 @@ class GLPlotCurve2D(object): markerColor=(0., 0., 0., 1.), markerSize=7, fillColor=None, + baseline=None, isYLog=False): self.colorData = colorData @@ -1003,11 +1119,28 @@ class GLPlotCurve2D(object): self.offset = 0., 0. self.xData = xData self.yData = yData - if fillColor is not None: + def deduce_baseline(baseline): + if baseline is None: + _baseline = 0 + else: + _baseline = baseline + if not isinstance(_baseline, numpy.ndarray): + _baseline = numpy.repeat(_baseline, + len(self.xData)) + if isYLog is True: + with warnings.catch_warnings(): # Ignore NaN comparison warnings + warnings.simplefilter('ignore', + category=RuntimeWarning) + log_val = numpy.log10(_baseline) + _baseline = numpy.where(_baseline>0.0, log_val, -38) + return _baseline + + _baseline = deduce_baseline(baseline) + # Use different baseline depending of Y log scale self.fill = _Fill2D(self.xData, self.yData, - baseline=-38 if isYLog else 0, + baseline=_baseline, color=fillColor, offset=self.offset) else: @@ -1129,7 +1262,7 @@ class GLPlotCurve2D(object): and the segment [i-1, i] is not tested for picking. :return: The indices of the picked data - :rtype: list of int + :rtype: Union[List[int],None] """ if (self.marker is None and self.lineStyle is None) or \ self.xMin > xPickMax or xPickMin > self.xMax or \ @@ -1209,4 +1342,4 @@ class GLPlotCurve2D(object): (self.yData >= yPickMin) & (self.yData <= yPickMax))[0].tolist() - return indices + return tuple(indices) if len(indices) > 0 else None |