diff --git a/lib/matplotlib/backends/backend_qt4.py b/lib/matplotlib/backends/backend_qt4.py index 65a06e0da12c..9bde3769ecfb 100644 --- a/lib/matplotlib/backends/backend_qt4.py +++ b/lib/matplotlib/backends/backend_qt4.py @@ -39,6 +39,7 @@ figureoptions = None from .qt4_compat import QtCore, QtGui, _getSaveFileName, __version__ +from matplotlib.backends.qt4_editor.formsubplottool import UiSubplotTool backend_version = __version__ @@ -558,6 +559,7 @@ class NavigationToolbar2QT(NavigationToolbar2, QtGui.QToolBar): def __init__(self, canvas, parent, coordinates=True): """ coordinates: should we show the coordinates on the right? """ self.canvas = canvas + self.parent = parent self.coordinates = coordinates self._actions = {} """A mapping of toolitem method names to their QActions""" @@ -613,29 +615,18 @@ def edit_parameters(self): axes = allaxes[0] else: titles = [] - for axes in allaxes: - title = axes.get_title() + for i, axes in enumerate(allaxes): ylabel = axes.get_ylabel() - if title: - fmt = "%(title)s" - if ylabel: - fmt += ": %(ylabel)s" - fmt += " (%(axes_repr)s)" - elif ylabel: - fmt = "%(axes_repr)s (%(ylabel)s)" - else: - fmt = "%(axes_repr)s" - titles.append(fmt % dict(title=title, - ylabel=ylabel, - axes_repr=repr(axes))) - item, ok = QtGui.QInputDialog.getItem(self, 'Customize', - 'Select axes:', titles, - 0, False) + text = "_axes%d" % i + if ylabel: + text += " %s" % ylabel + titles.append(text) + item, ok = QtGui.QInputDialog.getItem( + self.parent, 'Customize', 'Select axes:', titles, 0, False) if ok: axes = allaxes[titles.index(six.text_type(item))] else: return - figureoptions.figure_edit(axes, self) def _update_buttons_checked(self): @@ -676,20 +667,11 @@ def draw_rubberband(self, event, x0, y0, x1, y1): self.canvas.drawRectangle(rect) def configure_subplots(self): - self.adj_window = QtGui.QMainWindow() - win = self.adj_window - - win.setWindowTitle("Subplot Configuration Tool") image = os.path.join(matplotlib.rcParams['datapath'], 'images', 'matplotlib.png') - win.setWindowIcon(QtGui.QIcon(image)) - - tool = SubplotToolQt(self.canvas.figure, win) - win.setCentralWidget(tool) - win.setSizePolicy(QtGui.QSizePolicy.Preferred, - QtGui.QSizePolicy.Preferred) - - win.show() + dia = SubplotToolQt(self.canvas.figure, self.parent) + dia.setWindowIcon(QtGui.QIcon(image)) + dia.exec_() def _get_canvas(self, fig): return FigureCanvasQT(fig) @@ -712,8 +694,9 @@ def save_figure(self, *args): selectedFilter = filter filters.append(filter) filters = ';;'.join(filters) - fname = _getSaveFileName(self, "Choose a filename to save to", - start, filters, selectedFilter) + + fname = _getSaveFileName(self.parent, "Choose a filename to save to", + start, filters, selectedFilter) if fname: if startpath == '': # explicitly missing key or empty str signals to use cwd @@ -730,132 +713,142 @@ def save_figure(self, *args): QtGui.QMessageBox.Ok, QtGui.QMessageBox.NoButton) -class SubplotToolQt(SubplotTool, QtGui.QWidget): +class SubplotToolQt(SubplotTool, UiSubplotTool): def __init__(self, targetfig, parent): - QtGui.QWidget.__init__(self, None) - + UiSubplotTool.__init__(self, None) self.targetfig = targetfig self.parent = parent - - self.sliderleft = QtGui.QSlider(QtCore.Qt.Horizontal) - self.sliderbottom = QtGui.QSlider(QtCore.Qt.Vertical) - self.sliderright = QtGui.QSlider(QtCore.Qt.Horizontal) - self.slidertop = QtGui.QSlider(QtCore.Qt.Vertical) - self.sliderwspace = QtGui.QSlider(QtCore.Qt.Horizontal) - self.sliderhspace = QtGui.QSlider(QtCore.Qt.Vertical) - - # constraints - self.sliderleft.valueChanged.connect(self.sliderright.setMinimum) - self.sliderright.valueChanged.connect(self.sliderleft.setMaximum) - self.sliderbottom.valueChanged.connect(self.slidertop.setMinimum) - self.slidertop.valueChanged.connect(self.sliderbottom.setMaximum) + self.connect(self.doneButton, QtCore.SIGNAL("clicked()"), self.close) + self.connect(self.resetButton, QtCore.SIGNAL("clicked()"), self.reset) + self.connect(self.tightLayout, QtCore.SIGNAL("clicked()"), + self.functight) sliders = (self.sliderleft, self.sliderbottom, self.sliderright, self.slidertop, self.sliderwspace, self.sliderhspace,) - adjustments = ('left:', 'bottom:', 'right:', - 'top:', 'wspace:', 'hspace:') - for slider, adjustment in zip(sliders, adjustments): + for slider in sliders: slider.setMinimum(0) slider.setMaximum(1000) slider.setSingleStep(5) - layout = QtGui.QGridLayout() - - leftlabel = QtGui.QLabel('left') - layout.addWidget(leftlabel, 2, 0) - layout.addWidget(self.sliderleft, 2, 1) - - toplabel = QtGui.QLabel('top') - layout.addWidget(toplabel, 0, 2) - layout.addWidget(self.slidertop, 1, 2) - layout.setAlignment(self.slidertop, QtCore.Qt.AlignHCenter) - - bottomlabel = QtGui.QLabel('bottom') # this might not ever be used - layout.addWidget(bottomlabel, 4, 2) - layout.addWidget(self.sliderbottom, 3, 2) - layout.setAlignment(self.sliderbottom, QtCore.Qt.AlignHCenter) - - rightlabel = QtGui.QLabel('right') - layout.addWidget(rightlabel, 2, 4) - layout.addWidget(self.sliderright, 2, 3) - - hspacelabel = QtGui.QLabel('hspace') - layout.addWidget(hspacelabel, 0, 6) - layout.setAlignment(hspacelabel, QtCore.Qt.AlignHCenter) - layout.addWidget(self.sliderhspace, 1, 6) - layout.setAlignment(self.sliderhspace, QtCore.Qt.AlignHCenter) - - wspacelabel = QtGui.QLabel('wspace') - layout.addWidget(wspacelabel, 4, 6) - layout.setAlignment(wspacelabel, QtCore.Qt.AlignHCenter) - layout.addWidget(self.sliderwspace, 3, 6) - layout.setAlignment(self.sliderwspace, QtCore.Qt.AlignBottom) - - layout.setRowStretch(1, 1) - layout.setRowStretch(3, 1) - layout.setColumnStretch(1, 1) - layout.setColumnStretch(3, 1) - layout.setColumnStretch(6, 1) - - self.setLayout(layout) - - self.sliderleft.setSliderPosition(int(targetfig.subplotpars.left*1000)) + # constraints + self.connect(self.sliderleft, + QtCore.SIGNAL("valueChanged(int)"), + self.sliderright.setMinimum) + self.connect(self.sliderright, + QtCore.SIGNAL("valueChanged(int)"), + self.sliderleft.setMaximum) + self.connect(self.sliderbottom, + QtCore.SIGNAL("valueChanged(int)"), + self.slidertop.setMinimum) + self.connect(self.slidertop, + QtCore.SIGNAL("valueChanged(int)"), + self.sliderbottom.setMaximum) + + self._read_defaults() + self._setSliderPositions() + + self.connect(self.sliderleft, + QtCore.SIGNAL("valueChanged(int)"), + self.funcleft) + self.connect(self.sliderbottom, + QtCore.SIGNAL("valueChanged(int)"), + self.funcbottom) + self.connect(self.sliderright, + QtCore.SIGNAL("valueChanged(int)"), + self.funcright) + self.connect(self.slidertop, + QtCore.SIGNAL("valueChanged(int)"), + self.functop) + self.connect(self.sliderwspace, + QtCore.SIGNAL("valueChanged(int)"), + self.funcwspace) + self.connect(self.sliderhspace, + QtCore.SIGNAL("valueChanged(int)"), + self.funchspace) + + def _read_defaults(self): + self.defaults = {'left': self.targetfig.subplotpars.left, + 'bottom': self.targetfig.subplotpars.bottom, + 'right': self.targetfig.subplotpars.right, + 'top': self.targetfig.subplotpars.top, + 'wspace': self.targetfig.subplotpars.wspace, + 'hspace': self.targetfig.subplotpars.hspace} + + def _setSliderPositions(self): + self.sliderleft.setSliderPosition( + int(self.targetfig.subplotpars.left*1000)) self.sliderbottom.setSliderPosition( - int(targetfig.subplotpars.bottom*1000)) + int(self.targetfig.subplotpars.bottom*1000)) self.sliderright.setSliderPosition( - int(targetfig.subplotpars.right*1000)) - self.slidertop.setSliderPosition(int(targetfig.subplotpars.top*1000)) + int(self.targetfig.subplotpars.right*1000)) + self.slidertop.setSliderPosition( + int(self.targetfig.subplotpars.top*1000)) self.sliderwspace.setSliderPosition( - int(targetfig.subplotpars.wspace*1000)) + int(self.targetfig.subplotpars.wspace*1000)) self.sliderhspace.setSliderPosition( - int(targetfig.subplotpars.hspace*1000)) - - self.sliderleft.valueChanged.connect(self.funcleft) - self.sliderbottom.valueChanged.connect(self.funcbottom) - self.sliderright.valueChanged.connect(self.funcright) - self.slidertop.valueChanged.connect(self.functop) - self.sliderwspace.valueChanged.connect(self.funcwspace) - self.sliderhspace.valueChanged.connect(self.funchspace) + int(self.targetfig.subplotpars.hspace*1000)) def funcleft(self, val): if val == self.sliderright.value(): val -= 1 - self.targetfig.subplots_adjust(left=val/1000.) + val /= 1000. + self.targetfig.subplots_adjust(left=val) + self.leftvalue.setText("%.2f" % val) if self.drawon: self.targetfig.canvas.draw() def funcright(self, val): if val == self.sliderleft.value(): val += 1 - self.targetfig.subplots_adjust(right=val/1000.) + val /= 1000. + self.targetfig.subplots_adjust(right=val) + self.rightvalue.setText("%.2f" % val) if self.drawon: self.targetfig.canvas.draw() def funcbottom(self, val): if val == self.slidertop.value(): val -= 1 - self.targetfig.subplots_adjust(bottom=val/1000.) + val /= 1000. + self.targetfig.subplots_adjust(bottom=val) + self.bottomvalue.setText("%.2f" % val) if self.drawon: self.targetfig.canvas.draw() def functop(self, val): if val == self.sliderbottom.value(): val += 1 - self.targetfig.subplots_adjust(top=val/1000.) + val /= 1000. + self.targetfig.subplots_adjust(top=val) + self.topvalue.setText("%.2f" % val) if self.drawon: self.targetfig.canvas.draw() def funcwspace(self, val): - self.targetfig.subplots_adjust(wspace=val/1000.) + val /= 1000. + self.targetfig.subplots_adjust(wspace=val) + self.wspacevalue.setText("%.2f" % val) if self.drawon: self.targetfig.canvas.draw() def funchspace(self, val): - self.targetfig.subplots_adjust(hspace=val/1000.) + val /= 1000. + self.targetfig.subplots_adjust(hspace=val) + self.hspacevalue.setText("%.2f" % val) if self.drawon: self.targetfig.canvas.draw() + def functight(self): + self.targetfig.tight_layout() + self._setSliderPositions() + self.targetfig.canvas.draw() + + def reset(self): + self.targetfig.subplots_adjust(**self.defaults) + self._setSliderPositions() + self.targetfig.canvas.draw() + def error_msg_qt(msg, parent=None): if not is_string_like(msg): diff --git a/lib/matplotlib/backends/qt4_editor/figureoptions.py b/lib/matplotlib/backends/qt4_editor/figureoptions.py index f9dc2f838cbc..a8732bd93217 100644 --- a/lib/matplotlib/backends/qt4_editor/figureoptions.py +++ b/lib/matplotlib/backends/qt4_editor/figureoptions.py @@ -17,6 +17,7 @@ import matplotlib.backends.qt4_editor.formlayout as formlayout from matplotlib.backends.qt4_compat import QtGui from matplotlib import markers +from matplotlib.colors import rgb2hex def get_icon(name): import matplotlib @@ -34,6 +35,21 @@ def get_icon(name): MARKERS = markers.MarkerStyle.markers +COLORS = {'c': '#00bfbf', 'b': '#0000ff', 'w': '#ffffff', 'g': '#008000', + 'y': '#bfbf00', 'k': '#000000', 'r': '#ff0000', 'm': '#bf00bf'} + +def col2hex(color): + # default colors and hex colors + if isinstance(color, basestring): + try: + chex = COLORS[color] + except KeyError: + chex = color + else: # rgb tuples + chex = rgb2hex(color) + return chex + + def figure_edit(axes, parent=None): """Edit matplotlib figure options""" sep = (None, None) # separator diff --git a/lib/matplotlib/backends/qt4_editor/formsubplottool.py b/lib/matplotlib/backends/qt4_editor/formsubplottool.py new file mode 100644 index 000000000000..dabb6b9e0f2d --- /dev/null +++ b/lib/matplotlib/backends/qt4_editor/formsubplottool.py @@ -0,0 +1,230 @@ +# -*- coding: utf-8 -*- +""" +formsubplottool.py + +backend.qt4 (PyQt4|PySide) independend form form the subplot tool. + +""" + +__author__ = 'rudolf.hoefler@gmail.com' + +from matplotlib.backends.qt4_compat import QtCore, QtGui + + +class UiSubplotTool(QtGui.QDialog): + + def __init__(self, *args, **kwargs): + super(UiSubplotTool, self).__init__(*args, **kwargs) + self.setObjectName('SubplotTool') + self.resize(450, 265) + + gbox = QtGui.QGridLayout(self) + self.setLayout(gbox) + + # groupbox borders + groupbox = QtGui.QGroupBox('Borders', self) + gbox.addWidget(groupbox, 6, 0, 1, 1) + self.verticalLayout = QtGui.QVBoxLayout(groupbox) + self.verticalLayout.setSpacing(0) + + # slider top + self.hboxtop = QtGui.QHBoxLayout() + self.labeltop = QtGui.QLabel('top', self) + self.labeltop.setMinimumSize(QtCore.QSize(50, 0)) + self.labeltop.setAlignment( + QtCore.Qt.AlignRight | + QtCore.Qt.AlignTrailing | + QtCore.Qt.AlignVCenter) + + self.slidertop = QtGui.QSlider(self) + self.slidertop.setMouseTracking(False) + self.slidertop.setProperty("value", 0) + self.slidertop.setOrientation(QtCore.Qt.Horizontal) + self.slidertop.setInvertedAppearance(False) + self.slidertop.setInvertedControls(False) + self.slidertop.setTickPosition(QtGui.QSlider.TicksAbove) + self.slidertop.setTickInterval(100) + + self.topvalue = QtGui.QLabel('0', self) + self.topvalue.setMinimumSize(QtCore.QSize(30, 0)) + self.topvalue.setAlignment( + QtCore.Qt.AlignRight | + QtCore.Qt.AlignTrailing | + QtCore.Qt.AlignVCenter) + + self.verticalLayout.addLayout(self.hboxtop) + self.hboxtop.addWidget(self.labeltop) + self.hboxtop.addWidget(self.slidertop) + self.hboxtop.addWidget(self.topvalue) + + # slider bottom + hboxbottom = QtGui.QHBoxLayout() + labelbottom = QtGui.QLabel('bottom', self) + labelbottom.setMinimumSize(QtCore.QSize(50, 0)) + labelbottom.setAlignment( + QtCore.Qt.AlignRight | + QtCore.Qt.AlignTrailing | + QtCore.Qt.AlignVCenter) + + self.sliderbottom = QtGui.QSlider(self) + self.sliderbottom.setMouseTracking(False) + self.sliderbottom.setProperty("value", 0) + self.sliderbottom.setOrientation(QtCore.Qt.Horizontal) + self.sliderbottom.setInvertedAppearance(False) + self.sliderbottom.setInvertedControls(False) + self.sliderbottom.setTickPosition(QtGui.QSlider.TicksAbove) + self.sliderbottom.setTickInterval(100) + + self.bottomvalue = QtGui.QLabel('0', self) + self.bottomvalue.setMinimumSize(QtCore.QSize(30, 0)) + self.bottomvalue.setAlignment( + QtCore.Qt.AlignRight | + QtCore.Qt.AlignTrailing | + QtCore.Qt.AlignVCenter) + + self.verticalLayout.addLayout(hboxbottom) + hboxbottom.addWidget(labelbottom) + hboxbottom.addWidget(self.sliderbottom) + hboxbottom.addWidget(self.bottomvalue) + + # slider left + hboxleft = QtGui.QHBoxLayout() + labelleft = QtGui.QLabel('left', self) + labelleft.setMinimumSize(QtCore.QSize(50, 0)) + labelleft.setAlignment( + QtCore.Qt.AlignRight | + QtCore.Qt.AlignTrailing | + QtCore.Qt.AlignVCenter) + + self.sliderleft = QtGui.QSlider(self) + self.sliderleft.setMouseTracking(False) + self.sliderleft.setProperty("value", 0) + self.sliderleft.setOrientation(QtCore.Qt.Horizontal) + self.sliderleft.setInvertedAppearance(False) + self.sliderleft.setInvertedControls(False) + self.sliderleft.setTickPosition(QtGui.QSlider.TicksAbove) + self.sliderleft.setTickInterval(100) + + self.leftvalue = QtGui.QLabel('0', self) + self.leftvalue.setMinimumSize(QtCore.QSize(30, 0)) + self.leftvalue.setAlignment( + QtCore.Qt.AlignRight | + QtCore.Qt.AlignTrailing | + QtCore.Qt.AlignVCenter) + + self.verticalLayout.addLayout(hboxleft) + hboxleft.addWidget(labelleft) + hboxleft.addWidget(self.sliderleft) + hboxleft.addWidget(self.leftvalue) + + # slider right + hboxright = QtGui.QHBoxLayout() + self.labelright = QtGui.QLabel('right', self) + self.labelright.setMinimumSize(QtCore.QSize(50, 0)) + self.labelright.setAlignment( + QtCore.Qt.AlignRight | + QtCore.Qt.AlignTrailing | + QtCore.Qt.AlignVCenter) + + self.sliderright = QtGui.QSlider(self) + self.sliderright.setMouseTracking(False) + self.sliderright.setProperty("value", 0) + self.sliderright.setOrientation(QtCore.Qt.Horizontal) + self.sliderright.setInvertedAppearance(False) + self.sliderright.setInvertedControls(False) + self.sliderright.setTickPosition(QtGui.QSlider.TicksAbove) + self.sliderright.setTickInterval(100) + + self.rightvalue = QtGui.QLabel('0', self) + self.rightvalue.setMinimumSize(QtCore.QSize(30, 0)) + self.rightvalue.setAlignment( + QtCore.Qt.AlignRight | + QtCore.Qt.AlignTrailing | + QtCore.Qt.AlignVCenter) + + self.verticalLayout.addLayout(hboxright) + hboxright.addWidget(self.labelright) + hboxright.addWidget(self.sliderright) + hboxright.addWidget(self.rightvalue) + + # groupbox spacings + groupbox = QtGui.QGroupBox('Spacings', self) + gbox.addWidget(groupbox, 7, 0, 1, 1) + self.verticalLayout = QtGui.QVBoxLayout(groupbox) + self.verticalLayout.setSpacing(0) + + # slider hspace + hboxhspace = QtGui.QHBoxLayout() + self.labelhspace = QtGui.QLabel('hspace', self) + self.labelhspace.setMinimumSize(QtCore.QSize(50, 0)) + self.labelhspace.setAlignment( + QtCore.Qt.AlignRight | + QtCore.Qt.AlignTrailing | + QtCore.Qt.AlignVCenter) + + self.sliderhspace = QtGui.QSlider(self) + self.sliderhspace.setMouseTracking(False) + self.sliderhspace.setProperty("value", 0) + self.sliderhspace.setOrientation(QtCore.Qt.Horizontal) + self.sliderhspace.setInvertedAppearance(False) + self.sliderhspace.setInvertedControls(False) + self.sliderhspace.setTickPosition(QtGui.QSlider.TicksAbove) + self.sliderhspace.setTickInterval(100) + + self.hspacevalue = QtGui.QLabel('0', self) + self.hspacevalue.setMinimumSize(QtCore.QSize(30, 0)) + self.hspacevalue.setAlignment( + QtCore.Qt.AlignRight | + QtCore.Qt.AlignTrailing | + QtCore.Qt.AlignVCenter) + + self.verticalLayout.addLayout(hboxhspace) + hboxhspace.addWidget(self.labelhspace) + hboxhspace.addWidget(self.sliderhspace) + hboxhspace.addWidget(self.hspacevalue) # slider hspace + + # slider wspace + hboxwspace = QtGui.QHBoxLayout() + self.labelwspace = QtGui.QLabel('wspace', self) + self.labelwspace.setMinimumSize(QtCore.QSize(50, 0)) + self.labelwspace.setAlignment( + QtCore.Qt.AlignRight | + QtCore.Qt.AlignTrailing | + QtCore.Qt.AlignVCenter) + + self.sliderwspace = QtGui.QSlider(self) + self.sliderwspace.setMouseTracking(False) + self.sliderwspace.setProperty("value", 0) + self.sliderwspace.setOrientation(QtCore.Qt.Horizontal) + self.sliderwspace.setInvertedAppearance(False) + self.sliderwspace.setInvertedControls(False) + self.sliderwspace.setTickPosition(QtGui.QSlider.TicksAbove) + self.sliderwspace.setTickInterval(100) + + self.wspacevalue = QtGui.QLabel('0', self) + self.wspacevalue.setMinimumSize(QtCore.QSize(30, 0)) + self.wspacevalue.setAlignment( + QtCore.Qt.AlignRight | + QtCore.Qt.AlignTrailing | + QtCore.Qt.AlignVCenter) + + self.verticalLayout.addLayout(hboxwspace) + hboxwspace.addWidget(self.labelwspace) + hboxwspace.addWidget(self.sliderwspace) + hboxwspace.addWidget(self.wspacevalue) + + # button bar + hbox2 = QtGui.QHBoxLayout() + gbox.addLayout(hbox2, 8, 0, 1, 1) + self.tightLayout = QtGui.QPushButton('Thight Layout', self) + spacer = QtGui.QSpacerItem( + 5, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) + self.resetButton = QtGui.QPushButton('Reset', self) + self.doneButton = QtGui.QPushButton('Close', self) + self.doneButton.setFocus(True) + hbox2.addWidget(self.tightLayout) + hbox2.addItem(spacer) + hbox2.addWidget(self.resetButton) + hbox2.addWidget(self.doneButton) + + self.connect(self.doneButton, QtCore.SIGNAL("clicked()"), self.accept)