Source code for camelot.view.controls.editors.charteditor

#  ============================================================================
#
#  Copyright (C) 2007-2011 Conceptive Engineering bvba. All rights reserved.
#  www.conceptive.be / project-camelot@conceptive.be
#
#  This file is part of the Camelot Library.
#
#  This file may be used under the terms of the GNU General Public
#  License version 2.0 as published by the Free Software Foundation
#  and appearing in the file license.txt included in the packaging of
#  this file.  Please review this information to ensure GNU
#  General Public Licensing requirements will be met.
#
#  If you are unsure which license is appropriate for your use, please
#  visit www.python-camelot.com or contact project-camelot@conceptive.be
#
#  This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
#  WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#
#  For use of this library in commercial applications, please contact
#  project-camelot@conceptive.be
#
#  ============================================================================

import logging

from PyQt4 import QtGui
from PyQt4 import QtCore

from camelot.view.controls.editors.customeditor import CustomEditor
from camelot.view.controls.editors.wideeditor import WideEditor
from camelot.view.proxy import ValueLoading
from camelot.view.art import Icon
from camelot.core.utils import ugettext as _

PAD_INCHES = 0.1

LOGGER = logging.getLogger('camelot.view.controls.editors.charteditor')

[docs]class ChartEditor(QtGui.QFrame, CustomEditor, WideEditor): """Editor to display and manipulate matplotlib charts. The editor itself is generic for all kinds of plots, it simply provides the data to be ploted with a set of axes. The data itself should know how exactly to plot itself. """ show_fullscreen_signal = QtCore.pyqtSignal() editingFinished = QtCore.pyqtSignal() def __init__(self, parent=None, width=50, height=40, dpi=50, field_name='chart', **kwargs): from matplotlib.figure import Figure from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas super(ChartEditor, self).__init__(parent) self.setObjectName( field_name ) chart_frame = QtGui.QFrame( self ) chart_frame.setFrameShape( self.Box ) chart_frame.setContentsMargins( 1, 1, 1, 1 ) chart_frame_layout = QtGui.QHBoxLayout() chart_frame_layout.setContentsMargins( 0, 0, 0, 0) chart_frame.setLayout( chart_frame_layout ) # find out background color, because using a transparent # figure fails when the window is resized: the background # is not redrawn # need to do str() else matplotlib gets confused by the qstring # bgcolorrgb = str(self.palette().background().color().name()) self.fig = Figure( figsize=(width, height), dpi=dpi, facecolor='#ffffff', ) layout = QtGui.QHBoxLayout() self.canvas = FigureCanvas( self.fig ) chart_frame_layout.addWidget( self.canvas ) layout.addWidget(chart_frame) button_layout = QtGui.QVBoxLayout() button_layout.setSpacing( 0 ) icon = Icon( 'tango/16x16/actions/document-print-preview.png' ).getQIcon() button_layout.addStretch() print_button = QtGui.QToolButton() print_button.setIcon( icon ) print_button.setAutoRaise( True ) print_button.setToolTip( _('Print Preview') ) print_button.clicked.connect( self.print_preview ) button_layout.addWidget( print_button ) icon = Icon( 'tango/16x16/actions/edit-copy.png' ).getQIcon() copy_button = QtGui.QToolButton() copy_button.setIcon( icon ) copy_button.setAutoRaise( True ) copy_button.setToolTip( _('Copy to clipboard') ) copy_button.clicked.connect( self.copy_to_clipboard ) button_layout.addWidget( copy_button ) layout.addLayout( button_layout ) layout.setContentsMargins( 0, 0, 0, 0) self.setLayout(layout) self.canvas.setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding ) self.canvas.installEventFilter(self) self.show_fullscreen_signal.connect(self.show_fullscreen) self.canvas.updateGeometry() self._litebox = None @QtCore.pyqtSlot()
[docs] def copy_to_clipboard(self): """Copy the chart to the clipboard""" clipboard = QtGui.QApplication.clipboard() pixmap = QtGui.QPixmap.grabWidget( self.canvas ) clipboard.setPixmap( pixmap )
@QtCore.pyqtSlot()
[docs] def print_preview(self): """Popup a print preview dialog for the Chart""" dialog = QtGui.QPrintPreviewDialog() dialog.paintRequested.connect( self.on_paint_request ) dialog.exec_()
@QtCore.pyqtSlot( QtGui.QPrinter )
[docs] def on_paint_request(self, printer): from matplotlib.figure import Figure from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas rect = printer.pageRect( QtGui.QPrinter.Inch ) dpi = printer.resolution() fig = Figure( facecolor='#ffffff') fig.set_figsize_inches( (rect.width(),rect.height()) ) fig.set_dpi( dpi ) self._value.plot_on_figure( fig ) canvas = FigureCanvas(fig) canvas.render( printer )
[docs] def set_field_attributes(self, *args, **kwargs): """Overwrite set_field attributes because a ChartEditor cannot be disabled or have its background color changed""" pass
@staticmethod
[docs] def show_fullscreen_chart(chart, parent): """ :param chart: a chart container :return: the widget showing the chart, by default a LiteBoxView """ from matplotlib.figure import Figure from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas from camelot.view.controls.liteboxview import LiteBoxView from camelot.container.chartcontainer import structure_to_figure_container figure_container = structure_to_figure_container( chart ) litebox = LiteBoxView(parent) fig = Figure(facecolor='#ffffff') canvas = FigureCanvas(fig) canvas.updateGeometry() figure_container.plot_on_figure(fig) proxy = QtGui.QGraphicsProxyWidget() proxy.setWidget(canvas) litebox.show_fullscreen_item(proxy) canvas.draw() return litebox
@QtCore.pyqtSlot()
[docs] def show_fullscreen(self): """Show the plot full screen, using the litebox""" if self._value: # if we give the litebox a parent, the close button does not work ?? self._litebox = self.show_fullscreen_chart(self._value, None)
[docs] def eventFilter(self, object, event): """intercept mouse clicks on a chart to show the chart fullscreen""" if not object.isWidgetType(): return False if event.type() != QtCore.QEvent.MouseButtonPress: return False if event.modifiers() != QtCore.Qt.NoModifier: return False if event.buttons() == QtCore.Qt.LeftButton: self.show_fullscreen_signal.emit() return True return False
[docs] def set_value(self, value): """Accepts a camelot.container.chartcontainer.FigureContainer or a camelot.container.chartcontainer.AxesContainer """ from camelot.container.chartcontainer import structure_to_figure_container self._value = structure_to_figure_container( super(ChartEditor, self).set_value(value) ) self.on_draw() # def _get_tightbbox(self, fig, pad_inches): # renderer = fig.canvas.get_renderer() # bbox_inches = fig.get_tightbbox(renderer) # return bbox_inches.padded(pad_inches) # # def tight_borders(self, fig, pad_inches=PAD_INCHES): # """Stretch subplot boundaries to figure edges plus padding.""" # # call draw to update the renderer and get accurate bboxes. # import numpy as np # fig.canvas.draw() # bbox_original = fig.bbox_inches # bbox_tight = self._get_tightbbox(fig, pad_inches) # # print bbox_tight # # # figure dimensions ordered like bbox.extents: x0, y0, x1, y1 # lengths = np.array([bbox_original.width, bbox_original.height, # bbox_original.width, bbox_original.height]) # whitespace = (bbox_tight.extents - bbox_original.extents) / lengths # # # border padding ordered like bbox.extents: x0, y0, x1, y1 # current_borders = np.array([fig.subplotpars.left, fig.subplotpars.bottom, # fig.subplotpars.right, fig.subplotpars.top]) # # # left, bottom, right, top = current_borders - whitespace # print self.canvas.size() # print left, bottom, right, top # fig.subplots_adjust(bottom=bottom, top=top, left=left, right=right)
[docs] def on_draw(self): """draw the matplotlib figure on the canvas""" if self._value not in (None, ValueLoading): self._value.plot_on_figure(self.fig) self.canvas.draw() # renderer = self.fig.canvas.get_renderer() # print 'widget size', self.canvas.size() # print 'renderer size', renderer.get_canvas_width_height() # print 'points_to_pixels', renderer.points_to_pixels(1.0) # print 'tightbbox', self.fig.get_tightbbox(renderer) # #self.fig.subplots_adjust(bottom=0.3, right=0.9, top=0.9, left=0.1) # self.tight_borders(self.fig) # self.canvas.draw()

Comments
blog comments powered by Disqus