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, 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
00116 pass
00117
00118 def resizeEvent(self, event):
00119 Qwt.QwtPlot.resizeEvent(self, event)
00120 self.rescale()
00121
00122 def add_curve(self, curve_id, curve_name, curve_color=QColor(Qt.blue), markers_on=False):
00123 curve_id = str(curve_id)
00124 if curve_id in self._curves:
00125 return
00126 curve_object = Qwt.QwtPlotCurve(curve_name)
00127 curve_object.attach(self)
00128 curve_object.setPen(curve_color)
00129 if markers_on:
00130 curve_object.setSymbol(Qwt.QwtSymbol(Qwt.QwtSymbol.Ellipse, QBrush(curve_color), QPen(Qt.black), QSize(4,4)))
00131 self._curves[curve_id] = curve_object
00132
00133 def remove_curve(self, curve_id):
00134 curve_id = str(curve_id)
00135 if curve_id in self._curves:
00136 self._curves[curve_id].hide()
00137 self._curves[curve_id].attach(None)
00138 del self._curves[curve_id]
00139
00140 def set_values(self, curve_id, data_x, data_y):
00141 curve = self._curves[curve_id]
00142 curve.setData(data_x, data_y)
00143
00144 def redraw(self):
00145 self.replot()
00146
00147
00148
00149
00150 def rescale(self):
00151 self.setAxisScale(Qwt.QwtPlot.yLeft,
00152 self._y_limits[0],
00153 self._y_limits[1])
00154 self.setAxisScale(Qwt.QwtPlot.xBottom,
00155 self._x_limits[0],
00156 self._x_limits[1])
00157
00158 self._canvas_display_height = self._y_limits[1] - self._y_limits[0]
00159 self._canvas_display_width = self._x_limits[1] - self._x_limits[0]
00160 self.redraw()
00161
00162 def rescale_axis_x(self, delta__x):
00163 """
00164 add delta_x to the length of the x axis
00165 """
00166 x_width = self._x_limits[1] - self._x_limits[0]
00167 x_width += delta__x
00168 self._x_limits[1] = x_width + self._x_limits[0]
00169 self.rescale()
00170
00171 def scale_axis_y(self, max_value):
00172 """
00173 set the y axis height to max_value, about the current center
00174 """
00175 canvas_display_height = max_value
00176 canvas_offset_y = (self._y_limits[1] + self._y_limits[0])/2.0
00177 y_lower_limit = canvas_offset_y - (canvas_display_height / 2)
00178 y_upper_limit = canvas_offset_y + (canvas_display_height / 2)
00179 self._y_limits = [y_lower_limit, y_upper_limit]
00180 self.rescale()
00181
00182 def move_canvas(self, delta_x, delta_y):
00183 """
00184 move the canvas by delta_x and delta_y in SCREEN COORDINATES
00185 """
00186 canvas_offset_x = delta_x * self._canvas_display_width / self.canvas().width()
00187 canvas_offset_y = delta_y * self._canvas_display_height / self.canvas().height()
00188 self._x_limits = [ l + canvas_offset_x for l in self._x_limits]
00189 self._y_limits = [ l + canvas_offset_y for l in self._y_limits]
00190 self.rescale()
00191
00192 def mousePressEvent(self, event):
00193 self._last_canvas_x = event.x() - self.canvas().x()
00194 self._last_canvas_y = event.y() - self.canvas().y()
00195 self._pressed_canvas_y = event.y() - self.canvas().y()
00196
00197 def mouseMoveEvent(self, event):
00198 canvas_x = event.x() - self.canvas().x()
00199 canvas_y = event.y() - self.canvas().y()
00200 if event.buttons() & Qt.MiddleButton:
00201 delta_x = self._last_canvas_x - canvas_x
00202 delta_y = canvas_y - self._last_canvas_y
00203 self.move_canvas(delta_x, delta_y)
00204 elif event.buttons() & Qt.RightButton:
00205 zoom_factor = max(-0.6, min(0.6, (self._last_canvas_y - canvas_y) / 20.0 / 2.0))
00206 delta_y = (self.canvas().height() / 2.0) - self._pressed_canvas_y
00207 self.move_canvas(0, zoom_factor * delta_y * 1.0225)
00208 self.scale_axis_y(max(0.005, self._canvas_display_height - (zoom_factor * self._canvas_display_height)))
00209 self.rescale_axis_x(self._last_canvas_x - canvas_x)
00210 self._last_canvas_x = canvas_x
00211 self._last_canvas_y = canvas_y
00212
00213 def wheelEvent(self, event):
00214
00215 canvas_y = event.y() - self.canvas().y()
00216
00217 try:
00218 delta = event.angleDelta().y()
00219 except AttributeError:
00220 delta = event.delta()
00221 zoom_factor = max(-0.6, min(0.6, (delta / 120) / 6.0))
00222 delta_y = (self.canvas().height() / 2.0) - canvas_y
00223 self.move_canvas(0, zoom_factor * delta_y * 1.0225)
00224
00225 self.scale_axis_y(max(0.0005, self._canvas_display_height - zoom_factor * self._canvas_display_height))
00226 self.limits_changed.emit()
00227
00228
00229 def vline(self, x, color):
00230 qWarning("QwtDataPlot.vline is not implemented yet")
00231
00232 def set_xlim(self, limits):
00233 self.setAxisScale(Qwt.QwtPlot.xBottom, limits[0], limits[1])
00234 self._x_limits = limits
00235
00236 def set_ylim(self, limits):
00237 self.setAxisScale(Qwt.QwtPlot.yLeft, limits[0], limits[1])
00238 self._y_limits = limits
00239
00240 def get_xlim(self):
00241 return self._x_limits
00242
00243 def get_ylim(self):
00244 return self._y_limits
00245
00246
00247 if __name__ == '__main__':
00248 from python_qt_binding.QtGui import QApplication
00249
00250 app = QApplication(sys.argv)
00251 plot = QwtDataPlot()
00252 plot.resize(700, 500)
00253 plot.show()
00254 plot.add_curve(0, '(x/500)^2')
00255 plot.add_curve(1, 'sin(x / 20) * 500')
00256 for i in range(plot._num_value_saved):
00257 plot.update_value(0, (i / 500.0) * (i / 5.0))
00258 plot.update_value(1, math.sin(i / 20.0) * 500)
00259
00260 sys.exit(app.exec_())