Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plot label customisation widget #1920 #2096

Merged
merged 2 commits into from
Jun 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
263 changes: 263 additions & 0 deletions src/sas/qtgui/Plotting/PlotLabelProperties.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
from PyQt5 import QtCore
from PyQt5 import QtWidgets

from sas.qtgui.Plotting.PlotUtilities import COLORS, COLORS_LETTER, WEIGHTS, FONTS
from sas.qtgui.Plotting.UI.PlotLabelPropertiesUI import Ui_PlotLabelPropertiesUI


class PlotLabelPropertyHolder():
def __init__(self, font=None, color=None, weight=None, size=None, text="",):
self.__properties = {}
self.__properties['font'] = font
self.__properties['color'] = color
self.__properties['weight'] = weight
self.__properties['size'] = size
self.__properties['text'] = text

@property
def font(self):
return self.__properties['font']

@font.setter
def font(self, value):
self.__properties['font'] = value

@property
def color(self):
return self.__properties['color']

@color.setter
def color(self, value):
self.__properties['color'] = value

@property
def weight(self):
return self.__properties['weight']

@weight.setter
def weight(self, value):
self.__properties['weight'] = value

@property
def size(self):
return self.__properties['size']

@size.setter
def size(self, value):
self.__properties['size'] = value

@property
def text(self):
return self.__properties['text']

@text.setter
def text(self, value):
self.__properties['text'] = value


class PlotLabelProperties(QtWidgets.QDialog, Ui_PlotLabelPropertiesUI):
""" Dialog for modification of plot label properties """
def __init__(self,
parent=None,
x_props={},
y_props={}):

super(PlotLabelProperties, self).__init__(parent)
self.setupUi(self)
# disable the context help icon
self.setWindowFlags(self.windowFlags() & ~QtCore.Qt.WindowContextHelpButtonHint)

self.setFixedSize(self.minimumSizeHint())

self.custom_color = False
self.custom_colory = False

self._weight = x_props.weight
self._color = x_props.color
self._text = x_props.text
self._size = x_props.size
self._family = x_props.font

self._weighty = y_props.weight
self._colory = y_props.color
self._texty = y_props.text
self._sizey = y_props.size
self._familyy = y_props.font

# Fill out the color comboboxes
self.cbColor.addItems(list(COLORS.keys())[:-1])
self.cbColor_y.addItems(list(COLORS.keys())[:-1])
# data1d.custom_color can now be a simple integer,
# specifying COLORS dict index or a string containing
# the hex RGB value, e.g. #00FF00
if isinstance(self._color, int):
self.cbColor.setCurrentIndex(self._color)
elif self._color in COLORS.keys():
self.cbColor.setCurrentIndex(list(COLORS.keys()).index(self._color))
elif self._color in COLORS.values():
self.cbColor.setCurrentIndex(list(COLORS.values()).index(self._color))
elif self._color in COLORS_LETTER.keys():
self.cbColor.setCurrentIndex(list(COLORS_LETTER.keys()).index(self._color))
else:
# Need the Custom entry here. "Custom" is always last.
self.cbColor.addItems([list(COLORS.keys())[-1]])
self.cbColor.setCurrentIndex(list(COLORS.keys()).index("Custom"))
self.custom_color = True

if isinstance(self._colory, int):
self.cbColor_y.setCurrentIndex(self._colory)
elif self._colory in COLORS.keys():
self.cbColor_y.setCurrentIndex(list(COLORS.keys()).index(self._colory))
elif self._colory in COLORS.values():
self.cbColor_y.setCurrentIndex(list(COLORS.values()).index(self._colory))
elif self._colory in COLORS_LETTER.keys():
self.cbColor_y.setCurrentIndex(list(COLORS_LETTER.keys()).index(self._colory))
else:
# Need the Custom entry here. "Custom" is always last.
self.cbColor_y.addItems([list(COLORS.keys())[-1]])
self.cbColor_y.setCurrentIndex(list(COLORS.keys()).index("Custom"))
self.custom_colory = True

# Fill out the weight combobox
self.cbWeight.addItems(WEIGHTS)
try:
self.cbWeight.setCurrentIndex(self._weight)
except TypeError:
marker_index = self.cbWeight.findText(self._weight)
self.cbWeight.setCurrentIndex(marker_index)

