00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 from __future__ import division
00035 import math
00036 import sys
00037
00038 from python_qt_binding.QtCore import QEvent, QSize, QPointF, Qt, SIGNAL, Signal, Slot, qWarning
00039 from python_qt_binding.QtGui import QColor, QPen, QBrush, QVector2D
00040 import Qwt
00041
00042 from numpy import arange, zeros, concatenate
00043
00044
00045
00046 class QwtDataPlot(Qwt.QwtPlot):
00047 mouseCoordinatesChanged = Signal(QPointF)
00048 _num_value_saved = 1000
00049 _num_values_ploted = 1000
00050
00051 limits_changed = Signal()
00052
00053 def __init__(self, *args):
00054 super(QwtDataPlot, self).__init__(*args)
00055 self.setCanvasBackground(Qt.white)
00056 self.insertLegend(Qwt.QwtLegend(), Qwt.QwtPlot.BottomLegend)
00057
00058 self._curves = {}
00059
00060
00061
00062
00063
00064
00065 self._x_limits = [0.0, 10.0]
00066 self._y_limits = [0.0, 10.0]
00067
00068
00069 self._last_canvas_x = 0
00070 self._last_canvas_y = 0
00071 self._pressed_canvas_y = 0
00072 self._pressed_canvas_x = 0
00073 self._last_click_coordinates = None
00074
00075 marker_axis_y = Qwt.QwtPlotMarker()
00076 marker_axis_y.setLabelAlignment(Qt.AlignRight | Qt.AlignTop)
00077 marker_axis_y.setLineStyle(Qwt.QwtPlotMarker.HLine)
00078 marker_axis_y.setYValue(0.0)
00079 marker_axis_y.attach(self)
00080
00081 self._picker = Qwt.QwtPlotPicker(
00082 Qwt.QwtPlot.xBottom, Qwt.QwtPlot.yLeft, Qwt.QwtPicker.PolygonSelection,
00083 Qwt.QwtPlotPicker.PolygonRubberBand, Qwt.QwtPicker.AlwaysOn, self.canvas()
00084 )
00085 self._picker.setRubberBandPen(QPen(Qt.blue))
00086 self._picker.setTrackerPen(QPen(Qt.blue))
00087
00088
00089 self.rescale()
00090
00091 self.canvas().setMouseTracking(True)
00092 self.canvas().installEventFilter(self)
00093
00094 def eventFilter(self, _, event):
00095 if event.type() == QEvent.MouseButtonRelease:
00096 x = self.invTransform(Qwt.QwtPlot.xBottom, event.pos().x())
00097 y = self.invTransform(Qwt.QwtPlot.yLeft, event.pos().y())
00098 self._last_click_coordinates = QPointF(x, y)
00099 self.limits_changed.emit()
00100 elif event.type() == QEvent.MouseMove:
00101 x = self.invTransform(Qwt.QwtPlot.xBottom, event.pos().x())
00102 y = self.invTransform(Qwt.QwtPlot.yLeft, event.pos().y())
00103 coords = QPointF(x, y)
00104 if self._picker.isActive() and self._last_click_coordinates is not None:
00105 toolTip = 'origin x: %.5f, y: %.5f' % (self._last_click_coordinates.x(), self._last_click_coordinates.y())
00106 delta = coords - self._last_click_coordinates
00107 toolTip += '\ndelta x: %.5f, y: %.5f\nlength: %.5f' % (delta.x(), delta.y(), QVector2D(delta).length())
00108 else:
00109 toolTip = 'buttons\nleft: measure\nmiddle: move\nright: zoom x/y\nwheel: zoom y'
00110 self.setToolTip(toolTip)
00111 self.mouseCoordinatesChanged.emit(coords)
00112 return False
00113
00114 def log(self, level, message):
00115 self.emit(SIGNAL('logMessage'), level, message)
00116
00117 def resizeEvent(self, event):
00118 Qwt.QwtPlot.resizeEvent(self, event)
00119 self.rescale()
00120
00121 def add_curve(self, curve_id, curve_name, curve_color=QColor(Qt.blue), markers_on=False):
00122 curve_id = str(curve_id)
00123 if curve_id in self._curves:
00124 return
00125 curve_object = Qwt.QwtPlotCurve(curve_name)
00126 curve_object.attach(self)
00127 curve_object.setPen(curve_color)
00128 if markers_on:
00129 curve_object.setSymbol(Qwt.QwtSymbol(Qwt.QwtSymbol.Ellipse, QBrush(curve_color), QPen(Qt.black), QSize(4,4)))
00130 self._curves[curve_id] = curve_object
00131
00132 def remove_curve(self, curve_id):
00133 curve_id = str(curve_id)
00134 if curve_id in self._curves:
00135 self._curves[curve_id].hide()
00136 self._curves[curve_id].attach(None)
00137 del self._curves[curve_id]
00138
00139 def set_values(self, curve_id, data_x, data_y):
00140 curve = self._curves[curve_id]
00141 curve.setData(data_x, data_y)
00142
00143 def redraw(self):
00144 self.replot()
00145
00146
00147
00148
00149 def rescale(self):
00150 self.setAxisScale(Qwt.QwtPlot.yLeft,
00151 self._y_limits[0],
00152 self._y_limits[1])
00153 self.setAxisScale(Qwt.QwtPlot.xBottom,
00154 self._x_limits[0],
00155 self._x_limits[1])
00156
00157 self._canvas_display_height = self._y_limits[1] - self._y_limits[0]
00158 self._canvas_display_width = self._x_limits[1] - self._x_limits[0]
00159 self.redraw()
00160
00161 def rescale_axis_x(self, delta__x):
00162 """
00163 add delta_x to the length of the x axis
00164 """
00165 x_width = self._x_limits[1] - self._x_limits[0]
00166 x_width += delta__x
00167 self._x_limits[1] = x_width + self._x_limits[0]
00168 self.rescale()
00169
00170 def scale_axis_y(self, max_value):
00171 """
00172 set the y axis height to max_value, about the current center
00173 """
00174 canvas_display_height = max_value
00175 canvas_offset_y = (self._y_limits[1] + self._y_limits[0])/2.0
00176 y_lower_limit = canvas_offset_y - (canvas_display_height / 2)
00177 y_upper_limit = canvas_offset_y + (canvas_display_height / 2)
00178 self._y_limits = [y_lower_limit, y_upper_limit]
00179 self.rescale()
00180
00181 def move_canvas(self, delta_x, delta_y):
00182 """
00183 move the canvas by delta_x and delta_y in SCREEN COORDINATES
00184 """
00185 canvas_offset_x = delta_x * self._canvas_display_width / self.canvas().width()
00186 canvas_offset_y = delta_y * self._canvas_display_height / self.canvas().height()
00187 self._x_limits = [ l + canvas_offset_x for l in self._x_limits]
00188 self._y_limits = [ l + canvas_offset_y for l in self._y_limits]
00189 self.rescale()
00190
00191 def mousePressEvent(self, event):
00192 self._last_canvas_x = event.x() - self.canvas().x()
00193 self._last_canvas_y = event.y() - self.canvas().y()
00194 self._pressed_canvas_y = event.y() - self.canvas().y()
00195
00196 def mouseMoveEvent(self, event):
00197 canvas_x = event.x() - self.canvas().x()
00198 canvas_y = event.y() - self.canvas().y()
00199 if event.buttons() & Qt.MiddleButton:
00200 delta_x = self._last_canvas_x - canvas_x
00201 delta_y = canvas_y - self._last_canvas_y
00202 self.move_canvas(delta_x, delta_y)
00203 elif event.buttons() & Qt.RightButton:
00204 zoom_factor = max(-0.6, min(0.6, (self._last_canvas_y - canvas_y) / 20.0 / 2.0))
00205 delta_y = (self.canvas().height() / 2.0) - self._pressed_canvas_y
00206 self.move_canvas(0, zoom_factor * delta_y * 1.0225)
00207 self.scale_axis_y(max(0.005, self._canvas_display_height - (zoom_factor * self._canvas_display_height)))
00208 self.rescale_axis_x(self._last_canvas_x - canvas_x)
00209 self._last_canvas_x = canvas_x
00210 self._last_canvas_y = canvas_y
00211
00212 def wheelEvent(self, event):
00213
00214 canvas_y = event.y() - self.canvas().y()
00215
00216 zoom_factor = max(-0.6, min(0.6, (event.delta() / 120) / 6.0))
00217 delta_y = (self.canvas().height() / 2.0) - canvas_y
00218 self.move_canvas(0, zoom_factor * delta_y * 1.0225)
00219
00220 self.scale_axis_y(max(0.0005, self._canvas_display_height - zoom_factor * self._canvas_display_height))
00221 self.limits_changed.emit()
00222
00223
00224 def vline(self, x, color):
00225 qWarning("QwtDataPlot.vline is not implemented yet")
00226
00227 def set_xlim(self, limits):
00228 self.setAxisScale(Qwt.QwtPlot.xBottom, limits[0], limits[1])
00229 self._x_limits = limits
00230
00231 def set_ylim(self, limits):
00232 self.setAxisScale(Qwt.QwtPlot.yLeft, limits[0], limits[1])
00233 self._y_limits = limits
00234
00235 def get_xlim(self):
00236 return self._x_limits
00237
00238 def get_ylim(self):
00239 return self._y_limits
00240
00241
00242 if __name__ == '__main__':
00243 from python_qt_binding.QtGui import QApplication
00244
00245 app = QApplication(sys.argv)
00246 plot = QwtDataPlot()
00247 plot.resize(700, 500)
00248 plot.show()
00249 plot.add_curve(0, '(x/500)^2')
00250 plot.add_curve(1, 'sin(x / 20) * 500')
00251 for i in range(plot._num_value_saved):
00252 plot.update_value(0, (i / 500.0) * (i / 5.0))
00253 plot.update_value(1, math.sin(i / 20.0) * 500)
00254
00255 sys.exit(app.exec_())