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