# -*- coding: utf-8 -*-
#
# Copyright © 2009-2010 CEA
# Pierre Raybaut
# Licensed under the terms of the CECILL License
# (see guiqwt/__init__.py for details)
# pylint: disable=C0103
"""
guiqwt.styles
-------------
The `styles` module provides set of parameters (DataSet classes) to
configure `plot items` and `plot tools`.
.. seealso::
Module :py:mod:`guiqwt.plot`
Module providing ready-to-use curve and image plotting widgets and
dialog boxes
Module :py:mod:`guiqwt.curve`
Module providing curve-related plot items and plotting widgets
Module :py:mod:`guiqwt.image`
Module providing image-related plot items and plotting widgets
Module :py:mod:`guiqwt.tools`
Module providing the `plot tools`
Reference
~~~~~~~~~
.. autoclass:: CurveParam
:members:
:inherited-members:
.. autoclass:: ErrorBarParam
:members:
:inherited-members:
.. autoclass:: GridParam
:members:
:inherited-members:
.. autoclass:: ImageParam
:members:
:inherited-members:
.. autoclass:: TrImageParam
:members:
:inherited-members:
.. autoclass:: ImageFilterParam
:members:
:inherited-members:
.. autoclass:: HistogramParam
:members:
:inherited-members:
.. autoclass:: Histogram2DParam
:members:
:inherited-members:
.. autoclass:: AxesParam
:members:
:inherited-members:
.. autoclass:: ImageAxesParam
:members:
:inherited-members:
.. autoclass:: LabelParam
:members:
:inherited-members:
.. autoclass:: LegendParam
:members:
:inherited-members:
.. autoclass:: ShapeParam
:members:
:inherited-members:
.. autoclass:: AnnotationParam
:members:
:inherited-members:
.. autoclass:: AxesShapeParam
:members:
:inherited-members:
.. autoclass:: RangeShapeParam
:members:
:inherited-members:
.. autoclass:: MarkerParam
:members:
:inherited-members:
.. autoclass:: FontParam
:members:
:inherited-members:
.. autoclass:: SymbolParam
:members:
:inherited-members:
.. autoclass:: LineStyleParam
:members:
:inherited-members:
.. autoclass:: BrushStyleParam
:members:
:inherited-members:
.. autoclass:: TextStyleParam
:members:
:inherited-members:
"""
import numpy as np
from qtpy.QtWidgets import QFontDialog
from qtpy.QtGui import QPen, QBrush, QColor, QFont, QTransform
from qtpy.QtCore import Qt, QSizeF, QPointF
from guidata.dataset.datatypes import (
DataSet,
ObjectItem,
BeginGroup,
EndGroup,
Obj,
DataSetGroup,
BeginTabGroup,
EndTabGroup,
GetAttrProp,
NotProp,
)
from guidata.dataset.dataitems import (
ChoiceItem,
BoolItem,
FloatItem,
IntItem,
ImageChoiceItem,
ColorItem,
StringItem,
ButtonItem,
FloatArrayItem,
TextItem,
)
from guidata.dataset.qtwidgets import DataSetEditLayout
from guidata.dataset.qtitemwidgets import DataSetWidget
from guidata.utils import update_dataset
# Local imports
from guiqwt.transitional import QwtPlot, QwtPlotCurve, QwtSymbol, QwtPlotMarker
from guiqwt.config import _
from guiqwt.colormap import get_colormap_list, build_icon_from_cmap_name
class ItemParameters(object):
"""Class handling QwtPlotItem-like parameters"""
MULTISEL_DATASETS = []
# Customizing tab display order:
ENDING_PARAMETERS = (
"CurveParam",
"ErrorBarParam",
"ShapeParam",
"LabelParam",
"LegendParam",
"GridParam",
"AxesParam",
)
def __init__(self, multiselection=False):
self.multiselection = multiselection
self.paramdict = {}
self.items = set()
@classmethod
def register_multiselection(cls, klass, klass_ms):
"""Register a DataSet couple: (DataSet, DataSet_for_MultiSelection)"""
# Inserting element backwards because classes have to be registered
# from children to parent (see 'add' method to fully understand why)
cls.MULTISEL_DATASETS.insert(0, (klass, klass_ms))
def __add(self, key, item, param):
self.paramdict[key] = param
self.items.add(item)
def add(self, key, item, param):
if self.multiselection:
for klass, klass_ms in self.MULTISEL_DATASETS:
if isinstance(param, klass):
title = param.get_title()
if key in self.paramdict and not title.endswith("s"):
title += "s"
param_ms = klass_ms(
title=title, comment=param.get_comment(), icon=param.get_icon()
)
update_dataset(param_ms, param)
self.__add(key, item, param_ms)
return
self.__add(key, item, param)
def get(self, key):
from copy import deepcopy
return deepcopy(self.paramdict.get(key))
def update(self, plot):
# XXX: removed the following workaround as the associated bug can't be
# reproduced anymore with guiqwt 3. However, keeping the workaround
# here (commented) as it could become useful eventually.
# -----
# FIXME: without the following workaround, ImagePlot object aspect ratio
# is changed when pressing button "Apply"
# (see also guiqwt.image.ImagePlot.edit_axis_parameters)
# from guiqwt.image import ImagePlot
# if isinstance(plot, ImagePlot):
# ratio = plot.get_current_aspect_ratio()
# -----
for item in self.items:
item.set_item_parameters(self)
plot.replot()
# -----
# if isinstance(plot, ImagePlot):
# plot.set_aspect_ratio(ratio=ratio)
# plot.replot()
# -----
plot.SIG_ITEMS_CHANGED.emit(plot)
def edit(self, plot, title, icon):
paramdict = self.paramdict.copy()
ending_parameters = []
for key in self.ENDING_PARAMETERS:
if key in paramdict:
ending_parameters.append(paramdict.pop(key))
parameters = list(paramdict.values()) + ending_parameters
dset = DataSetGroup(parameters, title=title.rstrip("."), icon=icon)
if dset.edit(parent=plot, apply=lambda dset: self.update(plot)):
self.update(plot)
LINESTYLES = {
"-": "SolidLine",
"--": "DashLine",
":": "DotLine",
"-.": "DashDotLine",
}
COLORS = {
"r": "red",
"g": "green",
"b": "blue",
"c": "cyan",
"m": "magenta",
"y": "yellow",
"k": "black",
"w": "white",
"G": "gray",
}
MARKERS = {
"+": QwtSymbol.Cross,
"o": QwtSymbol.Ellipse,
"*": QwtSymbol.Star1,
".": QwtSymbol(QwtSymbol.Ellipse, QBrush(Qt.black), QPen(Qt.black), QSizeF(3, 3)),
"x": QwtSymbol.XCross,
"s": QwtSymbol.Rect,
"d": QwtSymbol.Diamond,
"^": QwtSymbol.UTriangle,
"v": QwtSymbol.DTriangle,
">": QwtSymbol.RTriangle,
"<": QwtSymbol.LTriangle,
"h": QwtSymbol.Star2,
}
MARKERSTYLES = {
None: "NoLine",
"-": "HLine",
"|": "VLine",
"+": "Cross",
}
def style_generator(color_keys="bgrcmykG"):
"""Cycling through curve styles"""
while True:
for linestyle in sorted(LINESTYLES.keys()):
for color in color_keys:
yield color + linestyle
def update_style_attr(style, param):
"""Parse a MATLAB-like style string and
update the color, linestyle, marker attributes of the param
object
"""
for marker in list(MARKERS.keys()):
if marker in style:
param.symbol.update_param(MARKERS[marker])
break
else:
param.symbol.update_param(QwtSymbol.NoSymbol)
for linestyle in list(LINESTYLES.keys()):
if linestyle in style:
param.line.style = LINESTYLES[linestyle]
break
else:
param.line.style = "NoPen"
for color in list(COLORS.keys()):
if color in style:
param.line.color = COLORS[color]
param.symbol.facecolor = COLORS[color]
param.symbol.edgecolor = COLORS[color]
break
def build_reverse_map(lst, obj):
dict = {}
for idx, _name, _icon in lst:
val = getattr(obj, idx)
dict[val] = idx
return dict
LINESTYLE_CHOICES = [
("SolidLine", _("Solid line"), "solid.png"),
("DashLine", _("Dashed line"), "dash.png"),
("DotLine", _("Dotted line"), "dot.png"),
("DashDotLine", _("Dash-dot line"), "dashdot.png"),
("DashDotDotLine", _("Dash-dot-dot line"), "dashdotdot.png"),
("NoPen", _("No line"), "none.png"),
]
MARKER_CHOICES = [
("Cross", _("Cross"), "cross.png"),
("Ellipse", _("Ellipse"), "ellipse.png"),
("Star1", _("Star"), "star.png"),
("XCross", _("X-Cross"), "xcross.png"),
("Rect", _("Square"), "square.png"),
("Diamond", _("Diamond"), "diamond.png"),
("UTriangle", _("Triangle"), "triangle_u.png"),
("DTriangle", _("Triangle"), "triangle_d.png"),
("RTriangle", _("Triangle"), "triangle_r.png"),
("LTriangle", _("Triangle"), "triangle_l.png"),
("Star2", _("Hexagon"), "hexagon.png"),
("NoSymbol", _("No symbol"), "none.png"),
]
CURVESTYLE_CHOICES = [
("Lines", _("Lines"), "lines.png"),
("Sticks", _("Sticks"), "sticks.png"),
("Steps", _("Steps"), "steps.png"),
("Dots", _("Dots"), "dots.png"),
("NoCurve", _("No curve"), "none.png"),
]
BRUSHSTYLE_CHOICES = [
("NoBrush", _("No brush pattern"), "nobrush.png"),
("SolidPattern", _("Uniform color"), "solidpattern.png"),
("Dense1Pattern", _("Extremely dense brush pattern"), "dense1pattern.png"),
("Dense2Pattern", _("Very dense brush pattern"), "dense2pattern.png"),
("Dense3Pattern", _("Somewhat dense brush pattern"), "dense3pattern.png"),
("Dense4Pattern", _("Half dense brush pattern"), "dense4pattern.png"),
("Dense5Pattern", _("Somewhat sparse brush pattern"), "dense5pattern.png"),
("Dense6Pattern", _("Very sparse brush pattern"), "dense6pattern.png"),
("Dense7Pattern", _("Extremely sparse brush pattern"), "dense7pattern.png"),
("HorPattern", _("Horizontal lines"), "horpattern.png"),
("VerPattern", _("Vertical lines"), "verpattern.png"),
("CrossPattern", _("Crossing horizontal and vertical lines"), "crosspattern.png"),
("BDiagPattern", _("Backward diagonal lines"), "bdiagpattern.png"),
("FDiagPattern", _("Forward diagonal lines"), "fdiagpattern.png"),
("DiagCrossPattern", _("Crossing diagonal lines"), "diagcrosspattern.png"),
# ("LinearGradientPattern", _("Linear gradient (set using a dedicated QBrush constructor)"), "none.png"),
# ("ConicalGradientPattern", _("Conical gradient (set using a dedicated QBrush constructor)"), "none.png"),
# ("RadialGradientPattern", _("Radial gradient (set using a dedicated QBrush constructor)"), "none.png"),
# ("TexturePattern", _("Custom pattern (see QBrush::setTexture())"), "none.png"),
]
MARKERSTYLE_CHOICES = [
("NoLine", _("None"), "none.png"),
("HLine", _("Horizontal"), "horiz_marker.png"),
("VLine", _("Vertical"), "vert_marker.png"),
("Cross", _("Cross"), "cross_marker.png"),
]
MARKER_NAME = build_reverse_map(MARKER_CHOICES, QwtSymbol)
CURVESTYLE_NAME = build_reverse_map(CURVESTYLE_CHOICES, QwtPlotCurve)
LINESTYLE_NAME = build_reverse_map(LINESTYLE_CHOICES, Qt)
BRUSHSTYLE_NAME = build_reverse_map(BRUSHSTYLE_CHOICES, Qt)
MARKERSTYLE_NAME = build_reverse_map(MARKERSTYLE_CHOICES, QwtPlotMarker)
# ===================================================
# Common font parameters
# ===================================================
def _font_selection(param, item, value, parent):
font = param.build_font()
result, valid = QFontDialog.getFont(font, parent)
if valid:
param.update_param(result)
[docs]class FontParam(DataSet):
family = StringItem(_("Family"), default="default")
_choose = ButtonItem(_("Choose font"), _font_selection, default=None).set_pos(col=1)
size = IntItem(_("Size in point"), default=12)
bold = BoolItem(_("Bold"), default=False).set_pos(col=1)
italic = BoolItem(_("Italic"), default=False).set_pos(col=2)
def update_param(self, font):
self.family = str(font.family())
self.size = font.pointSize()
self.bold = bool(font.bold())
self.italic = bool(font.italic())
def build_font(self):
font = QFont(self.family)
font.setPointSize(self.size)
font.setBold(self.bold)
font.setItalic(self.italic)
return font
class FontItemWidget(DataSetWidget):
klass = FontParam
class FontItem(ObjectItem):
"""Item holding a LineStyleParam"""
klass = FontParam
DataSetEditLayout.register(FontItem, FontItemWidget)
# ===================================================
# Common Qwt symbol parameters
# ===================================================
[docs]class SymbolParam(DataSet):
marker = ImageChoiceItem(_("Style"), MARKER_CHOICES, default="NoSymbol")
size = IntItem(_("Size"), default=9)
edgecolor = ColorItem(_("Border"), default="gray")
facecolor = ColorItem(_("Background color"), default="yellow")
alpha = FloatItem(_("Background alpha"), default=1.0, min=0, max=1)
def update_param(self, symb):
if not isinstance(symb, QwtSymbol):
# check if this is still needed
# raise RuntimeError
assert isinstance(symb, QwtSymbol.Style)
self.marker = MARKER_NAME[symb]
return
self.marker = MARKER_NAME[symb.style()]
self.size = symb.size().width()
self.edgecolor = str(symb.pen().color().name())
self.facecolor = str(symb.brush().color().name())
def build_symbol(self):
marker_type = getattr(QwtSymbol, self.marker)
color = QColor(self.facecolor)
color.setAlphaF(self.alpha)
marker = QwtSymbol(
marker_type,
QBrush(color),
QPen(QColor(self.edgecolor)),
QSizeF(self.size, self.size),
)
return marker
def update_symbol(self, obj):
obj.setSymbol(self.build_symbol())
class SymbolItemWidget(DataSetWidget):
klass = SymbolParam
class SymbolItem(ObjectItem):
"""Item holding a SymbolParam"""
klass = SymbolParam
DataSetEditLayout.register(SymbolItem, SymbolItemWidget)
# ===================================================
# Common line style parameters
# ===================================================
[docs]class LineStyleParam(DataSet):
style = ImageChoiceItem(_("Style"), LINESTYLE_CHOICES, default="SolidLine")
color = ColorItem(_("Color"), default="black")
width = FloatItem(_("Width"), default=1.0, min=0)
def update_param(self, pen):
self.width = pen.widthF()
self.color = str(pen.color().name())
self.style = LINESTYLE_NAME[pen.style()]
def build_pen(self):
linecolor = QColor(self.color)
style = getattr(Qt, self.style)
pen = QPen(linecolor, self.width, style)
return pen
[docs] def set_style_from_matlab(self, linestyle):
"""Eventually convert MATLAB-like linestyle into Qt linestyle"""
linestyle = LINESTYLES.get(linestyle, linestyle) # MATLAB-style
if linestyle == "": # MATLAB-style
linestyle = "NoPen"
self.style = linestyle
class LineStyleItemWidget(DataSetWidget):
klass = LineStyleParam
class LineStyleItem(ObjectItem):
"""Item holding a LineStyleParam"""
klass = LineStyleParam
DataSetEditLayout.register(LineStyleItem, LineStyleItemWidget)
# ===================================================
# Common brush style parameters
# ===================================================
[docs]class BrushStyleParam(DataSet):
style = ImageChoiceItem(_("Style"), BRUSHSTYLE_CHOICES, default="SolidPattern")
color = ColorItem(_("Color"), default="black")
alpha = FloatItem(_("Alpha"), default=1.0)
angle = FloatItem(_("Angle"), default=0.0, min=0)
sx = FloatItem(_("sx"), default=1.0, min=0)
sy = FloatItem(_("sy"), default=1.0, min=0)
def update_param(self, brush):
from math import pi, sqrt, atan2
tr = brush.transform()
pt = tr.map(QPointF(1.0, 0.0))
self.sx = sqrt(pt.x() ** 2 + pt.y() ** 2)
self.angle = 180 * atan2(pt.y(), pt.x()) / pi
pt = tr.map(QPointF(0.0, 1.0))
self.sy = sqrt(pt.x() ** 2 + pt.y() ** 2)
col = brush.color()
self.color = str(col.name())
self.alpha = col.alphaF()
self.style = BRUSHSTYLE_NAME[brush.style()]
def build_brush(self):
color = QColor(self.color)
color.setAlphaF(self.alpha)
brush = QBrush(color, getattr(Qt, self.style))
tr = QTransform()
tr = tr.scale(self.sx, self.sy)
tr = tr.rotate(self.angle)
brush.setTransform(tr)
return brush
class BrushStyleItemWidget(DataSetWidget):
klass = BrushStyleParam
class BrushStyleItem(ObjectItem):
"""Item holding a LineStyleParam"""
klass = BrushStyleParam
DataSetEditLayout.register(BrushStyleItem, BrushStyleItemWidget)
# ===================================================
# QwtText parameters
# ===================================================
[docs]class TextStyleParam(DataSet):
font = FontItem(_("Font"))
textcolor = ColorItem(_("Text color"), default="blue")
background_color = ColorItem(_("Background color"), default="white")
background_alpha = FloatItem(_("Background alpha"), default=0.5, min=0, max=1)
[docs] def update_param(self, obj):
"""obj: QwtText instance"""
self.font.update_param(obj.font())
self.textcolor = obj.color().name()
color = obj.backgroundBrush().color()
self.background_color = color.name()
self.background_alpha = color.alphaF()
[docs] def update_text(self, obj):
"""obj: QwtText instance"""
obj.setColor(QColor(self.textcolor))
color = QColor(self.background_color)
color.setAlphaF(self.background_alpha)
obj.setBackgroundBrush(QBrush(color))
font = self.font.build_font()
obj.setFont(font)
class TextStyleItemWidget(DataSetWidget):
klass = TextStyleParam
class TextStyleItem(ObjectItem):
"""Item holding a TextStyleParam"""
klass = TextStyleParam
DataSetEditLayout.register(TextStyleItem, TextStyleItemWidget)
# ===================================================
# Grid parameters
# ===================================================
[docs]class GridParam(DataSet):
background = ColorItem(_("Background color"), default="white")
maj = BeginGroup(_("Major grid"))
maj_xenabled = BoolItem(_("X Axis"), default=True)
maj_yenabled = BoolItem(_("Y Axis"), default=True).set_pos(col=1)
maj_line = LineStyleItem(_("Line"))
_maj = EndGroup("end group")
min = BeginGroup(_("Minor grid"))
min_xenabled = BoolItem(_("X Axis"), default=False)
min_yenabled = BoolItem(_("Y Axis"), default=False).set_pos(col=1)
min_line = LineStyleItem(_("Line"))
_min = EndGroup("fin groupe")
def update_param(self, grid):
plot = grid.plot()
if plot is not None:
self.background = str(plot.canvasBackground().color().name())
self.maj_xenabled = grid.xEnabled()
self.maj_yenabled = grid.yEnabled()
self.maj_line.update_param(grid.majorPen())
self.min_xenabled = grid.xMinEnabled()
self.min_yenabled = grid.yMinEnabled()
self.min_line.update_param(grid.minorPen())
def update_grid(self, grid):
plot = grid.plot()
if plot is not None:
plot.blockSignals(True) # Avoid unwanted calls of update_param
# triggered by the setter methods below
plot.setCanvasBackground(QColor(self.background))
grid.enableX(self.maj_xenabled)
grid.enableY(self.maj_yenabled)
grid.setPen(self.maj_line.build_pen())
grid.enableXMin(self.min_xenabled)
grid.enableYMin(self.min_yenabled)
grid.setMinorPen(self.min_line.build_pen())
grid.setTitle(self.get_title())
if plot is not None:
plot.blockSignals(False)
# ===================================================
# Axes style parameters
# ===================================================
class AxeStyleParam(DataSet):
title = StringItem(_("Title"), default="")
unit = StringItem(_("Unit"), default="")
color = ColorItem(_("Color"), default="black").set_pos(col=1)
title_font = FontItem(_("Title font"))
ticks_font = FontItem(_("Values font"))
# ===================================================
# Axes parameters
# ===================================================
class AxisParam(DataSet):
scale = ChoiceItem(
_("Scale"), [("lin", _("linear")), ("log", _("logarithmic"))], default="lin"
)
vmin = FloatItem("Min", help=_("Lower axis limit"))
vmax = FloatItem("Max", help=_("Upper axis limit"))
def update_param(self, plot, axis_id):
self.scale = plot.get_axis_scale(axis_id)
axis = plot.axisScaleDiv(axis_id)
self.vmin = axis.lowerBound()
self.vmax = axis.upperBound()
def update_axis(self, plot, axis_id):
plot.enableAxis(axis_id, True)
plot.set_axis_scale(axis_id, self.scale, autoscale=False)
plot.setAxisScale(axis_id, self.vmin, self.vmax)
plot.disable_unused_axes()
class AxisItemWidget(DataSetWidget):
klass = AxisParam
class AxisItem(ObjectItem):
klass = AxisParam
DataSetEditLayout.register(AxisItem, AxisItemWidget)
[docs]class AxesParam(DataSet):
xaxis_id = ChoiceItem(
_("X-axis position"),
[(QwtPlot.xBottom, _("bottom")), (QwtPlot.xTop, _("top"))],
default=QwtPlot.xBottom,
)
xaxis = AxisItem(_("X Axis"))
yaxis_id = ChoiceItem(
_("Y-axis position"),
[(QwtPlot.yLeft, _("left")), (QwtPlot.yRight, _("right"))],
default=QwtPlot.yLeft,
)
yaxis = AxisItem(_("Y Axis"))
def update_param(self, item):
plot = item.plot()
self.xaxis_id = item.xAxis()
self.xaxis.update_param(plot, self.xaxis_id)
self.yaxis_id = item.yAxis()
self.yaxis.update_param(plot, self.yaxis_id)
def update_axes(self, item):
plot = item.plot()
plot.grid.setAxes(self.xaxis_id, self.yaxis_id)
item.setXAxis(self.xaxis_id)
self.xaxis.update_axis(plot, self.xaxis_id)
item.setYAxis(self.yaxis_id)
self.yaxis.update_axis(plot, self.yaxis_id)
[docs]class ImageAxesParam(DataSet):
xparams = BeginGroup(_("X Axis"))
xmin = FloatItem("x|min", help=_("Lower x-axis limit"))
xmax = FloatItem("x|max", help=_("Upper x-axis limit"))
_xparams = EndGroup("end X")
yparams = BeginGroup(_("Y Axis"))
ymin = FloatItem("y|min", help=_("Lower y-axis limit"))
ymax = FloatItem("y|max", help=_("Upper y-axis limit"))
_yparams = EndGroup("end Y")
zparams = BeginGroup(_("Z Axis"))
zmin = FloatItem("z|min", help=_("Lower z-axis limit"))
zmax = FloatItem("z|max", help=_("Upper z-axis limit"))
_zparams = EndGroup("end Z")
def update_param(self, item):
plot = item.plot()
xaxis = plot.axisScaleDiv(item.xAxis())
self.xmin = xaxis.lowerBound()
self.xmax = xaxis.upperBound()
yaxis = plot.axisScaleDiv(item.yAxis())
self.ymin = yaxis.lowerBound()
self.ymax = yaxis.upperBound()
self.zmin, self.zmax = item.min, item.max
def update_axes(self, item):
plot = item.plot()
plot.set_plot_limits(self.xmin, self.xmax, self.ymin, self.ymax)
item.set_lut_range([self.zmin, self.zmax])
plot.update_colormap_axis(item)
# ===================================================
# Label parameters
# ===================================================
[docs]class LabelParam(DataSet):
_multiselection = False
_legend = False
_no_contents = True
label = StringItem(_("Title"), default="").set_prop(
"display", hide=GetAttrProp("_multiselection")
)
_styles = BeginTabGroup("Styles")
# -------------------------------------------------------------- Contents tab
___cont = BeginGroup(_("Contents")).set_prop(
"display", icon="label.png", hide=GetAttrProp("_no_contents")
)
contents = TextItem("").set_prop("display", hide=GetAttrProp("_no_contents"))
___econt = EndGroup(_("Contents")).set_prop(
"display", hide=GetAttrProp("_no_contents")
)
# ---------------------------------------------------------------- Symbol tab
symbol = SymbolItem(_("Symbol")).set_prop(
"display", icon="diamond.png", hide=GetAttrProp("_legend")
)
# ---------------------------------------------------------------- Border tab
border = LineStyleItem(
_("Border"), default=Obj(color="#cbcbcb"), help=_("set width to 0 to disable")
).set_prop("display", icon="dashdot.png")
# ------------------------------------------------------------------ Text tab
___text = BeginGroup(_("Text")).set_prop("display", icon="font.png")
font = FontItem(_("Text font"))
color = ColorItem(_("Text color"), default="#000000")
bgcolor = ColorItem(_("Background color"), default="#ffffff")
bgalpha = FloatItem(_("Background transparency"), min=0.0, max=1.0, default=0.8)
___etext = EndGroup(_("Text"))
# -------------------------------------------------------------- Position tab
___position = BeginGroup(_("Position")).set_prop("display", icon="move.png")
_begin_anchor = BeginGroup(_("Position relative to anchor")).set_prop(
"display", hide=GetAttrProp("_multiselection")
)
anchor = ChoiceItem(
_("Corner"),
[
("TL", _("Top left")),
("TR", _("Top right")),
("BL", _("Bottom left")),
("BR", _("Bottom right")),
("L", _("Left")),
("R", _("Right")),
("T", _("Top")),
("B", _("Bottom")),
("C", _("Center")),
],
default="TL",
help=_("Label position relative to anchor point"),
).set_prop("display", hide=GetAttrProp("_multiselection"))
xc = IntItem(
"ΔX",
default=5,
help=_("Horizontal offset (pixels) relative to anchor point"),
).set_prop("display", hide=GetAttrProp("_multiselection"))
yc = (
IntItem(
"ΔY",
default=5,
help=_("Vertical offset (pixels) relative to anchor point"),
)
.set_pos(col=1)
.set_prop("display", hide=GetAttrProp("_multiselection"))
)
_end_anchor = EndGroup(_("Anchor")).set_prop(
"display", hide=GetAttrProp("_multiselection")
)
_begin_anchorpos = BeginGroup(_("Anchor position")).set_prop(
"display", hide=GetAttrProp("_multiselection")
)
_abspos_prop = GetAttrProp("abspos")
abspos = (
BoolItem(text=_("Attach to canvas"), label=_("Anchor"), default=True)
.set_prop("display", store=_abspos_prop)
.set_prop("display", hide=GetAttrProp("_multiselection"))
)
xg = (
FloatItem(_("X"), default=0.0, help=_("X-axis position in canvas coordinates"))
.set_prop("display", active=NotProp(_abspos_prop))
.set_prop("display", hide=GetAttrProp("_multiselection"))
)
yg = (
FloatItem(_("Y"), default=0.0, help=_("Y-axis position in canvas coordinates"))
.set_pos(col=1)
.set_prop("display", active=NotProp(_abspos_prop))
.set_prop("display", hide=GetAttrProp("_multiselection"))
)
move_anchor = (
ChoiceItem(
_("Interact"),
(
(True, _("moving object changes anchor position")),
(False, _("moving object changes label position")),
),
default=True,
)
.set_prop("display", active=NotProp(_abspos_prop))
.set_prop("display", hide=GetAttrProp("_multiselection"))
)
absg = (
ChoiceItem(
_("Position"),
[
("TL", _("Top left")),
("TR", _("Top right")),
("BL", _("Bottom left")),
("BR", _("Bottom right")),
("L", _("Left")),
("R", _("Right")),
("T", _("Top")),
("B", _("Bottom")),
("C", _("Center")),
],
default="TL",
help=_("Absolute position on canvas"),
)
.set_prop("display", active=_abspos_prop)
.set_prop("display", hide=GetAttrProp("_multiselection"))
)
_end_anchorpos = EndGroup(_("Anchor position")).set_prop(
"display", hide=GetAttrProp("_multiselection")
)
___eposition = EndGroup(_("Position"))
# ----------------------------------------------------------------------- End
_endstyles = EndTabGroup("Styles")
def update_param(self, obj):
# The following is necessary only for shape labels:
# when shape is just created (and not yet moved), we need to update
# these attributes
if self.abspos:
self.absg = obj.G
else:
self.xg, self.yg = obj.G
self.xc, self.yc = obj.C
def update_label(self, obj):
if not self._multiselection:
if self.abspos:
obj.G = self.absg
else:
obj.G = (self.xg, self.yg)
obj.C = self.xc, self.yc
obj.anchor = self.anchor
obj.move_anchor = self.move_anchor
obj.setTitle(self.label)
obj.marker = self.symbol.build_symbol()
obj.border_pen = self.border.build_pen()
obj.set_text_style(self.font.build_font(), self.color)
color = QColor(self.bgcolor)
color.setAlphaF(self.bgalpha)
obj.bg_brush = QBrush(color)
class LabelParam_MS(LabelParam):
_multiselection = True
ItemParameters.register_multiselection(LabelParam, LabelParam_MS)
[docs]class LegendParam(LabelParam):
_legend = True
label = StringItem(_("Title"), default="").set_prop("display", hide=True)
def update_label(self, obj):
super(LegendParam, self).update_label(obj)
if not self._multiselection:
obj.setTitle(self.get_title())
class LegendParam_MS(LegendParam):
_multiselection = True
ItemParameters.register_multiselection(LegendParam, LegendParam_MS)
class LabelParamWithContents(LabelParam):
_no_contents = False
def __init__(self, title=None, comment=None, icon=""):
self.plain_text = None
super(LabelParamWithContents, self).__init__(title, comment, icon)
def update_param(self, obj):
super(LabelParamWithContents, self).update_param(obj)
self.contents = self.plain_text = obj.get_plain_text()
def update_label(self, obj):
super(LabelParamWithContents, self).update_label(obj)
if self.plain_text is not None and self.contents != self.plain_text:
text = self.contents.replace("\n", "<br>")
obj.set_text(text)
class LabelParamWithContents_MS(LabelParamWithContents):
_multiselection = True
ItemParameters.register_multiselection(
LabelParamWithContents, LabelParamWithContents_MS
)
# ===================================================
# Curve parameters
# ===================================================
[docs]class CurveParam(DataSet):
_multiselection = False
label = StringItem(_("Title"), default="").set_prop(
"display", hide=GetAttrProp("_multiselection")
)
line = LineStyleItem(_("Line"))
symbol = SymbolItem(_("Symbol"))
shade = FloatItem(_("Shadow"), default=0, min=0, max=1)
curvestyle = ImageChoiceItem(_("Curve style"), CURVESTYLE_CHOICES, default="Lines")
baseline = FloatItem(_("Baseline"), default=0.0)
def update_param(self, curve):
self.label = str(curve.title().text())
self.symbol.update_param(curve.symbol())
self.line.update_param(curve.pen())
self.curvestyle = CURVESTYLE_NAME[curve.style()]
self.baseline = curve.baseline()
def update_curve(self, curve):
plot = curve.plot()
if plot is not None:
plot.blockSignals(True) # Avoid unwanted calls of update_param
# triggered by the setter methods below
if not self._multiselection:
# Non common parameters
curve.setTitle(self.label)
curve.setPen(self.line.build_pen())
# Brush
linecolor = QColor(self.line.color)
linecolor.setAlphaF(self.shade)
brush = QBrush(linecolor)
if not self.shade:
brush.setStyle(Qt.NoBrush)
curve.setBrush(brush)
# Symbol
self.symbol.update_symbol(curve)
# Curve style, type and baseline
curve.setStyle(getattr(QwtPlotCurve, self.curvestyle))
curve.setBaseline(self.baseline)
if plot is not None:
plot.blockSignals(False)
class CurveParam_MS(CurveParam):
_multiselection = True
ItemParameters.register_multiselection(CurveParam, CurveParam_MS)
# ===================================================
# ErrorBar Curve parameters
# ===================================================
[docs]class ErrorBarParam(DataSet):
mode = ChoiceItem(
_("Display"),
default=0,
choices=[_("error bars with caps (x, y)"), _("error area (y)")],
help=_(
"Note: only y-axis error bars are shown in "
"error area mode\n(width and cap parameters "
"will also be ignored)"
),
)
color = ColorItem(_("Color"), default="darkred")
alpha = FloatItem(
_("Alpha"), default=0.9, min=0, max=1, help=_("Error bar transparency")
)
width = FloatItem(_("Width"), default=1.0, min=1)
cap = IntItem(_("Cap"), default=4, min=0)
ontop = BoolItem(_("set to foreground"), _("Visibility"), default=False)
def update_param(self, curve):
color = curve.errorPen.color()
self.color = str(color.name())
self.alpha = color.alphaF()
self.width = curve.errorPen.widthF()
self.cap = curve.errorCap
self.ontop = curve.errorOnTop
def update_curve(self, curve):
color = QColor(self.color)
color.setAlphaF(self.alpha)
curve.errorPen = QPen(color, self.width)
curve.errorBrush = QBrush(color)
curve.errorCap = self.cap
curve.errorOnTop = self.ontop
# ===================================================
# Image parameters
# ===================================================
def _create_choices():
choices = []
for cmap_name in get_colormap_list():
choices.append((cmap_name, cmap_name, build_icon_from_cmap_name))
return choices
class BaseImageParam(DataSet):
_multiselection = False
label = StringItem(_("Image title"), default=_("Image")).set_prop(
"display", hide=GetAttrProp("_multiselection")
)
alpha_mask = BoolItem(
_("Use image level as alpha"), _("Alpha channel"), default=False
)
alpha = FloatItem(
_("Global alpha"), default=1.0, min=0, max=1, help=_("Global alpha value")
)
_hide_colormap = False
colormap = ImageChoiceItem(
_("Colormap"), _create_choices(), default="jet"
).set_prop("display", hide=GetAttrProp("_hide_colormap"))
interpolation = ChoiceItem(
_("Interpolation"),
[
(0, _("None (nearest pixel)")),
(1, _("Linear interpolation")),
(2, _("2x2 antialiasing filter")),
(3, _("3x3 antialiasing filter")),
(5, _("5x5 antialiasing filter")),
],
default=0,
help=_("Image interpolation type"),
)
_formats = BeginGroup(_("Statistics string formatting"))
xformat = StringItem(_("X-Axis"), default=r"%.1f")
yformat = StringItem(_("Y-Axis"), default=r"%.1f")
zformat = StringItem(_("Z-Axis"), default=r"%.1f")
_end_formats = EndGroup(_("Statistics string formatting"))
def update_param(self, image):
self.label = str(image.title().text())
self.colormap = image.get_color_map_name()
interpolation = image.get_interpolation()
mode = interpolation[0]
from guiqwt.image import INTERP_NEAREST, INTERP_LINEAR
if mode == INTERP_NEAREST:
self.interpolation = 0
elif mode == INTERP_LINEAR:
self.interpolation = 1
else:
size = interpolation[1].shape[0]
self.interpolation = size
def update_image(self, image):
plot = image.plot()
if plot is not None:
plot.blockSignals(True) # Avoid unwanted calls of update_param
# triggered by the setter methods below
image.setTitle(self.label)
image.set_color_map(self.colormap)
size = self.interpolation
from guiqwt.image import INTERP_NEAREST, INTERP_LINEAR, INTERP_AA
if size == 0:
mode = INTERP_NEAREST
elif size == 1:
mode = INTERP_LINEAR
else:
mode = INTERP_AA
image.set_interpolation(mode, size)
if plot is not None:
plot.blockSignals(False)
class QuadGridParam(DataSet):
_multiselection = False
label = StringItem(_("Image title"), default=_("Image")).set_prop(
"display", hide=GetAttrProp("_multiselection")
)
alpha_mask = BoolItem(
_("Use image level as alpha"),
_("Alpha channel"),
default=False,
help=_("When enabled, highest level is opaque and lowest level is transparent"),
)
alpha = FloatItem(
_("Global alpha"), default=1.0, min=0, max=1, help=_("Global alpha value")
)
_hide_colormap = False
colormap = ImageChoiceItem(
_("Colormap"), _create_choices(), default="jet"
).set_prop("display", hide=GetAttrProp("_hide_colormap"))
interpolation = ChoiceItem(
_("Interpolation"),
[
(0, _("Quadrangle interpolation")),
(1, _("Flat")),
],
default=0,
help=_(
"Image interpolation type, "
"Flat mode use fixed u,v "
"interpolation parameters"
),
)
uflat = FloatItem(
_("Fixed U interpolation parameter"),
default=0.5,
min=0.0,
max=1.0,
help=_("For flat mode only"),
)
vflat = FloatItem(
_("Fixed V interpolation parameter"),
default=0.5,
min=0.0,
max=1.0,
help=_("For flat mode only"),
)
grid = BoolItem(_("Show grid"), default=False)
gridcolor = ColorItem(_("Grid lines color"), default="black")
def update_param(self, image):
self.label = str(image.title().text())
self.colormap = image.get_color_map_name()
interp, uflat, vflat = image.interpolate
self.interpolation = interp
self.uflat = uflat
self.vflat = vflat
self.grid = image.grid
def update_image(self, image):
plot = image.plot()
if plot is not None:
plot.blockSignals(True) # Avoid unwanted calls of update_param
# triggered by the setter methods below
image.setTitle(self.label)
image.set_color_map(self.colormap)
image.interpolate = (self.interpolation, self.uflat, self.vflat)
image.grid = self.grid
# TODO : gridcolor
if plot is not None:
plot.blockSignals(False)
class RawImageParam(BaseImageParam):
_hide_background = False
background = ColorItem(_("Background color"), default="#000000").set_prop(
"display", hide=GetAttrProp("_hide_background")
)
def update_param(self, image):
super(RawImageParam, self).update_param(image)
self.background = str(QColor(image.bg_qcolor).name())
def update_image(self, image):
super(RawImageParam, self).update_image(image)
plot = image.plot()
if plot is not None:
plot.blockSignals(True) # Avoid unwanted calls of update_param
# triggered by the setter methods below
image.set_background_color(self.background)
if plot is not None:
plot.blockSignals(False)
class RawImageParam_MS(RawImageParam):
_multiselection = True
ItemParameters.register_multiselection(RawImageParam, RawImageParam_MS)
class XYImageParam(RawImageParam):
pass
class XYImageParam_MS(XYImageParam):
_multiselection = True
ItemParameters.register_multiselection(XYImageParam, XYImageParam_MS)
[docs]class ImageParam(RawImageParam):
_xdata = BeginGroup(_("Image placement along X-axis"))
xmin = FloatItem(_("x|min"), default=None)
xmax = FloatItem(_("x|max"), default=None)
_end_xdata = EndGroup(_("Image placement along X-axis"))
_ydata = BeginGroup(_("Image placement along Y-axis"))
ymin = FloatItem(_("y|min"), default=None)
ymax = FloatItem(_("y|max"), default=None)
_end_ydata = EndGroup(_("Image placement along Y-axis"))
def update_param(self, image):
super(ImageParam, self).update_param(image)
self.xmin = image.xmin
if self.xmin is None:
self.xmin = 0.0
self.ymin = image.ymin
if self.ymin is None:
self.ymin = 0.0
if image.is_empty():
shape = (0, 0)
else:
shape = image.data.shape
self.xmax = image.xmax
if self.xmax is None:
self.xmax = float(shape[1])
self.ymax = image.ymax
if self.ymax is None:
self.ymax = float(shape[0])
def update_image(self, image):
super(ImageParam, self).update_image(image)
plot = image.plot()
if plot is not None:
plot.blockSignals(True) # Avoid unwanted calls of update_param
# triggered by the setter methods below
image.xmin = self.xmin
image.xmax = self.xmax
image.ymin = self.ymin
image.ymax = self.ymax
image.update_bounds()
image.update_border()
if plot is not None:
plot.blockSignals(False)
class ImageParam_MS(ImageParam):
_multiselection = True
ItemParameters.register_multiselection(ImageParam, ImageParam_MS)
class RGBImageParam(ImageParam):
_hide_background = True
_hide_colormap = True
def update_image(self, image):
super(RGBImageParam, self).update_image(image)
plot = image.plot()
if plot is not None:
plot.blockSignals(True) # Avoid unwanted calls of update_param
# triggered by the setter methods below
image.recompute_alpha_channel()
if plot is not None:
plot.blockSignals(False)
class RGBImageParam_MS(RGBImageParam):
_multiselection = True
ItemParameters.register_multiselection(RGBImageParam, RGBImageParam_MS)
class MaskedImageParam(ImageParam):
g_mask = BeginGroup(_("Mask"))
filling_value = FloatItem(_("Filling value"))
show_mask = BoolItem(_("Show image mask"), default=False)
alpha_masked = FloatItem(_("Masked area alpha"), default=0.7, min=0, max=1)
alpha_unmasked = FloatItem(_("Unmasked area alpha"), default=0.0, min=0, max=1)
_g_mask = EndGroup(_("Mask"))
def update_image(self, image):
super(MaskedImageParam, self).update_image(image)
plot = image.plot()
if plot is not None:
plot.blockSignals(True) # Avoid unwanted calls of update_param
# triggered by the setter methods below
image.update_mask()
if plot is not None:
plot.blockSignals(False)
class MaskedImageParam_MS(MaskedImageParam):
_multiselection = True
ItemParameters.register_multiselection(MaskedImageParam, MaskedImageParam_MS)
[docs]class ImageFilterParam(BaseImageParam):
label = StringItem(_("Title"), default=_("Filter"))
g1 = BeginGroup(_("Bounds"))
xmin = FloatItem(_("x|min"))
xmax = FloatItem(_("x|max"))
ymin = FloatItem(_("y|min"))
ymax = FloatItem(_("y|max"))
_g1 = EndGroup("sub-group")
use_source_cmap = BoolItem(
_("Use image colormap and level"), _("Color map"), default=True
)
def update_param(self, obj):
self.xmin, self.ymin, self.xmax, self.ymax = obj.border_rect.get_rect()
self.use_source_cmap = obj.use_source_cmap
super(ImageFilterParam, self).update_param(obj)
def update_imagefilter(self, imagefilter):
m, M = imagefilter.get_lut_range()
set_range = False
if not self.use_source_cmap and imagefilter.use_source_cmap:
set_range = True
imagefilter.use_source_cmap = self.use_source_cmap
if set_range:
imagefilter.set_lut_range([m, M])
self.update_image(imagefilter)
imagefilter.border_rect.set_rect(self.xmin, self.ymin, self.xmax, self.ymax)
[docs]class TrImageParam(RawImageParam):
_crop = BeginGroup(_("Crop")).set_prop(
"display", hide=GetAttrProp("_multiselection")
)
crop_left = IntItem(_("Left"), default=0)
crop_right = IntItem(_("Right"), default=0)
crop_top = IntItem(_("Top"), default=0)
crop_bottom = IntItem(_("Bottom"), default=0)
_end_crop = EndGroup(_("Cropping")).set_prop(
"display", hide=GetAttrProp("_multiselection")
)
_ps = BeginGroup(_("Pixel size")).set_prop(
"display", hide=GetAttrProp("_multiselection")
)
dx = FloatItem(_("Width (dx)"), default=1.0)
dy = FloatItem(_("Height (dy)"), default=1.0)
_end_ps = EndGroup(_("Pixel size")).set_prop(
"display", hide=GetAttrProp("_multiselection")
)
_pos = BeginGroup(_("Translate, rotate and flip"))
pos_x0 = FloatItem(_("x<sub>CENTER</sub>"), default=0.0).set_prop(
"display", hide=GetAttrProp("_multiselection")
)
hflip = BoolItem(_("Flip horizontally"), default=False).set_prop("display", col=1)
pos_y0 = FloatItem(_("y<sub>CENTER</sub>"), default=0.0).set_prop(
"display", hide=GetAttrProp("_multiselection")
)
vflip = BoolItem(_("Flip vertically"), default=False).set_prop("display", col=1)
pos_angle = FloatItem("θ (°)", default=0.0).set_prop("display", col=0)
_end_pos = EndGroup(_("Translate, rotate and flip"))
def update_param(self, image):
super(TrImageParam, self).update_param(image)
# we don't get crop info from the image because
# its not easy to extract from the transform
# and TrImageItem keeps it's crop information
# directly in this DataSet
def update_image(self, image):
RawImageParam.update_image(self, image)
plot = image.plot()
if plot is not None:
plot.blockSignals(True) # Avoid unwanted calls of update_param
# triggered by the setter methods below
image.set_transform(*self.get_transform())
if plot is not None:
plot.blockSignals(False)
def get_transform(self):
return (
self.pos_x0,
self.pos_y0,
self.pos_angle * np.pi / 180,
self.dx,
self.dy,
self.hflip,
self.vflip,
)
def set_transform(self, x0, y0, angle, dx=1.0, dy=1.0, hflip=False, vflip=False):
self.pos_x0 = x0
self.pos_y0 = y0
self.pos_angle = angle * 180 / np.pi
self.dx = dx
self.dy = dy
self.hflip = hflip
self.vflip = vflip
def set_crop(self, left, top, right, bottom):
self.crop_left = left
self.crop_right = right
self.crop_top = top
self.crop_bottom = bottom
def get_crop(self):
return (self.crop_left, self.crop_top, self.crop_right, self.crop_bottom)
class TrImageParam_MS(TrImageParam):
_multiselection = True
ItemParameters.register_multiselection(TrImageParam, TrImageParam_MS)
# ===================================================
# Histogram parameters
# ===================================================
[docs]class HistogramParam(DataSet):
n_bins = IntItem(_("Bins"), default=100, min=1, help=_("Number of bins"))
logscale = BoolItem(_("logarithmic"), _("Y-axis scale"), default=False)
def update_param(self, obj):
self.n_bins = obj.get_bins()
self.logscale = obj.get_logscale()
def update_hist(self, hist):
hist.set_bins(self.n_bins)
hist.set_logscale(self.logscale)
# ===================================================
# Histogram 2D parameters
# ===================================================
[docs]class Histogram2DParam(BaseImageParam):
"""Histogram"""
_multiselection = False
label = StringItem(_("Title"), default=_("Histogram")).set_prop(
"display", hide=GetAttrProp("_multiselection")
)
nx_bins = IntItem(
_("X-axis bins"), default=100, min=1, help=_("Number of bins along x-axis")
)
ny_bins = IntItem(
_("Y-axis bins"), default=100, min=1, help=_("Number of bins along y-axis")
)
logscale = BoolItem(_("logarithmic"), _("Z-axis scale"), default=False)
computation = ChoiceItem(
_("Computation"),
[
(-1, _("Bin count")),
(0, _("Maximum value")),
(1, _("Mininum value")),
(2, _("Sum")),
(3, _("Product")),
(4, _("Average")),
],
default=-1,
help=_(
"Bin count : counts the number of points per bin,\n"
"For max, min, sum, product, average, compute the "
"function of a third parameter (one by default)"
),
)
auto_lut = BoolItem(
_("Automatic LUT range"),
default=True,
help=_("Automatically adapt color scale " "when panning, zooming"),
)
background = ColorItem(
_("Background color"),
default="transparent",
help=_("Background color when no data is present"),
)
def update_param(self, obj):
super(Histogram2DParam, self).update_param(obj)
self.logscale = obj.logscale
self.nx_bins, self.ny_bins = obj.nx_bins, obj.ny_bins
def update_histogram(self, histogram):
histogram.logscale = int(self.logscale)
histogram.set_background_color(self.background)
histogram.set_bins(self.nx_bins, self.ny_bins)
self.update_image(histogram)
class Histogram2DParam_MS(Histogram2DParam):
_multiselection = True
ItemParameters.register_multiselection(Histogram2DParam, Histogram2DParam_MS)
# ===================================================
# Shape parameters
# ===================================================
[docs]class MarkerParam(DataSet):
_styles = BeginTabGroup("Styles")
# ------------------------------------------------------------------ Line tab
___line = BeginGroup(_("Line")).set_prop("display", icon="dashdot.png")
line = LineStyleItem(_("Line (not selected)"))
sel_line = LineStyleItem(_("Line (selected)"))
___eline = EndGroup(_("Line"))
# ---------------------------------------------------------------- Symbol tab
___sym = BeginGroup(_("Symbol")).set_prop("display", icon="diamond.png")
symbol = SymbolItem(_("Symbol (not selected)"))
sel_symbol = SymbolItem(_("Symbol (selected)"))
___esym = EndGroup(_("Symbol"))
# ------------------------------------------------------------------ Text tab
___text = BeginGroup(_("Text")).set_prop("display", icon="font.png")
text = TextStyleItem(_("Text (not selected)"))
sel_text = TextStyleItem(_("Text (selected)"))
___etext = EndGroup(_("Text"))
# ----------------------------------------------------------------------- End
_endstyles = EndTabGroup("Styles")
markerstyle = ImageChoiceItem(
_("Line style"), MARKERSTYLE_CHOICES, default="NoLine"
)
spacing = IntItem(_("Spacing"), default=10, min=0)
def update_param(self, obj):
self.symbol.update_param(obj.symbol())
self.text.update_param(obj.label())
self.line.update_param(obj.linePen())
self.markerstyle = MARKERSTYLE_NAME[obj.lineStyle()]
self.spacing = obj.spacing()
def update_marker(self, obj):
if obj.selected:
line = self.sel_line
symb = self.sel_symbol
text = self.sel_text
else:
line = self.line
symb = self.symbol
text = self.text
symb.update_symbol(obj)
label = obj.label()
text.update_text(label)
obj.setLabel(label)
obj.setLinePen(line.build_pen())
obj.setLineStyle(getattr(QwtPlotMarker, self.markerstyle))
obj.setSpacing(self.spacing)
obj.update_label()
[docs] def set_markerstyle(self, style):
"""
Set marker line style
style:
* convenient values: '+', '-', '|' or None
* `QwtPlotMarker.NoLine`, `QwtPlotMarker.Vertical`, ...
"""
self.markerstyle = MARKERSTYLES.get(style, style)
[docs]class ShapeParam(DataSet):
label = StringItem(_("Title"), default="")
_styles = BeginTabGroup("Styles")
# ------------------------------------------------------------------ Line tab
___line = BeginGroup(_("Line")).set_prop("display", icon="dashdot.png")
line = LineStyleItem(_("Line (not selected)"))
sel_line = LineStyleItem(_("Line (selected)"))
___eline = EndGroup(_("Line"))
# ---------------------------------------------------------------- Symbol tab
___sym = BeginGroup(_("Symbol")).set_prop("display", icon="diamond.png")
symbol = SymbolItem(_("Symbol (not selected)"))
sel_symbol = SymbolItem(_("Symbol (selected)"))
___esym = EndGroup(_("Symbol"))
# ------------------------------------------------------------------ Fill tab
___fill = BeginGroup(_("Fill pattern")).set_prop(
"display", icon="dense6pattern.png"
)
fill = BrushStyleItem(_("Fill pattern (not selected)"))
sel_fill = BrushStyleItem(_("Fill pattern (selected)"))
___efill = EndGroup(_("Fill pattern"))
# ----------------------------------------------------------------------- End
_endstyles = EndTabGroup("Styles")
readonly = BoolItem(
_("Read-only shape"),
default=False,
help=_("Read-only shapes can't be removed from " "the item list panel"),
)
private = BoolItem(
_("Private shape"),
default=False,
help=_("Private shapes are not shown in " "the item list panel"),
).set_pos(col=1)
def update_param(self, obj):
self.label = str(obj.title().text())
self.line.update_param(obj.pen)
self.symbol.update_param(obj.symbol)
self.fill.update_param(obj.brush)
self.sel_line.update_param(obj.sel_pen)
self.sel_symbol.update_param(obj.sel_symbol)
self.sel_fill.update_param(obj.sel_brush)
self.readonly = obj.is_readonly()
self.private = obj.is_private()
def update_shape(self, obj):
plot = obj.plot()
if plot is not None:
plot.blockSignals(True) # Avoid unwanted calls of update_param
# triggered by the setter methods below
obj.setTitle(self.label)
obj.pen = self.line.build_pen()
obj.symbol = self.symbol.build_symbol()
obj.brush = self.fill.build_brush()
obj.sel_pen = self.sel_line.build_pen()
obj.sel_symbol = self.sel_symbol.build_symbol()
obj.sel_brush = self.sel_fill.build_brush()
obj.set_readonly(self.readonly)
obj.set_private(self.private)
if plot is not None:
plot.blockSignals(False)
[docs]class AxesShapeParam(DataSet):
arrow_angle = FloatItem(_("Arrow angle") + " (°)", min=0, max=90, nonzero=True)
arrow_size = FloatItem(_("Arrow size") + " (%)", min=0, max=100, nonzero=True)
_styles = BeginTabGroup("Styles")
# ------------------------------------------------------------------ Line tab
___line = BeginGroup(_("Line")).set_prop("display", icon="dashdot.png")
xarrow_pen = LineStyleItem(_("Line (X-Axis)"))
yarrow_pen = LineStyleItem(_("Line (Y-Axis)"))
___eline = EndGroup(_("Line"))
# ------------------------------------------------------------------ Fill tab
___fill = BeginGroup(_("Fill pattern")).set_prop(
"display", icon="dense6pattern.png"
)
xarrow_brush = BrushStyleItem(_("Fill pattern (X-Axis)"))
yarrow_brush = BrushStyleItem(_("Fill pattern (Y-Axis)"))
___efill = EndGroup(_("Fill pattern"))
# ----------------------------------------------------------------------- End
_endstyles = EndTabGroup("Styles")
def update_param(self, obj):
self.arrow_angle = obj.arrow_angle
self.arrow_size = obj.arrow_size
self.xarrow_pen.update_param(obj.x_pen)
self.yarrow_pen.update_param(obj.y_pen)
self.xarrow_brush.update_param(obj.x_brush)
self.yarrow_brush.update_param(obj.y_brush)
def update_axes(self, obj):
obj.arrow_angle = self.arrow_angle
obj.arrow_size = self.arrow_size
obj.x_pen = self.xarrow_pen.build_pen()
obj.x_brush = self.xarrow_brush.build_brush()
obj.y_pen = self.yarrow_pen.build_pen()
obj.y_brush = self.yarrow_brush.build_brush()
[docs]class AnnotationParam(DataSet):
show_label = BoolItem(_("Show annotation"), default=True)
show_computations = BoolItem(
_("Show informations on area " "covered by this shape"), default=True
)
title = StringItem(_("Title"), default="")
subtitle = StringItem(_("Subtitle"), default="")
format = StringItem(_("String formatting"), default="%.1f")
uncertainty = FloatItem(
_("Uncertainty"),
default=0.0,
min=0.0,
max=1.0,
help=_("Measurement relative uncertainty"),
).set_pos(col=1)
transform_matrix = FloatArrayItem(
_("Transform matrix"), default=np.eye(3, dtype=float)
)
readonly = BoolItem(
_("Read-only shape"),
default=False,
help=_("Read-only shapes can't be removed from " "the item list panel"),
)
private = BoolItem(
_("Private shape"),
default=False,
help=_("Private shapes are not shown in " "the item list panel"),
).set_pos(col=1)
def update_param(self, obj):
self.show_label = obj.is_label_visible()
self.show_computations = obj.area_computations_visible
self.title = str(obj.title().text())
self.readonly = obj.is_readonly()
self.private = obj.is_private()
def update_annotation(self, obj):
plot = obj.plot()
if plot is not None:
plot.blockSignals(True) # Avoid unwanted calls of update_param
# triggered by the setter methods below
obj.setTitle(self.title)
obj.set_label_visible(self.show_label)
obj.area_computations_visible = self.show_computations
obj.update_label()
obj.set_readonly(self.readonly)
obj.set_private(self.private)
if plot is not None:
plot.blockSignals(False)
# ===================================================
# Range selection parameters
# ===================================================
[docs]class RangeShapeParam(DataSet):
_styles = BeginTabGroup("Styles")
# ------------------------------------------------------------------ Line tab
___line = BeginGroup(_("Line")).set_prop("display", icon="dashdot.png")
line = LineStyleItem(_("Line (not selected)"))
sel_line = LineStyleItem(_("Line (selected)"))
___eline = EndGroup(_("Line"))
# ---------------------------------------------------------------- Symbol tab
___symbol = BeginGroup(_("Symbol")).set_prop("display", icon="diamond.png")
symbol = SymbolItem(_("Symbol (not selected)"))
sel_symbol = SymbolItem(_("Symbol (selected)"))
___esymbol = EndGroup(_("Symbol"))
# ------------------------------------------------------------------ Fill tab
___fill = BeginGroup(_("Fill")).set_prop("display", icon="dense6pattern.png")
fill = ColorItem(_("Fill color"))
shade = FloatItem(_("Shade"), default=0.05, min=0, max=1)
___efill = EndGroup(_("Fill"))
# ----------------------------------------------------------------------- End
_endstyles = EndTabGroup("Styles")
def update_param(self, range):
self.line.update_param(range.pen)
self.sel_line.update_param(range.sel_pen)
self.fill = range.brush.color().name()
self.shade = range.brush.color().alphaF()
self.symbol.update_param(range.symbol)
self.sel_symbol.update_param(range.sel_symbol)
def update_range(self, range):
range.pen = self.line.build_pen()
range.sel_pen = self.sel_line.build_pen()
col = QColor(self.fill)
col.setAlphaF(self.shade)
range.brush = QBrush(col)
range.symbol = self.symbol.build_symbol()
range.sel_symbol = self.sel_symbol.build_symbol()