Convenience functions to set axis properties in visualization tool.

Also makes the properties protected, as previously requested by Stefan.

Review-Url: https://codereview.webrtc.org/2179223003
Cr-Commit-Position: refs/heads/master@{#13593}
This commit is contained in:
terelius
2016-08-01 12:03:27 -07:00
committed by Commit bot
parent 8b70faf262
commit dc35dcd4dc
9 changed files with 247 additions and 175 deletions

View File

@ -178,6 +178,7 @@ if (rtc_include_tests) {
"event_log_visualizer/analyzer.cc",
"event_log_visualizer/analyzer.h",
"event_log_visualizer/generate_timeseries.cc",
"event_log_visualizer/plot_base.cc",
"event_log_visualizer/plot_base.h",
"event_log_visualizer/plot_python.cc",
"event_log_visualizer/plot_python.h",

View File

@ -32,6 +32,9 @@
#include "webrtc/video_receive_stream.h"
#include "webrtc/video_send_stream.h"
namespace webrtc {
namespace plotting {
namespace {
std::string SsrcToString(uint32_t ssrc) {
@ -90,17 +93,13 @@ void RegisterHeaderExtensions(
}
}
const double kXMargin = 1.02;
const double kYMargin = 1.1;
const double kDefaultXMin = -1;
const double kDefaultYMin = -1;
constexpr float kLeftMargin = 0.01f;
constexpr float kRightMargin = 0.02f;
constexpr float kBottomMargin = 0.02f;
constexpr float kTopMargin = 0.05f;
} // namespace
namespace webrtc {
namespace plotting {
bool EventLogAnalyzer::StreamId::operator<(const StreamId& other) const {
if (ssrc_ < other.ssrc_) {
return true;
@ -274,6 +273,7 @@ EventLogAnalyzer::EventLogAnalyzer(const ParsedRtcEventLog& log)
}
begin_time_ = first_timestamp;
end_time_ = last_timestamp;
call_duration_s_ = static_cast<float>(end_time_ - begin_time_) / 1000000;
}
class BitrateObserver : public CongestionController::Observer,
@ -311,7 +311,6 @@ void EventLogAnalyzer::CreatePacketGraph(PacketDirection desired_direction,
MediaType media_type;
uint8_t header[IP_PACKET_SIZE];
size_t header_length, total_length;
float max_y = 0;
for (size_t i = 0; i < parsed_log_.GetNumberOfEvents(); i++) {
ParsedRtcEventLog::EventType event_type = parsed_log_.GetEventType(i);
@ -328,7 +327,6 @@ void EventLogAnalyzer::CreatePacketGraph(PacketDirection desired_direction,
uint64_t timestamp = parsed_log_.GetTimestamp(i);
float x = static_cast<float>(timestamp - begin_time_) / 1000000;
float y = total_length;
max_y = std::max(max_y, y);
time_series[parsed_header.ssrc].points.push_back(
TimeSeriesPoint(x, y));
}
@ -340,19 +338,16 @@ void EventLogAnalyzer::CreatePacketGraph(PacketDirection desired_direction,
for (auto& kv : time_series) {
kv.second.label = SsrcToString(kv.first);
kv.second.style = BAR_GRAPH;
plot->series.push_back(std::move(kv.second));
plot->series_list_.push_back(std::move(kv.second));
}
plot->xaxis_min = kDefaultXMin;
plot->xaxis_max = (end_time_ - begin_time_) / 1000000 * kXMargin;
plot->xaxis_label = "Time (s)";
plot->yaxis_min = kDefaultYMin;
plot->yaxis_max = max_y * kYMargin;
plot->yaxis_label = "Packet size (bytes)";
plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin);
plot->SetSuggestedYAxis(0, 1, "Packet size (bytes)", kBottomMargin,
kTopMargin);
if (desired_direction == webrtc::PacketDirection::kIncomingPacket) {
plot->title = "Incoming RTP packets";
plot->SetTitle("Incoming RTP packets");
} else if (desired_direction == webrtc::PacketDirection::kOutgoingPacket) {
plot->title = "Outgoing RTP packets";
plot->SetTitle("Outgoing RTP packets");
}
}
@ -362,7 +357,6 @@ void EventLogAnalyzer::CreatePlayoutGraph(Plot* plot) {
std::map<uint32_t, uint64_t> last_playout;
uint32_t ssrc;
float max_y = 0;
for (size_t i = 0; i < parsed_log_.GetNumberOfEvents(); i++) {
ParsedRtcEventLog::EventType event_type = parsed_log_.GetEventType(i);
@ -377,7 +371,6 @@ void EventLogAnalyzer::CreatePlayoutGraph(Plot* plot) {
// Generate a point, but place it on the x-axis.
y = 0;
}
max_y = std::max(max_y, y);
time_series[ssrc].points.push_back(TimeSeriesPoint(x, y));
last_playout[ssrc] = timestamp;
}
@ -388,16 +381,13 @@ void EventLogAnalyzer::CreatePlayoutGraph(Plot* plot) {
for (auto& kv : time_series) {
kv.second.label = SsrcToString(kv.first);
kv.second.style = BAR_GRAPH;
plot->series.push_back(std::move(kv.second));
plot->series_list_.push_back(std::move(kv.second));
}
plot->xaxis_min = kDefaultXMin;
plot->xaxis_max = (end_time_ - begin_time_) / 1000000 * kXMargin;
plot->xaxis_label = "Time (s)";
plot->yaxis_min = kDefaultYMin;
plot->yaxis_max = max_y * kYMargin;
plot->yaxis_label = "Time since last playout (ms)";
plot->title = "Audio playout";
plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin);
plot->SetSuggestedYAxis(0, 1, "Time since last playout (ms)", kBottomMargin,
kTopMargin);
plot->SetTitle("Audio playout");
}
// For each SSRC, plot the time between the consecutive playouts.
@ -410,9 +400,6 @@ void EventLogAnalyzer::CreateSequenceNumberGraph(Plot* plot) {
uint8_t header[IP_PACKET_SIZE];
size_t header_length, total_length;
int max_y = 1;
int min_y = 0;
for (size_t i = 0; i < parsed_log_.GetNumberOfEvents(); i++) {
ParsedRtcEventLog::EventType event_type = parsed_log_.GetEventType(i);
if (event_type == ParsedRtcEventLog::RTP_EVENT) {
@ -434,8 +421,6 @@ void EventLogAnalyzer::CreateSequenceNumberGraph(Plot* plot) {
// Generate a point, but place it on the x-axis.
y = 0;
}
max_y = std::max(max_y, y);
min_y = std::min(min_y, y);
time_series[parsed_header.ssrc].points.push_back(
TimeSeriesPoint(x, y));
last_seqno[parsed_header.ssrc] = parsed_header.sequenceNumber;
@ -448,22 +433,16 @@ void EventLogAnalyzer::CreateSequenceNumberGraph(Plot* plot) {
for (auto& kv : time_series) {
kv.second.label = SsrcToString(kv.first);
kv.second.style = BAR_GRAPH;
plot->series.push_back(std::move(kv.second));
plot->series_list_.push_back(std::move(kv.second));
}
plot->xaxis_min = kDefaultXMin;
plot->xaxis_max = (end_time_ - begin_time_) / 1000000 * kXMargin;
plot->xaxis_label = "Time (s)";
plot->yaxis_min = min_y - (kYMargin - 1) / 2 * (max_y - min_y);
plot->yaxis_max = max_y + (kYMargin - 1) / 2 * (max_y - min_y);
plot->yaxis_label = "Difference since last packet";
plot->title = "Sequence number";
plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin);
plot->SetSuggestedYAxis(0, 1, "Difference since last packet", kBottomMargin,
kTopMargin);
plot->SetTitle("Sequence number");
}
void EventLogAnalyzer::CreateDelayChangeGraph(Plot* plot) {
double max_y = 10;
double min_y = 0;
for (auto& kv : rtp_packets_) {
StreamId stream_id = kv.first;
// Filter on direction and SSRC.
@ -498,28 +477,20 @@ void EventLogAnalyzer::CreateDelayChangeGraph(Plot* plot) {
// Generate a point, but place it on the x-axis.
y = 0;
}
max_y = std::max(max_y, y);
min_y = std::min(min_y, y);
time_series.points.emplace_back(x, y);
}
}
// Add the data set to the plot.
plot->series.push_back(std::move(time_series));
plot->series_list_.push_back(std::move(time_series));
}
plot->xaxis_min = kDefaultXMin;
plot->xaxis_max = (end_time_ - begin_time_) / 1000000 * kXMargin;
plot->xaxis_label = "Time (s)";
plot->yaxis_min = min_y - (kYMargin - 1) / 2 * (max_y - min_y);
plot->yaxis_max = max_y + (kYMargin - 1) / 2 * (max_y - min_y);
plot->yaxis_label = "Latency change (ms)";
plot->title = "Network latency change between consecutive packets";
plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin);
plot->SetSuggestedYAxis(0, 1, "Latency change (ms)", kBottomMargin,
kTopMargin);
plot->SetTitle("Network latency change between consecutive packets");
}
void EventLogAnalyzer::CreateAccumulatedDelayChangeGraph(Plot* plot) {
double max_y = 10;
double min_y = 0;
for (auto& kv : rtp_packets_) {
StreamId stream_id = kv.first;
// Filter on direction and SSRC.
@ -554,22 +525,17 @@ void EventLogAnalyzer::CreateAccumulatedDelayChangeGraph(Plot* plot) {
// Generate a point, but place it on the x-axis.
accumulated_delay_ms = 0;
}
max_y = std::max(max_y, accumulated_delay_ms);
min_y = std::min(min_y, accumulated_delay_ms);
time_series.points.emplace_back(x, accumulated_delay_ms);
}
}
// Add the data set to the plot.
plot->series.push_back(std::move(time_series));
plot->series_list_.push_back(std::move(time_series));
}
plot->xaxis_min = kDefaultXMin;
plot->xaxis_max = (end_time_ - begin_time_) / 1000000 * kXMargin;
plot->xaxis_label = "Time (s)";
plot->yaxis_min = min_y - (kYMargin - 1) / 2 * (max_y - min_y);
plot->yaxis_max = max_y + (kYMargin - 1) / 2 * (max_y - min_y);
plot->yaxis_label = "Latency change (ms)";
plot->title = "Accumulated network latency change";
plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin);
plot->SetSuggestedYAxis(0, 1, "Latency change (ms)", kBottomMargin,
kTopMargin);
plot->SetTitle("Accumulated network latency change");
}
// Plot the total bandwidth used by all RTP streams.
@ -602,10 +568,9 @@ void EventLogAnalyzer::CreateTotalBitrateGraph(
size_t window_index_begin = 0;
size_t window_index_end = 0;
size_t bytes_in_window = 0;
float max_y = 0;
// Calculate a moving average of the bitrate and store in a TimeSeries.
plot->series.push_back(TimeSeries());
plot->series_list_.push_back(TimeSeries());
for (uint64_t time = begin_time_; time < end_time_ + step_; time += step_) {
while (window_index_end < packets.size() &&
packets[window_index_end].timestamp < time) {
@ -622,42 +587,36 @@ void EventLogAnalyzer::CreateTotalBitrateGraph(
static_cast<float>(window_duration_) / 1000000;
float x = static_cast<float>(time - begin_time_) / 1000000;
float y = bytes_in_window * 8 / window_duration_in_seconds / 1000;
max_y = std::max(max_y, y);
plot->series.back().points.push_back(TimeSeriesPoint(x, y));
plot->series_list_.back().points.push_back(TimeSeriesPoint(x, y));
}
// Set labels.
if (desired_direction == webrtc::PacketDirection::kIncomingPacket) {
plot->series.back().label = "Incoming bitrate";
plot->series_list_.back().label = "Incoming bitrate";
} else if (desired_direction == webrtc::PacketDirection::kOutgoingPacket) {
plot->series.back().label = "Outgoing bitrate";
plot->series_list_.back().label = "Outgoing bitrate";
}
plot->series.back().style = LINE_GRAPH;
plot->series_list_.back().style = LINE_GRAPH;
// Overlay the send-side bandwidth estimate over the outgoing bitrate.
if (desired_direction == kOutgoingPacket) {
plot->series.push_back(TimeSeries());
plot->series_list_.push_back(TimeSeries());
for (auto& bwe_update : bwe_loss_updates_) {
float x =
static_cast<float>(bwe_update.timestamp - begin_time_) / 1000000;
float y = static_cast<float>(bwe_update.new_bitrate) / 1000;
max_y = std::max(max_y, y);
plot->series.back().points.emplace_back(x, y);
plot->series_list_.back().points.emplace_back(x, y);
}
plot->series.back().label = "Loss-based estimate";
plot->series.back().style = LINE_GRAPH;
plot->series_list_.back().label = "Loss-based estimate";
plot->series_list_.back().style = LINE_GRAPH;
}
plot->xaxis_min = kDefaultXMin;
plot->xaxis_max = (end_time_ - begin_time_) / 1000000 * kXMargin;
plot->xaxis_label = "Time (s)";
plot->yaxis_min = kDefaultYMin;
plot->yaxis_max = max_y * kYMargin;
plot->yaxis_label = "Bitrate (kbps)";
plot->series_list_.back().style = LINE_GRAPH;
plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin);
plot->SetSuggestedYAxis(0, 1, "Bitrate (kbps)", kBottomMargin, kTopMargin);
if (desired_direction == webrtc::PacketDirection::kIncomingPacket) {
plot->title = "Incoming RTP bitrate";
plot->SetTitle("Incoming RTP bitrate");
} else if (desired_direction == webrtc::PacketDirection::kOutgoingPacket) {
plot->title = "Outgoing RTP bitrate";
plot->SetTitle("Outgoing RTP bitrate");
}
}
@ -698,15 +657,13 @@ void EventLogAnalyzer::CreateStreamBitrateGraph(
}
}
float max_y = 0;
for (auto& kv : packets) {
size_t window_index_begin = 0;
size_t window_index_end = 0;
size_t bytes_in_window = 0;
// Calculate a moving average of the bitrate and store in a TimeSeries.
plot->series.push_back(TimeSeries());
plot->series_list_.push_back(TimeSeries());
for (uint64_t time = begin_time_; time < end_time_ + step_; time += step_) {
while (window_index_end < kv.second.size() &&
kv.second[window_index_end].timestamp < time) {
@ -724,25 +681,20 @@ void EventLogAnalyzer::CreateStreamBitrateGraph(
static_cast<float>(window_duration_) / 1000000;
float x = static_cast<float>(time - begin_time_) / 1000000;
float y = bytes_in_window * 8 / window_duration_in_seconds / 1000;
max_y = std::max(max_y, y);
plot->series.back().points.push_back(TimeSeriesPoint(x, y));
plot->series_list_.back().points.push_back(TimeSeriesPoint(x, y));
}
// Set labels.
plot->series.back().label = SsrcToString(kv.first);
plot->series.back().style = LINE_GRAPH;
plot->series_list_.back().label = SsrcToString(kv.first);
plot->series_list_.back().style = LINE_GRAPH;
}
plot->xaxis_min = kDefaultXMin;
plot->xaxis_max = (end_time_ - begin_time_) / 1000000 * kXMargin;
plot->xaxis_label = "Time (s)";
plot->yaxis_min = kDefaultYMin;
plot->yaxis_max = max_y * kYMargin;
plot->yaxis_label = "Bitrate (kbps)";
plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin);
plot->SetSuggestedYAxis(0, 1, "Bitrate (kbps)", kBottomMargin, kTopMargin);
if (desired_direction == webrtc::PacketDirection::kIncomingPacket) {
plot->title = "Incoming bitrate per stream";
plot->SetTitle("Incoming bitrate per stream");
} else if (desired_direction == webrtc::PacketDirection::kOutgoingPacket) {
plot->title = "Outgoing bitrate per stream";
plot->SetTitle("Outgoing bitrate per stream");
}
}
@ -776,8 +728,6 @@ void EventLogAnalyzer::CreateBweGraph(Plot* plot) {
TimeSeries time_series;
time_series.label = "BWE";
time_series.style = LINE_DOT_GRAPH;
uint32_t max_y = 10;
uint32_t min_y = 0;
auto rtp_iterator = outgoing_rtp.begin();
auto rtcp_iterator = incoming_rtcp.begin();
@ -834,8 +784,6 @@ void EventLogAnalyzer::CreateBweGraph(Plot* plot) {
cc.Process();
if (observer.GetAndResetBitrateUpdated()) {
uint32_t y = observer.last_bitrate_bps() / 1000;
max_y = std::max(max_y, y);
min_y = std::min(min_y, y);
float x = static_cast<float>(clock.TimeInMicroseconds() - begin_time_) /
1000000;
time_series.points.emplace_back(x, y);
@ -843,15 +791,11 @@ void EventLogAnalyzer::CreateBweGraph(Plot* plot) {
time_us = std::min({NextRtpTime(), NextRtcpTime(), NextProcessTime()});
}
// Add the data set to the plot.
plot->series.push_back(std::move(time_series));
plot->series_list_.push_back(std::move(time_series));
plot->xaxis_min = kDefaultXMin;
plot->xaxis_max = (end_time_ - begin_time_) / 1000000 * kXMargin;
plot->xaxis_label = "Time (s)";
plot->yaxis_min = min_y - (kYMargin - 1) / 2 * (max_y - min_y);
plot->yaxis_max = max_y + (kYMargin - 1) / 2 * (max_y - min_y);
plot->yaxis_label = "Bitrate (kbps)";
plot->title = "BWE";
plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin);
plot->SetSuggestedYAxis(0, 10, "Bitrate (kbps)", kBottomMargin, kTopMargin);
plot->SetTitle("Simulated BWE behavior");
}
} // namespace plotting

View File

@ -115,6 +115,9 @@ class EventLogAnalyzer {
// First and last events of the log.
uint64_t begin_time_;
uint64_t end_time_;
// Duration (in seconds) of log file.
float call_duration_s_;
};
} // namespace plotting

View File

@ -82,44 +82,44 @@ int main(int argc, char* argv[]) {
if (FLAGS_plot_all || FLAGS_plot_packets) {
if (FLAGS_incoming) {
analyzer.CreatePacketGraph(webrtc::PacketDirection::kIncomingPacket,
collection->append_new_plot());
collection->AppendNewPlot());
}
if (FLAGS_outgoing) {
analyzer.CreatePacketGraph(webrtc::PacketDirection::kOutgoingPacket,
collection->append_new_plot());
collection->AppendNewPlot());
}
}
if (FLAGS_plot_all || FLAGS_plot_audio_playout) {
analyzer.CreatePlayoutGraph(collection->append_new_plot());
analyzer.CreatePlayoutGraph(collection->AppendNewPlot());
}
if (FLAGS_plot_all || FLAGS_plot_sequence_number) {
if (FLAGS_incoming) {
analyzer.CreateSequenceNumberGraph(collection->append_new_plot());
analyzer.CreateSequenceNumberGraph(collection->AppendNewPlot());
}
}
if (FLAGS_plot_all || FLAGS_plot_delay_change) {
if (FLAGS_incoming) {
analyzer.CreateDelayChangeGraph(collection->append_new_plot());
analyzer.CreateDelayChangeGraph(collection->AppendNewPlot());
}
}
if (FLAGS_plot_all || FLAGS_plot_accumulated_delay_change) {
if (FLAGS_incoming) {
analyzer.CreateAccumulatedDelayChangeGraph(collection->append_new_plot());
analyzer.CreateAccumulatedDelayChangeGraph(collection->AppendNewPlot());
}
}
if (FLAGS_plot_all || FLAGS_plot_total_bitrate) {
if (FLAGS_incoming) {
analyzer.CreateTotalBitrateGraph(webrtc::PacketDirection::kIncomingPacket,
collection->append_new_plot());
collection->AppendNewPlot());
}
if (FLAGS_outgoing) {
analyzer.CreateTotalBitrateGraph(webrtc::PacketDirection::kOutgoingPacket,
collection->append_new_plot());
collection->AppendNewPlot());
}
}
@ -127,20 +127,20 @@ int main(int argc, char* argv[]) {
if (FLAGS_incoming) {
analyzer.CreateStreamBitrateGraph(
webrtc::PacketDirection::kIncomingPacket,
collection->append_new_plot());
collection->AppendNewPlot());
}
if (FLAGS_outgoing) {
analyzer.CreateStreamBitrateGraph(
webrtc::PacketDirection::kOutgoingPacket,
collection->append_new_plot());
collection->AppendNewPlot());
}
}
if (FLAGS_plot_all || FLAGS_plot_bwe) {
analyzer.CreateBweGraph(collection->append_new_plot());
analyzer.CreateBweGraph(collection->AppendNewPlot());
}
collection->draw();
collection->Draw();
return 0;
}

