1 /*
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 #ifndef RTC_TOOLS_RTC_EVENT_LOG_VISUALIZER_PLOT_BASE_H_
11 #define RTC_TOOLS_RTC_EVENT_LOG_VISUALIZER_PLOT_BASE_H_
12
13 #include <memory>
14 #include <string>
15 #include <utility>
16 #include <vector>
17
18 #include "absl/base/attributes.h"
19 #include "absl/types/optional.h"
20 #include "rtc_base/ignore_wundef.h"
21
22 RTC_PUSH_IGNORING_WUNDEF()
23 #include "rtc_tools/rtc_event_log_visualizer/proto/chart.pb.h"
RTC_POP_IGNORING_WUNDEF()24 RTC_POP_IGNORING_WUNDEF()
25
26 namespace webrtc {
27
28 enum class LineStyle {
29 kNone, // No line connecting the points. Used to create scatter plots.
30 kLine, // Straight line between consecutive points.
31 kStep, // Horizontal line until the next value. Used for state changes.
32 kBar // Vertical bars from the x-axis to the point.
33 };
34
35 enum class PointStyle {
36 kNone, // Don't draw the points.
37 kHighlight // Draw circles or dots to highlight the points.
38 };
39
40 struct TimeSeriesPoint {
41 TimeSeriesPoint(float x, float y) : x(x), y(y) {}
42 float x;
43 float y;
44 };
45
46 struct TimeSeries {
47 TimeSeries() = default; // TODO(terelius): Remove the default constructor.
48 TimeSeries(const char* label,
49 LineStyle line_style,
50 PointStyle point_style = PointStyle::kNone)
51 : label(label), line_style(line_style), point_style(point_style) {}
52 TimeSeries(const std::string& label,
53 LineStyle line_style,
54 PointStyle point_style = PointStyle::kNone)
55 : label(label), line_style(line_style), point_style(point_style) {}
56 TimeSeries(TimeSeries&& other)
57 : label(std::move(other.label)),
58 line_style(other.line_style),
59 point_style(other.point_style),
60 points(std::move(other.points)) {}
61 TimeSeries& operator=(TimeSeries&& other) {
62 label = std::move(other.label);
63 line_style = other.line_style;
64 point_style = other.point_style;
65 points = std::move(other.points);
66 return *this;
67 }
68
69 std::string label;
70 LineStyle line_style = LineStyle::kLine;
71 PointStyle point_style = PointStyle::kNone;
72 std::vector<TimeSeriesPoint> points;
73 };
74
75 struct Interval {
76 Interval() = default;
77 Interval(double begin, double end) : begin(begin), end(end) {}
78
79 double begin;
80 double end;
81 };
82
83 struct IntervalSeries {
84 enum Orientation { kHorizontal, kVertical };
85
86 IntervalSeries() = default;
87 IntervalSeries(const std::string& label,
88 const std::string& color,
89 IntervalSeries::Orientation orientation)
90 : label(label), color(color), orientation(orientation) {}
91
92 std::string label;
93 std::string color;
94 Orientation orientation;
95 std::vector<Interval> intervals;
96 };
97
98 // A container that represents a general graph, with axes, title and one or
99 // more data series. A subclass should define the output format by overriding
100 // the Draw() method.
101 class Plot {
102 public:
103 virtual ~Plot() {}
104
105 ABSL_DEPRECATED("Use PrintPythonCode() or ExportProtobuf() instead.")
106 virtual void Draw() {}
107
108 // Sets the lower x-axis limit to min_value (if left_margin == 0).
109 // Sets the upper x-axis limit to max_value (if right_margin == 0).
110 // The margins are measured as fractions of the interval
111 // (max_value - min_value) and are added to either side of the plot.
112 void SetXAxis(float min_value,
113 float max_value,
114 std::string label,
115 float left_margin = 0,
116 float right_margin = 0);
117
118 // Sets the lower and upper x-axis limits based on min_value and max_value,
119 // but modified such that all points in the data series can be represented
120 // on the x-axis. The margins are measured as fractions of the range of
121 // x-values and are added to either side of the plot.
122 void SetSuggestedXAxis(float min_value,
123 float max_value,
124 std::string label,
125 float left_margin = 0,
126 float right_margin = 0);
127
128 // Sets the lower y-axis limit to min_value (if bottom_margin == 0).
129 // Sets the upper y-axis limit to max_value (if top_margin == 0).
130 // The margins are measured as fractions of the interval
131 // (max_value - min_value) and are added to either side of the plot.
132 void SetYAxis(float min_value,
133 float max_value,
134 std::string label,
135 float bottom_margin = 0,
136 float top_margin = 0);
137
138 // Sets the lower and upper y-axis limits based on min_value and max_value,
139 // but modified such that all points in the data series can be represented
140 // on the y-axis. The margins are measured as fractions of the range of
141 // y-values and are added to either side of the plot.
142 void SetSuggestedYAxis(float min_value,
143 float max_value,
144 std::string label,
145 float bottom_margin = 0,
146 float top_margin = 0);
147
148 void SetYAxisTickLabels(
149 const std::vector<std::pair<float, std::string>>& labels);
150
151 // Sets the title of the plot.
152 void SetTitle(const std::string& title);
153
154 // Sets an unique ID for the plot. The ID is similar to the title except that
155 // the title might change in future releases whereas the ID should be stable
156 // over time.
157 void SetId(const std::string& id);
158
159 // Add a new TimeSeries to the plot.
160 void AppendTimeSeries(TimeSeries&& time_series);
161
162 // Add a new IntervalSeries to the plot.
163 void AppendIntervalSeries(IntervalSeries&& interval_series);
164
165 // Add a new TimeSeries to the plot if the series contains contains data.
166 // Otherwise, the call has no effect and the timeseries is destroyed.
167 void AppendTimeSeriesIfNotEmpty(TimeSeries&& time_series);
168
169 // Replaces PythonPlot::Draw()
170 void PrintPythonCode() const;
171
172 // Replaces ProtobufPlot::Draw()
173 void ExportProtobuf(webrtc::analytics::Chart* chart) const;
174
175 protected:
176 float xaxis_min_;
177 float xaxis_max_;
178 std::string xaxis_label_;
179 float yaxis_min_;
180 float yaxis_max_;
181 std::string yaxis_label_;
182 std::vector<std::pair<float, std::string>> yaxis_tick_labels_;
183 std::string title_;
184 std::string id_;
185 std::vector<TimeSeries> series_list_;
186 std::vector<IntervalSeries> interval_list_;
187 };
188
189 class PlotCollection {
190 public:
191 virtual ~PlotCollection() {}
192
193 ABSL_DEPRECATED("Use PrintPythonCode() or ExportProtobuf() instead.")
194 virtual void Draw() {}
195
196 virtual Plot* AppendNewPlot();
197
198 void SetCallTimeToUtcOffsetMs(int64_t calltime_to_utc_ms) {
199 calltime_to_utc_ms_ = calltime_to_utc_ms;
200 }
201
202 // Replaces PythonPlotCollection::Draw()
203 void PrintPythonCode(bool shared_xaxis) const;
204
205 // Replaces ProtobufPlotCollections::Draw()
206 void ExportProtobuf(webrtc::analytics::ChartCollection* collection) const;
207
208 protected:
209 std::vector<std::unique_ptr<Plot>> plots_;
210 absl::optional<int64_t> calltime_to_utc_ms_;
211 };
212
213 } // namespace webrtc
214
215 #endif // RTC_TOOLS_RTC_EVENT_LOG_VISUALIZER_PLOT_BASE_H_
216