Skip to content

New layout for qt4 subplottool + QMainWindow -> QDialog #2594

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

Merged
merged 5 commits into from
Nov 30, 2013
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
11 changes: 11 additions & 0 deletions doc/users/whats_new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,17 @@ You can add your own custom ``<style name>.mplstyle`` files to
*Note that this is an experimental feature*, and the interface may change as
users test out this new feature.

Backends
--------

Qt4 backend
``````````````
Rudolf Höfler changed the appearance of the subplottool. All sliders are
vertically arranged now, buttons for tight layout and reset were
added. Furthermore, the the subplottool is now implemented as a modal
dialog. It was previously a QMainWindow, leaving the SPT open if one closed the
plotwindow.

.. _whats-new-1-3:

new in matplotlib-1.3
Expand Down
149 changes: 54 additions & 95 deletions lib/matplotlib/backends/backend_qt4.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__

Expand Down Expand Up @@ -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"""
Expand Down Expand Up @@ -628,9 +630,8 @@ def edit_parameters(self):
titles.append(fmt % dict(title=title,
ylabel=ylabel,
axes_repr=repr(axes)))
item, ok = QtGui.QInputDialog.getItem(self, 'Customize',
'Select axes:', titles,
0, False)
item, ok = QtGui.QInputDialog.getItem(
self.parent, 'Customize', 'Select axes:', titles, 0, False)
if ok:
axes = allaxes[titles.index(six.text_type(item))]
else:
Expand Down Expand Up @@ -676,20 +677,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)
Expand All @@ -712,8 +704,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
Expand All @@ -730,132 +723,98 @@ 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)
self.donebutton.clicked.connect(self.close)
self.resetbutton.clicked.connect(self.reset)
self.tightlayout.clicked.connect(self.functight)

# 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)

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):
self.defaults = {}
for attr in ('left', 'bottom', 'right', 'top', 'wspace', 'hspace',):
self.defaults[attr] = getattr(self.targetfig.subplotpars, attr)
slider = getattr(self, 'slider' + attr)
slider.setMinimum(0)
slider.setMaximum(1000)
slider.setSingleStep(5)
slider.valueChanged.connect(getattr(self, 'func' + attr))

self._setSliderPositions()

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))
self.sliderbottom.setSliderPosition(
int(targetfig.subplotpars.bottom*1000))
self.sliderright.setSliderPosition(
int(targetfig.subplotpars.right*1000))
self.slidertop.setSliderPosition(int(targetfig.subplotpars.top*1000))
self.sliderwspace.setSliderPosition(
int(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)
def _setSliderPositions(self):
for attr in ('left', 'bottom', 'right', 'top', 'wspace', 'hspace',):
slider = getattr(self, 'slider' + attr)
slider.setSliderPosition(int(self.defaults[attr] * 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):
Expand Down
Loading