View File

@ -0,0 +1,75 @@
/*
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/tools/event_log_visualizer/plot_base.h"
#include <algorithm>
#include "webrtc/base/checks.h"
namespace webrtc {
namespace plotting {
void Plot::SetXAxis(float min_value,
float max_value,
std::string label,
float left_margin,
float right_margin) {
RTC_DCHECK_LE(min_value, max_value);
xaxis_min_ = min_value - left_margin * (max_value - min_value);
xaxis_max_ = max_value + right_margin * (max_value - min_value);
xaxis_label_ = label;
}
void Plot::SetSuggestedXAxis(float min_value,
float max_value,
std::string label,
float left_margin,
float right_margin) {
for (const auto& series : series_list_) {
for (const auto& point : series.points) {
min_value = std::min(min_value, point.x);
max_value = std::max(max_value, point.x);
}
}
SetXAxis(min_value, max_value, label, left_margin, right_margin);
}
void Plot::SetYAxis(float min_value,
float max_value,
std::string label,
float bottom_margin,
float top_margin) {
RTC_DCHECK_LE(min_value, max_value);
yaxis_min_ = min_value - bottom_margin * (max_value - min_value);
yaxis_max_ = max_value + top_margin * (max_value - min_value);
yaxis_label_ = label;
}
void Plot::SetSuggestedYAxis(float min_value,
float max_value,
std::string label,
float bottom_margin,
float top_margin) {
for (const auto& series : series_list_) {
for (const auto& point : series.points) {
min_value = std::min(min_value, point.y);
max_value = std::max(max_value, point.y);
}
}
SetYAxis(min_value, max_value, label, bottom_margin, top_margin);
}
void Plot::SetTitle(std::string title) {
title_ = title;
}
} // namespace plotting
} // namespace webrtc

View File

@ -44,32 +44,79 @@ struct TimeSeries {
std::vector<TimeSeriesPoint> points;
};
// This is basically a struct that represents of a general graph, with axes,
// title and one or more data series. We make it a class only to document that
// it also specifies an interface for the draw()ing objects.
// A container that represents a general graph, with axes, title and one or
// more data series. A subclass should define the output format by overriding
// the Draw() method.
class Plot {
public:
virtual ~Plot() {}
virtual void draw() = 0;
float xaxis_min;
float xaxis_max;
std::string xaxis_label;
float yaxis_min;
float yaxis_max;
std::string yaxis_label;
std::vector<TimeSeries> series;
std::string title;
// Overloaded to draw the plot.
virtual void Draw() = 0;
// Sets the lower x-axis limit to min_value (if left_margin == 0).
// Sets the upper x-axis limit to max_value (if right_margin == 0).
// The margins are measured as fractions of the interval
// (max_value - min_value) and are added to either side of the plot.
void SetXAxis(float min_value,
float max_value,
std::string label,
float left_margin = 0,
float right_margin = 0);
// Sets the lower and upper x-axis limits based on min_value and max_value,
// but modified such that all points in the data series can be represented
// on the x-axis. The margins are measured as fractions of the range of
// x-values and are added to either side of the plot.
void SetSuggestedXAxis(float min_value,
float max_value,
std::string label,
float left_margin = 0,
float right_margin = 0);
// Sets the lower y-axis limit to min_value (if bottom_margin == 0).
// Sets the upper y-axis limit to max_value (if top_margin == 0).
// The margins are measured as fractions of the interval
// (max_value - min_value) and are added to either side of the plot.
void SetYAxis(float min_value,
float max_value,
std::string label,
float bottom_margin = 0,
float top_margin = 0);
// Sets the lower and upper y-axis limits based on min_value and max_value,
// but modified such that all points in the data series can be represented
// on the y-axis. The margins are measured as fractions of the range of
// y-values and are added to either side of the plot.
void SetSuggestedYAxis(float min_value,
float max_value,
std::string label,
float bottom_margin = 0,
float top_margin = 0);
// Sets the title of the plot.
void SetTitle(std::string title);
std::vector<TimeSeries> series_list_;
protected:
float xaxis_min_;
float xaxis_max_;
std::string xaxis_label_;
float yaxis_min_;
float yaxis_max_;
std::string yaxis_label_;
std::string title_;
};
class PlotCollection {
public:
virtual ~PlotCollection() {}
virtual void draw() = 0;
virtual Plot* append_new_plot() = 0;
virtual void Draw() = 0;
virtual Plot* AppendNewPlot() = 0;
protected:
std::vector<std::unique_ptr<Plot> > plots;
std::vector<std::unique_ptr<Plot> > plots_;
};
} // namespace plotting

View File

@ -11,6 +11,7 @@
#include "webrtc/tools/event_log_visualizer/plot_python.h"
#include <stdio.h>
#include <memory>
namespace webrtc {
@ -20,62 +21,62 @@ PythonPlot::PythonPlot() {}
PythonPlot::~PythonPlot() {}
void PythonPlot::draw() {
void PythonPlot::Draw() {
// Write python commands to stdout. Intended program usage is
// ./event_log_visualizer event_log160330.dump | python
if (!series.empty()) {
printf("color_count = %zu\n", series.size());
if (!series_list_.empty()) {
printf("color_count = %zu\n", series_list_.size());
printf(
"hls_colors = [(i*1.0/color_count, 0.25+i*0.5/color_count, 0.8) for i "
"in range(color_count)]\n");
printf("rgb_colors = [colorsys.hls_to_rgb(*hls) for hls in hls_colors]\n");
for (size_t i = 0; i < series.size(); i++) {
for (size_t i = 0; i < series_list_.size(); i++) {
// List x coordinates
printf("x%zu = [", i);
if (series[i].points.size() > 0)
printf("%G", series[i].points[0].x);
for (size_t j = 1; j < series[i].points.size(); j++)
printf(", %G", series[i].points[j].x);
if (series_list_[i].points.size() > 0)
printf("%G", series_list_[i].points[0].x);
for (size_t j = 1; j < series_list_[i].points.size(); j++)
printf(", %G", series_list_[i].points[j].x);
printf("]\n");
// List y coordinates
printf("y%zu = [", i);
if (series[i].points.size() > 0)
printf("%G", series[i].points[0].y);
for (size_t j = 1; j < series[i].points.size(); j++)
printf(", %G", series[i].points[j].y);
if (series_list_[i].points.size() > 0)
printf("%G", series_list_[i].points[0].y);
for (size_t j = 1; j < series_list_[i].points.size(); j++)
printf(", %G", series_list_[i].points[j].y);
printf("]\n");
if (series[i].style == BAR_GRAPH) {
if (series_list_[i].style == BAR_GRAPH) {
// There is a plt.bar function that draws bar plots,
// but it is *way* too slow to be useful.
printf(
"plt.vlines(x%zu, map(lambda t: min(t,0), y%zu), map(lambda t: "
"max(t,0), y%zu), color=rgb_colors[%zu], "
"label=\'%s\')\n",
i, i, i, i, series[i].label.c_str());
} else if (series[i].style == LINE_GRAPH) {
i, i, i, i, series_list_[i].label.c_str());
} else if (series_list_[i].style == LINE_GRAPH) {
printf("plt.plot(x%zu, y%zu, color=rgb_colors[%zu], label=\'%s\')\n", i,
i, i, series[i].label.c_str());
} else if (series[i].style == LINE_DOT_GRAPH) {
i, i, series_list_[i].label.c_str());
} else if (series_list_[i].style == LINE_DOT_GRAPH) {
printf(
"plt.plot(x%zu, y%zu, color=rgb_colors[%zu], label=\'%s\', "
"marker='.')\n",
i, i, i, series[i].label.c_str());
i, i, i, series_list_[i].label.c_str());
} else {
printf("raise Exception(\"Unknown graph type\")\n");
}
}
}
printf("plt.xlim(%f, %f)\n", xaxis_min, xaxis_max);
printf("plt.ylim(%f, %f)\n", yaxis_min, yaxis_max);
printf("plt.xlabel(\'%s\')\n", xaxis_label.c_str());
printf("plt.ylabel(\'%s\')\n", yaxis_label.c_str());
printf("plt.title(\'%s\')\n", title.c_str());
if (!series.empty()) {
printf("plt.xlim(%f, %f)\n", xaxis_min_, xaxis_max_);
printf("plt.ylim(%f, %f)\n", yaxis_min_, yaxis_max_);
printf("plt.xlabel(\'%s\')\n", xaxis_label_.c_str());
printf("plt.ylabel(\'%s\')\n", yaxis_label_.c_str());
printf("plt.title(\'%s\')\n", title_.c_str());
if (!series_list_.empty()) {
printf("plt.legend(loc=\'best\', fontsize=\'small\')\n");
}
}
@ -84,19 +85,19 @@ PythonPlotCollection::PythonPlotCollection() {}
PythonPlotCollection::~PythonPlotCollection() {}
void PythonPlotCollection::draw() {
void PythonPlotCollection::Draw() {
printf("import matplotlib.pyplot as plt\n");
printf("import colorsys\n");
for (size_t i = 0; i < plots.size(); i++) {
for (size_t i = 0; i < plots_.size(); i++) {
printf("plt.figure(%zu)\n", i);
plots[i]->draw();
plots_[i]->Draw();
}
printf("plt.show()\n");
}
Plot* PythonPlotCollection::append_new_plot() {
Plot* PythonPlotCollection::AppendNewPlot() {
Plot* plot = new PythonPlot();
plots.push_back(std::unique_ptr<Plot>(plot));
plots_.push_back(std::unique_ptr<Plot>(plot));
return plot;
}

View File

@ -19,15 +19,15 @@ class PythonPlot final : public Plot {
public:
PythonPlot();
~PythonPlot() override;
void draw() override;
void Draw() override;
};
class PythonPlotCollection final : public PlotCollection {
public:
PythonPlotCollection();
~PythonPlotCollection() override;
void draw() override;
Plot* append_new_plot() override;
void Draw() override;
Plot* AppendNewPlot() override;
};
} // namespace plotting

View File

@ -121,6 +121,7 @@
'event_log_visualizer/analyzer.cc',
'event_log_visualizer/analyzer.h',
'event_log_visualizer/generate_timeseries.cc',
'event_log_visualizer/plot_base.cc',
'event_log_visualizer/plot_base.h',
'event_log_visualizer/plot_python.cc',
'event_log_visualizer/plot_python.h',