blob: b29c09212ff56d5e43e047e9ecfd0d9f89bea9d9 [file] [log] [blame]
terelius54ce6802016-07-13 06:44:41 -07001/*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "rtc_tools/event_log_visualizer/plot_python.h"
terelius54ce6802016-07-13 06:44:41 -070012
13#include <stdio.h>
Jonas Olssona4d87372019-07-05 19:08:33 +020014
Stefan Holmer13181032016-07-29 14:48:54 +020015#include <memory>
Yves Gerey3e707812018-11-28 16:47:49 +010016#include <string>
17#include <vector>
terelius54ce6802016-07-13 06:44:41 -070018
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "rtc_base/checks.h"
philipel23c7f252017-07-14 06:30:03 -070020
terelius54ce6802016-07-13 06:44:41 -070021namespace webrtc {
terelius54ce6802016-07-13 06:44:41 -070022
23PythonPlot::PythonPlot() {}
24
25PythonPlot::~PythonPlot() {}
26
tereliusdc35dcd2016-08-01 12:03:27 -070027void PythonPlot::Draw() {
terelius54ce6802016-07-13 06:44:41 -070028 // Write python commands to stdout. Intended program usage is
29 // ./event_log_visualizer event_log160330.dump | python
30
tereliusdc35dcd2016-08-01 12:03:27 -070031 if (!series_list_.empty()) {
32 printf("color_count = %zu\n", series_list_.size());
terelius54ce6802016-07-13 06:44:41 -070033 printf(
34 "hls_colors = [(i*1.0/color_count, 0.25+i*0.5/color_count, 0.8) for i "
35 "in range(color_count)]\n");
Bjorn Tereliusb577d5e2017-11-10 16:21:34 +010036 printf("colors = [colorsys.hls_to_rgb(*hls) for hls in hls_colors]\n");
terelius54ce6802016-07-13 06:44:41 -070037
tereliusdc35dcd2016-08-01 12:03:27 -070038 for (size_t i = 0; i < series_list_.size(); i++) {
philipel35ba9bd2017-04-19 05:58:51 -070039 printf("\n# === Series: %s ===\n", series_list_[i].label.c_str());
terelius54ce6802016-07-13 06:44:41 -070040 // List x coordinates
41 printf("x%zu = [", i);
tereliusdc35dcd2016-08-01 12:03:27 -070042 if (series_list_[i].points.size() > 0)
Stefan Holmer1d4a2272018-05-24 13:48:09 +020043 printf("%.3f", series_list_[i].points[0].x);
tereliusdc35dcd2016-08-01 12:03:27 -070044 for (size_t j = 1; j < series_list_[i].points.size(); j++)
Stefan Holmer1d4a2272018-05-24 13:48:09 +020045 printf(", %.3f", series_list_[i].points[j].x);
terelius54ce6802016-07-13 06:44:41 -070046 printf("]\n");
47
48 // List y coordinates
49 printf("y%zu = [", i);
tereliusdc35dcd2016-08-01 12:03:27 -070050 if (series_list_[i].points.size() > 0)
51 printf("%G", series_list_[i].points[0].y);
52 for (size_t j = 1; j < series_list_[i].points.size(); j++)
53 printf(", %G", series_list_[i].points[j].y);
terelius54ce6802016-07-13 06:44:41 -070054 printf("]\n");
55
Bjorn Tereliusb577d5e2017-11-10 16:21:34 +010056 if (series_list_[i].line_style == LineStyle::kBar) {
terelius54ce6802016-07-13 06:44:41 -070057 // There is a plt.bar function that draws bar plots,
58 // but it is *way* too slow to be useful.
59 printf(
60 "plt.vlines(x%zu, map(lambda t: min(t,0), y%zu), map(lambda t: "
Bjorn Tereliusb577d5e2017-11-10 16:21:34 +010061 "max(t,0), y%zu), color=colors[%zu], "
terelius54ce6802016-07-13 06:44:41 -070062 "label=\'%s\')\n",
tereliusdc35dcd2016-08-01 12:03:27 -070063 i, i, i, i, series_list_[i].label.c_str());
Bjorn Tereliusb577d5e2017-11-10 16:21:34 +010064 if (series_list_[i].point_style == PointStyle::kHighlight) {
65 printf(
66 "plt.plot(x%zu, y%zu, color=colors[%zu], "
67 "marker='.', ls=' ')\n",
68 i, i, i);
69 }
70 } else if (series_list_[i].line_style == LineStyle::kLine) {
71 if (series_list_[i].point_style == PointStyle::kHighlight) {
72 printf(
73 "plt.plot(x%zu, y%zu, color=colors[%zu], label=\'%s\', "
74 "marker='.')\n",
75 i, i, i, series_list_[i].label.c_str());
76 } else {
77 printf("plt.plot(x%zu, y%zu, color=colors[%zu], label=\'%s\')\n", i,
78 i, i, series_list_[i].label.c_str());
79 }
80 } else if (series_list_[i].line_style == LineStyle::kStep) {
terelius77f05802017-02-01 06:34:53 -080081 // Draw lines from (x[0],y[0]) to (x[1],y[0]) to (x[1],y[1]) and so on
82 // to illustrate the "steps". This can be expressed by duplicating all
83 // elements except the first in x and the last in y.
Bjorn Tereliusb577d5e2017-11-10 16:21:34 +010084 printf("xd%zu = [dup for v in x%zu for dup in [v, v]]\n", i, i);
85 printf("yd%zu = [dup for v in y%zu for dup in [v, v]]\n", i, i);
terelius77f05802017-02-01 06:34:53 -080086 printf(
Bjorn Tereliusb577d5e2017-11-10 16:21:34 +010087 "plt.plot(xd%zu[1:], yd%zu[:-1], color=colors[%zu], "
terelius77f05802017-02-01 06:34:53 -080088 "label=\'%s\')\n",
89 i, i, i, series_list_[i].label.c_str());
Bjorn Tereliusb577d5e2017-11-10 16:21:34 +010090 if (series_list_[i].point_style == PointStyle::kHighlight) {
91 printf(
92 "plt.plot(x%zu, y%zu, color=colors[%zu], "
93 "marker='.', ls=' ')\n",
94 i, i, i);
95 }
96 } else if (series_list_[i].line_style == LineStyle::kNone) {
philipele127e7a2017-03-29 16:28:53 +020097 printf(
Bjorn Tereliusb577d5e2017-11-10 16:21:34 +010098 "plt.plot(x%zu, y%zu, color=colors[%zu], label=\'%s\', "
philipel10fc0e62017-04-11 01:50:23 -070099 "marker='o', ls=' ')\n",
philipele127e7a2017-03-29 16:28:53 +0200100 i, i, i, series_list_[i].label.c_str());
terelius54ce6802016-07-13 06:44:41 -0700101 } else {
102 printf("raise Exception(\"Unknown graph type\")\n");
103 }
104 }
philipel23c7f252017-07-14 06:30:03 -0700105
106 // IntervalSeries
Ilya Nikolaevskiya4259f62017-12-05 13:19:45 +0100107 printf("interval_colors = ['#ff8e82','#5092fc','#c4ffc4','#aaaaaa']\n");
108 RTC_CHECK_LE(interval_list_.size(), 4);
Bjorn Tereliusb577d5e2017-11-10 16:21:34 +0100109 // To get the intervals to show up in the legend we have to create patches
philipel23c7f252017-07-14 06:30:03 -0700110 // for them.
111 printf("legend_patches = []\n");
112 for (size_t i = 0; i < interval_list_.size(); i++) {
113 // List intervals
114 printf("\n# === IntervalSeries: %s ===\n",
115 interval_list_[i].label.c_str());
116 printf("ival%zu = [", i);
117 if (interval_list_[i].intervals.size() > 0) {
118 printf("(%G, %G)", interval_list_[i].intervals[0].begin,
119 interval_list_[i].intervals[0].end);
120 }
121 for (size_t j = 1; j < interval_list_[i].intervals.size(); j++) {
122 printf(", (%G, %G)", interval_list_[i].intervals[j].begin,
123 interval_list_[i].intervals[j].end);
124 }
125 printf("]\n");
126
127 printf("for i in range(0, %zu):\n", interval_list_[i].intervals.size());
128 if (interval_list_[i].orientation == IntervalSeries::kVertical) {
129 printf(
130 " plt.axhspan(ival%zu[i][0], ival%zu[i][1], "
131 "facecolor=interval_colors[%zu], "
132 "alpha=0.3)\n",
133 i, i, i);
134 } else {
135 printf(
136 " plt.axvspan(ival%zu[i][0], ival%zu[i][1], "
137 "facecolor=interval_colors[%zu], "
138 "alpha=0.3)\n",
139 i, i, i);
140 }
141 printf(
142 "legend_patches.append(mpatches.Patch(ec=\'black\', "
143 "fc=interval_colors[%zu], label='%s'))\n",
144 i, interval_list_[i].label.c_str());
145 }
terelius54ce6802016-07-13 06:44:41 -0700146 }
147
tereliusdc35dcd2016-08-01 12:03:27 -0700148 printf("plt.xlim(%f, %f)\n", xaxis_min_, xaxis_max_);
149 printf("plt.ylim(%f, %f)\n", yaxis_min_, yaxis_max_);
150 printf("plt.xlabel(\'%s\')\n", xaxis_label_.c_str());
151 printf("plt.ylabel(\'%s\')\n", yaxis_label_.c_str());
152 printf("plt.title(\'%s\')\n", title_.c_str());
philipel23c7f252017-07-14 06:30:03 -0700153 if (!series_list_.empty() || !interval_list_.empty()) {
154 printf("handles, labels = plt.gca().get_legend_handles_labels()\n");
155 printf("for lp in legend_patches:\n");
156 printf(" handles.append(lp)\n");
157 printf(" labels.append(lp.get_label())\n");
158 printf("plt.legend(handles, labels, loc=\'best\', fontsize=\'small\')\n");
terelius54ce6802016-07-13 06:44:41 -0700159 }
160}
161
Bjorn Tereliusff8cce32019-04-11 18:34:01 +0200162PythonPlotCollection::PythonPlotCollection(bool shared_xaxis)
163 : shared_xaxis_(shared_xaxis) {}
terelius54ce6802016-07-13 06:44:41 -0700164
165PythonPlotCollection::~PythonPlotCollection() {}
166
tereliusdc35dcd2016-08-01 12:03:27 -0700167void PythonPlotCollection::Draw() {
terelius54ce6802016-07-13 06:44:41 -0700168 printf("import matplotlib.pyplot as plt\n");
Konrad Hofbauer9316c1a2019-03-29 15:39:53 +0100169 printf("plt.rcParams.update({'figure.max_open_warning': 0})\n");
philipel23c7f252017-07-14 06:30:03 -0700170 printf("import matplotlib.patches as mpatches\n");
171 printf("import matplotlib.patheffects as pe\n");
terelius54ce6802016-07-13 06:44:41 -0700172 printf("import colorsys\n");
tereliusdc35dcd2016-08-01 12:03:27 -0700173 for (size_t i = 0; i < plots_.size(); i++) {
terelius54ce6802016-07-13 06:44:41 -0700174 printf("plt.figure(%zu)\n", i);
Bjorn Tereliusff8cce32019-04-11 18:34:01 +0200175 if (shared_xaxis_) {
176 // Link x-axes across all figures for synchronized zooming.
177 if (i == 0) {
178 printf("axis0 = plt.subplot(111)\n");
179 } else {
180 printf("plt.subplot(111, sharex=axis0)\n");
181 }
Konrad Hofbauer225f4f62019-03-26 13:23:54 +0100182 }
tereliusdc35dcd2016-08-01 12:03:27 -0700183 plots_[i]->Draw();
terelius54ce6802016-07-13 06:44:41 -0700184 }
185 printf("plt.show()\n");
186}
187
tereliusdc35dcd2016-08-01 12:03:27 -0700188Plot* PythonPlotCollection::AppendNewPlot() {
terelius54ce6802016-07-13 06:44:41 -0700189 Plot* plot = new PythonPlot();
tereliusdc35dcd2016-08-01 12:03:27 -0700190 plots_.push_back(std::unique_ptr<Plot>(plot));
terelius54ce6802016-07-13 06:44:41 -0700191 return plot;
192}
193
terelius54ce6802016-07-13 06:44:41 -0700194} // namespace webrtc