self.cbWeight_y.addItems(WEIGHTS)
try:
self.cbWeight_y.setCurrentIndex(self._weighty)
except TypeError:
marker_index = self.cbWeight_y.findText(self._weighty)
self.cbWeight_y.setCurrentIndex(marker_index)

# Fill out the font combobox
self.cbFont.addItems(FONTS)
try:
self.cbFont.setCurrentIndex(self._family)
except TypeError:
marker_index = self.cbFont.findText(self._family)
self.cbFont.setCurrentIndex(marker_index)

self.cbFont_y.addItems(FONTS)
try:
self.cbFont_y.setCurrentIndex(self._familyy)
except TypeError:
marker_index = self.cbFont_y.findText(self._familyy)
self.cbFont_y.setCurrentIndex(marker_index)


self.txtLegend.setText(self._text)
self.txtLegend_y.setText(self._texty)

# Size
self.cbSize.setValue(self._size)
self.cbSize_y.setValue(self._sizey)

# Connect slots
self.cmdCustom.clicked.connect(self.onColorChange)
self.cmdCustom_y.clicked.connect(self.onColorChange_y)
self.cbColor.currentIndexChanged.connect(self.onColorIndexChange)
self.cbColor_y.currentIndexChanged.connect(self.onColorIndexChange_y)

def text_x(self):
''' return current legend text for x-axis '''
return str(self.txtLegend.text())

def text_y(self):
''' return current legend text for y-axis '''
return str(self.txtLegend_y.text())

def apply_to_ticks_x(self):
''' return status of the "Apply to ticks" checkbox for x-axis '''
return self.chkTicks.isChecked()

def apply_to_ticks_y(self):
''' return status of the "Apply to ticks" checkbox for y-axis '''
return self.chkTicks_y.isChecked()

def fx(self):
''' return font parameters for x-axis '''
if self.custom_color:
color = self._color
else:
color = self.cbColor.currentText()
font = {'family': self.cbFont.currentText(),
'color': color,
'weight': self.cbWeight.currentText(),
'size': self.cbSize.value(),
}
return font

def fy(self):
''' return font parameters for y-axis '''
if self.custom_colory:
color = self._colory
else:
color = self.cbColor_y.currentText()
font = {'family': self.cbFont_y.currentText(),
'color': color,
'weight': self.cbWeight_y.currentText(),
'size': self.cbSize_y.value(),
}
return font

def onColorChange(self):
"""
Pop up the standard Qt color change dialog
"""
# Pick up the chosen color
proposed_color = QtWidgets.QColorDialog.getColor(parent=self)
# Update the text control
if proposed_color.isValid():
# Block currentIndexChanged
self.cbColor.blockSignals(True)
# Add Custom to the color combo box
self.cbColor.addItems(["Custom"])
self.cbColor.setCurrentIndex(list(COLORS.keys()).index("Custom"))
# unblock currentIndexChanged
self.cbColor.blockSignals(False)
# Save the color as #RRGGBB
self.custom_color = True
self._color = str(proposed_color.name())

def onColorChange_y(self):
"""
Pop up the standard Qt color change dialog
"""
# Pick up the chosen color
proposed_color = QtWidgets.QColorDialog.getColor(parent=self)
# Update the text control
if proposed_color.isValid():
# Block currentIndexChanged
self.cbColor_y.blockSignals(True)
# Add Custom to the color combo box
self.cbColor_y.addItems(["Custom"])
self.cbColor_y.setCurrentIndex(list(COLORS.keys()).index("Custom"))
# unblock currentIndexChanged
self.cbColor_y.blockSignals(False)
# Save the color as #RRGGBB
self.custom_colory = True
self._colory = str(proposed_color.name())

def onColorIndexChange(self):
"""
Dynamically add/remove "Custom" color index
"""
# Changed index - assure Custom is deleted
custom_index = self.cbColor.findText("Custom")
self.custom_color = False
if custom_index > -1:
self.cbColor.removeItem(custom_index)

def onColorIndexChange_y(self):
"""
Dynamically add/remove "Custom" color index
"""
# Changed index - assure Custom is deleted
custom_index = self.cbColor_y.findText("Custom")
self.custom_colory = False
if custom_index > -1:
self.cbColor_y.removeItem(custom_index)
3 changes: 1 addition & 2 deletions src/sas/qtgui/Plotting/PlotProperties.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def onColorChange(self):
# Save the color as #RRGGBB
self.custom_color = True
self._color = str(proposed_color.name())

