10 from cStringIO
import StringIO
12 from io
import BytesIO
as StringIO
14 from cv_bridge
import CvBridge
15 from distutils.version
import LooseVersion
16 from matplotlib.figure
import Figure
18 import python_qt_binding
19 from python_qt_binding
import loadUi
20 from python_qt_binding.QtCore
import Qt
21 from python_qt_binding.QtCore
import QTimer
22 from python_qt_binding.QtCore
import Slot
23 from python_qt_binding.QtGui
import QIcon
30 from sensor_msgs.msg
import Image
31 from sklearn
import linear_model
33 from jsk_recognition_msgs.msg
import PlotData
34 from jsk_recognition_msgs.msg
import PlotDataArray
37 if LooseVersion(python_qt_binding.QT_BINDING_VERSION).version[0] >= 5:
38 from python_qt_binding.QtWidgets
import QSizePolicy
39 from python_qt_binding.QtWidgets
import QVBoxLayout
40 from python_qt_binding.QtWidgets
import QWidget
42 from matplotlib.backends.backend_qt5agg
import FigureCanvasQTAgg \
47 sys.modules[
'_thread'] = thread
48 from matplotlib.backends.backend_qt5agg
import FigureCanvasQTAgg \
51 from matplotlib.backends.backend_qt5agg
import NavigationToolbar2QTAgg \
54 from matplotlib.backends.backend_qt5agg
import NavigationToolbar2QT \
57 from python_qt_binding.QtGui
import QSizePolicy
58 from python_qt_binding.QtGui
import QVBoxLayout
59 from python_qt_binding.QtGui
import QWidget
61 from matplotlib.backends.backend_qt4agg
import FigureCanvasQTAgg \
66 sys.modules[
'_thread'] = thread
67 from matplotlib.backends.backend_qt4agg
import FigureCanvasQTAgg \
70 from matplotlib.backends.backend_qt4agg
import NavigationToolbar2QTAgg \
73 from matplotlib.backends.backend_qt4agg
import NavigationToolbar2QT \
82 if not self.field_evals:
84 for f
in self.field_evals:
89 "{0} index error for: {1}".format(
90 self.name, str(val).replace(
'\n',
', ')))
93 "{0} value was not numeric: {1}".format(
99 "xss = [[0, 1, 2, ...], [0, 1, 2, ...], ...]"
109 super(Plot2D, self).
__init__(context)
110 self.setObjectName(
'Plot2D')
115 self.
_widget.fit_line_ransac = self.
_args.fit_line_ransac
116 outlier = self.
_args.fit_line_ransac_outlier
117 self.
_widget.fit_line_ransac_outlier = outlier
122 context.add_widget(self.
_widget)
125 parser = argparse.ArgumentParser(
126 prog=
'rqt_histogram_plot', add_help=
False)
127 Plot2D.add_arguments(parser)
128 args = parser.parse_args(argv)
133 group = parser.add_argument_group(
134 'Options for rqt_histogram plugin')
136 'topics', nargs=
'?', default=[], help=
'Topics to plot')
138 '--line', action=
"store_true",
139 help=
"Plot with lines instead of scatter")
141 '--fit-line', action=
"store_true",
142 help=
"Plot line with least-square fitting")
144 '--fit-line-ransac', action=
"store_true",
145 help=
"Plot line with RANSAC")
147 '--fit-line-ransac-outlier', type=float, default=0.1,
148 help=
"Plot line with RANSAC")
149 group.add_argument(
'--xtitle', help=
"Title in X axis")
150 group.add_argument(
'--ytitle', help=
"Title in Y axis")
151 group.add_argument(
'--no-legend', action=
"store_true")
152 group.add_argument(
'--sort-x', action=
"store_true")
156 _redraw_interval = 10
159 super(Plot2DWidget, self).
__init__()
160 self.setObjectName(
'Plot2DWidget')
161 rp = rospkg.RosPack()
162 ui_file = os.path.join(
163 rp.get_path(
'jsk_rqt_plugins'),
'resource',
'plot_histogram.ui')
164 loadUi(ui_file, self)
166 self.subscribe_topic_button.setIcon(QIcon.fromTheme(
'add'))
167 self.pause_button.setIcon(QIcon.fromTheme(
'media-playback-pause'))
168 self.clear_button.setIcon(QIcon.fromTheme(
'edit-clear'))
170 self.data_plot_layout.addWidget(self.
data_plot)
175 self.
data_plot.dragEnterEvent = self.dragEnterEvent
186 if event.mimeData().hasText():
187 topic_name = str(event.mimeData().text())
189 droped_item = event.source().selectedItems()[0]
190 topic_name = str(droped_item.data(0, Qt.UserRole))
195 "callback function when form is entered"
196 if self.subscribe_topic_button.isEnabled():
204 rospy.loginfo(
"subscribe topic")
207 topic_name +
"/plot_image", Image, queue_size=1)
216 rospy.logwarn(
"%s is already subscribed", topic_name)
233 concatenated_data = list(zip(msg.xs, msg.ys))
235 concatenated_data.sort(key=
lambda x: x[0])
236 xs = [d[0]
for d
in concatenated_data]
237 ys = [d[1]
for d
in concatenated_data]
238 if self.is_line
or msg.type
is PlotData.LINE:
244 if msg.fit_line
or self.fit_line:
247 A = np.array([X, np.ones(len(X))])
249 a, b = np.linalg.lstsq(A, Y, rcond=-1)[0]
250 axes.plot(X, (a*X+b),
"g--", label=
"{0} x + {1}".format(a, b))
251 if msg.fit_line_ransac
or self.fit_line_ransac:
252 model_ransac = linear_model.RANSACRegressor(
253 linear_model.LinearRegression(), min_samples=2,
254 residual_threshold=self.fit_line_ransac_outlier)
255 X = np.array(msg.xs).reshape((len(msg.xs), 1))
257 model_ransac.fit(X, Y)
259 line_y_ransac = model_ransac.predict(line_X)
260 if len(model_ransac.estimator_.coef_) == 1:
261 coef = model_ransac.estimator_.coef_[0]
263 coef = model_ransac.estimator_.coef_[0][0]
264 if not isinstance(model_ransac.estimator_.intercept_, list):
265 intercept = model_ransac.estimator_.intercept_
267 intercept = model_ransac.estimator_.intercept_[0]
269 line_X, line_y_ransac,
"r--",
270 label=
"{0} x + {1}".format(coef, intercept))
276 data_x, data_y = self.
_rosdata.next()
277 except RosPlotException
as e:
278 rospy.logerr(
"Exception in subscribing topic")
279 rospy.logerr(e.message)
287 latest_msg = data_y[-1]
292 if isinstance(latest_msg, PlotData):
296 elif isinstance(latest_msg, PlotDataArray):
297 data = latest_msg.data
298 legend_size = latest_msg.legend_font_size
or 8
299 no_legend = latest_msg.no_legend
300 if latest_msg.min_x != latest_msg.max_x:
301 min_x = latest_msg.min_x
302 max_x = latest_msg.max_x
303 if latest_msg.min_y != latest_msg.max_y:
304 min_y = latest_msg.min_y
305 max_y = latest_msg.max_y
308 "Topic should be jsk_recognition_msgs/PlotData",
309 "or jsk_recognition_msgs/PlotDataArray")
322 axes.set_xlim(min_x, max_x)
323 axes.set_ylim(min_y, max_y)
325 if not no_legend
and not self.no_legend:
326 axes.legend(prop={
'size': legend_size})
329 axes.set_xlabel(self.xtitle)
331 axes.set_ylabel(self.ytitle)
334 self.
data_plot._canvas.figure.savefig(buffer, format=
"png")
336 img_array = np.asarray(bytearray(buffer.read()), dtype=np.uint8)
337 if LooseVersion(cv2.__version__).version[0] < 2:
338 iscolor = cv2.CV_LOAD_IMAGE_COLOR
340 iscolor = cv2.IMREAD_COLOR
341 img = cv2.imdecode(img_array, iscolor)
350 self.
axes = self.figure.add_subplot(111)
351 self.figure.tight_layout()
352 self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
353 self.updateGeometry()
357 self.figure.tight_layout()
360 super(MatPlot2D, self).
__init__(parent)
372 self._canvas.axes.cla()