def onColorIndexChange(self):
"""
Dynamically add/remove "Custom" color index
Expand All @@ -100,4 +100,3 @@ def onColorIndexChange(self):
self.custom_color = False
if custom_index > -1:
self.cbColor.removeItem(custom_index)

18 changes: 18 additions & 0 deletions src/sas/qtgui/Plotting/PlotUtilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,24 @@
('Custom', 'x'),
])

COLORS_LETTER = OrderedDict([
('b', '#1f77b4'),
('g', '#2ca02c'),
('r', '#d62728'),
('c', '#17becf'),
('m', '#e377c2'),
('y', '#bcbd22'),
('k', '#000000'),
])


# MPL font weights list
WEIGHTS = ['light', 'normal', 'bold']

# MPL font family list
FONTS = ['sans-serif', 'serif', 'cursive', 'fantasy', 'monospace']


def build_matrix(data, qx_data, qy_data):
"""
Build a matrix for 2d plot from a vector
Expand Down
51 changes: 51 additions & 0 deletions src/sas/qtgui/Plotting/Plotter.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
from sas.qtgui.Plotting.QRangeSlider import QRangeSlider
from sas.qtgui.Plotting.PlotProperties import PlotProperties
from sas.qtgui.Plotting.ScaleProperties import ScaleProperties
from sas.qtgui.Plotting.PlotLabelProperties import PlotLabelProperties
from sas.qtgui.Plotting.PlotLabelProperties import PlotLabelPropertyHolder

import sas.qtgui.Utilities.GuiUtils as GuiUtils
import sas.qtgui.Plotting.PlotUtilities as PlotUtilities
Expand Down Expand Up @@ -325,6 +327,8 @@ def createContextMenu(self):
if self.show_legend:
self.actionToggleLegend = self.contextMenu.addAction("Toggle Legend")
self.contextMenu.addSeparator()
self.actionCustomizeLabel = self.contextMenu.addAction("Customize Labels")
self.contextMenu.addSeparator()
self.actionChangeScale = self.contextMenu.addAction("Change Scale")
self.contextMenu.addSeparator()
self.actionSetGraphRange = self.contextMenu.addAction("Set Graph Range")
Expand All @@ -347,6 +351,7 @@ def createContextMenu(self):
self.actionToggleMenu.triggered.connect(self.onToggleMenu)
if self.show_legend:
self.actionToggleLegend.triggered.connect(self.onToggleLegend)
self.actionCustomizeLabel.triggered.connect(self.onCusotmizeLabel)

def addPlotsToContextMenu(self):
"""
Expand Down Expand Up @@ -798,6 +803,52 @@ def onToggleLegend(self):
self.legend.set_visible(not visible)
self.canvas.draw_idle()

def onCusotmizeLabel(self):
"""
Show label customization widget
"""
xl = self.ax.xaxis.label
yl = self.ax.yaxis.label
font_x = PlotLabelPropertyHolder(
size=xl.get_fontsize(),
font=xl.get_family()[0],
color=xl.get_color(),
weight=xl.get_weight(),
text=xl.get_text())

font_y = PlotLabelPropertyHolder(
size=yl.get_fontsize(),
font=yl.get_family()[0],
color=yl.get_color(),
weight=yl.get_weight(),
text=yl.get_text())

labelWidget = PlotLabelProperties(self, x_props=font_x, y_props=font_y)

if labelWidget.exec_() != QtWidgets.QDialog.Accepted:
return

fx = labelWidget.fx()
fy = labelWidget.fy()
label_x = labelWidget.text_x()
label_y = labelWidget.text_y()
apply_x = labelWidget.apply_to_ticks_x()
apply_y = labelWidget.apply_to_ticks_y()

self.ax.set_xlabel(label_x, fontdict=fx)
self.ax.set_ylabel(label_y, fontdict=fy)
if apply_x:
# self.ax.tick_params(axis='x', labelsize=fx.size, labelcolor=fx.color)
from matplotlib.pyplot import gca
a = gca()
a.set_xticklabels(a.get_xticks(), fx)
if apply_y:
# self.ay.tick_params(axis='y', labelsize=fy.size, labelcolor=fy.color)
from matplotlib.pyplot import gca
a = gca()
a.set_yticklabels(a.get_yticks(), fy)
self.canvas.draw_idle()

def onMplMouseDown(self, event):
"""
Left button down and ready to drag
Expand Down
Loading