James Kuszmaul | 4867136 | 2020-12-24 13:54:16 -0800 | [diff] [blame] | 1 | #include "frc971/analysis/in_process_plotter.h" |
| 2 | |
| 3 | #include "aos/configuration.h" |
| 4 | |
| 5 | namespace frc971 { |
| 6 | namespace analysis { |
| 7 | |
| 8 | namespace { |
Austin Schuh | aa3b086 | 2022-07-15 14:38:41 -0700 | [diff] [blame] | 9 | const char *kDataPath = "frc971/analysis/cpp_plot"; |
James Kuszmaul | 4867136 | 2020-12-24 13:54:16 -0800 | [diff] [blame] | 10 | const char *kConfigPath = "frc971/analysis/plotter.json"; |
| 11 | } // namespace |
| 12 | |
| 13 | Plotter::Plotter() |
| 14 | : config_(aos::configuration::ReadConfig(kConfigPath)), |
| 15 | event_loop_factory_(&config_.message()), |
| 16 | event_loop_(event_loop_factory_.MakeEventLoop("plotter")), |
| 17 | plot_sender_(event_loop_->MakeSender<Plot>("/analysis")), |
James Kuszmaul | 1a29c08 | 2022-02-03 14:02:47 -0800 | [diff] [blame] | 18 | web_proxy_(event_loop_.get(), aos::web_proxy::StoreHistory::kYes, -1), |
James Kuszmaul | 4867136 | 2020-12-24 13:54:16 -0800 | [diff] [blame] | 19 | builder_(plot_sender_.MakeBuilder()) { |
| 20 | web_proxy_.SetDataPath(kDataPath); |
| 21 | event_loop_->SkipTimingReport(); |
Austin Schuh | ea62f60 | 2022-07-18 16:53:04 -0700 | [diff] [blame] | 22 | |
| 23 | color_wheel_.emplace_back(ColorWheelColor{.name = "red", .color = {1, 0, 0}}); |
| 24 | color_wheel_.emplace_back( |
| 25 | ColorWheelColor{.name = "green", .color = {0, 1, 0}}); |
| 26 | color_wheel_.emplace_back( |
| 27 | ColorWheelColor{.name = "purple", .color = {0.54, 0.3, 0.75}}); |
| 28 | color_wheel_.emplace_back( |
| 29 | ColorWheelColor{.name = "blue", .color = {0, 0, 1}}); |
| 30 | color_wheel_.emplace_back( |
| 31 | ColorWheelColor{.name = "yellow", .color = {1, 1, 0}}); |
| 32 | color_wheel_.emplace_back( |
| 33 | ColorWheelColor{.name = "teal", .color = {0, 1, 1}}); |
| 34 | color_wheel_.emplace_back( |
| 35 | ColorWheelColor{.name = "pink", .color = {1, 0, 1}}); |
| 36 | color_wheel_.emplace_back( |
| 37 | ColorWheelColor{.name = "orange", .color = {1, 0.6, 0}}); |
| 38 | color_wheel_.emplace_back( |
| 39 | ColorWheelColor{.name = "brown", .color = {0.6, 0.3, 0}}); |
| 40 | color_wheel_.emplace_back( |
| 41 | ColorWheelColor{.name = "white", .color = {1, 1, 1}}); |
James Kuszmaul | 4867136 | 2020-12-24 13:54:16 -0800 | [diff] [blame] | 42 | } |
| 43 | |
| 44 | void Plotter::Spin() { event_loop_factory_.Run(); } |
| 45 | |
| 46 | void Plotter::Title(std::string_view title) { |
| 47 | title_ = builder_.fbb()->CreateString(title); |
| 48 | } |
| 49 | |
| 50 | void Plotter::AddFigure(std::string_view title, double width, double height) { |
| 51 | MaybeFinishFigure(); |
| 52 | |
| 53 | if (!title.empty()) { |
| 54 | figure_title_ = builder_.fbb()->CreateString(title); |
| 55 | } |
| 56 | |
| 57 | // For positioning, just stack figures vertically. |
| 58 | auto position_builder = builder_.MakeBuilder<Position>(); |
| 59 | position_builder.add_top(next_top_); |
| 60 | position_builder.add_left(0); |
| 61 | position_builder.add_width(width); |
| 62 | position_builder.add_height(height); |
| 63 | position_ = position_builder.Finish(); |
| 64 | |
| 65 | next_top_ += height; |
| 66 | } |
| 67 | |
| 68 | void Plotter::XLabel(std::string_view label) { |
| 69 | xlabel_ = builder_.fbb()->CreateString(label); |
| 70 | } |
| 71 | |
| 72 | void Plotter::YLabel(std::string_view label) { |
| 73 | ylabel_ = builder_.fbb()->CreateString(label); |
| 74 | } |
| 75 | |
| 76 | void Plotter::AddLine(const std::vector<double> &x, |
Austin Schuh | ea62f60 | 2022-07-18 16:53:04 -0700 | [diff] [blame] | 77 | const std::vector<double> &y, LineOptions options) { |
James Kuszmaul | 4867136 | 2020-12-24 13:54:16 -0800 | [diff] [blame] | 78 | CHECK_EQ(x.size(), y.size()); |
| 79 | CHECK(!position_.IsNull()) |
| 80 | << "You must call AddFigure() before calling AddLine()."; |
| 81 | |
| 82 | flatbuffers::Offset<flatbuffers::String> label_offset; |
Austin Schuh | ea62f60 | 2022-07-18 16:53:04 -0700 | [diff] [blame] | 83 | if (!options.label.empty()) { |
| 84 | label_offset = builder_.fbb()->CreateString(options.label); |
James Kuszmaul | 4867136 | 2020-12-24 13:54:16 -0800 | [diff] [blame] | 85 | } |
| 86 | |
| 87 | std::vector<Point> points; |
| 88 | for (size_t ii = 0; ii < x.size(); ++ii) { |
| 89 | points.emplace_back(x[ii], y[ii]); |
| 90 | } |
milind | 1f1dca3 | 2021-07-03 13:50:07 -0700 | [diff] [blame] | 91 | const flatbuffers::Offset<flatbuffers::Vector<const Point *>> points_offset = |
| 92 | builder_.fbb()->CreateVectorOfStructs(points); |
James Kuszmaul | 4867136 | 2020-12-24 13:54:16 -0800 | [diff] [blame] | 93 | |
Austin Schuh | ea62f60 | 2022-07-18 16:53:04 -0700 | [diff] [blame] | 94 | const Color *color; |
| 95 | if (options.color.empty()) { |
| 96 | color = &color_wheel_.at(color_wheel_position_).color; |
| 97 | color_wheel_position_ = (color_wheel_position_ + 1) % color_wheel_.size(); |
| 98 | } else { |
| 99 | auto it = std::find_if( |
| 100 | color_wheel_.begin(), color_wheel_.end(), |
| 101 | [options_color = options.color](const ColorWheelColor &color) { |
| 102 | return color.name == options_color; |
| 103 | }); |
| 104 | CHECK(it != color_wheel_.end()) << ": Failed to find " << options.color; |
| 105 | color = &(it->color); |
| 106 | } |
James Kuszmaul | 4867136 | 2020-12-24 13:54:16 -0800 | [diff] [blame] | 107 | |
James Kuszmaul | 19217a4 | 2022-06-17 10:54:29 -0700 | [diff] [blame] | 108 | LineStyle::Builder style_builder = builder_.MakeBuilder<LineStyle>(); |
Austin Schuh | ea62f60 | 2022-07-18 16:53:04 -0700 | [diff] [blame] | 109 | if (options.line_style.find('*') != options.line_style.npos) { |
Austin Schuh | 69d0b73 | 2022-07-20 21:19:32 -0700 | [diff] [blame^] | 110 | style_builder.add_point_size(options.point_size); |
James Kuszmaul | 19217a4 | 2022-06-17 10:54:29 -0700 | [diff] [blame] | 111 | } else { |
| 112 | style_builder.add_point_size(0.0); |
| 113 | } |
Austin Schuh | ea62f60 | 2022-07-18 16:53:04 -0700 | [diff] [blame] | 114 | style_builder.add_draw_line(options.line_style.find('-') != |
| 115 | options.line_style.npos); |
James Kuszmaul | 19217a4 | 2022-06-17 10:54:29 -0700 | [diff] [blame] | 116 | const flatbuffers::Offset<LineStyle> style_offset = style_builder.Finish(); |
| 117 | |
James Kuszmaul | 4867136 | 2020-12-24 13:54:16 -0800 | [diff] [blame] | 118 | auto line_builder = builder_.MakeBuilder<Line>(); |
| 119 | line_builder.add_label(label_offset); |
| 120 | line_builder.add_points(points_offset); |
| 121 | line_builder.add_color(color); |
James Kuszmaul | 19217a4 | 2022-06-17 10:54:29 -0700 | [diff] [blame] | 122 | line_builder.add_style(style_offset); |
James Kuszmaul | 4867136 | 2020-12-24 13:54:16 -0800 | [diff] [blame] | 123 | lines_.push_back(line_builder.Finish()); |
| 124 | } |
| 125 | |
| 126 | void Plotter::MaybeFinishFigure() { |
| 127 | if (!lines_.empty()) { |
| 128 | const flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Line>>> |
| 129 | lines_offset = builder_.fbb()->CreateVector(lines_); |
| 130 | auto figure_builder = builder_.MakeBuilder<Figure>(); |
| 131 | figure_builder.add_title(figure_title_); |
| 132 | figure_builder.add_position(position_); |
| 133 | figure_builder.add_lines(lines_offset); |
| 134 | figure_builder.add_xlabel(xlabel_); |
| 135 | figure_builder.add_share_x_axis(share_x_axis_); |
| 136 | figure_builder.add_ylabel(ylabel_); |
| 137 | figures_.push_back(figure_builder.Finish()); |
| 138 | } |
| 139 | lines_.clear(); |
| 140 | figure_title_.o = 0; |
| 141 | xlabel_.o = 0; |
| 142 | ylabel_.o = 0; |
| 143 | position_.o = 0; |
| 144 | share_x_axis_ = false; |
| 145 | color_wheel_position_ = 0; |
| 146 | } |
| 147 | |
| 148 | void Plotter::Publish() { |
| 149 | MaybeFinishFigure(); |
| 150 | const flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Figure>>> |
| 151 | figures_offset = builder_.fbb()->CreateVector(figures_); |
| 152 | |
| 153 | auto plot_builder = builder_.MakeBuilder<Plot>(); |
| 154 | plot_builder.add_title(title_); |
| 155 | plot_builder.add_figures(figures_offset); |
| 156 | |
Austin Schuh | ea62f60 | 2022-07-18 16:53:04 -0700 | [diff] [blame] | 157 | CHECK_EQ(builder_.Send(plot_builder.Finish()), aos::RawSender::Error::kOk); |
James Kuszmaul | 4867136 | 2020-12-24 13:54:16 -0800 | [diff] [blame] | 158 | |
| 159 | builder_ = plot_sender_.MakeBuilder(); |
| 160 | |
| 161 | title_.o = 0; |
| 162 | figures_.clear(); |
| 163 | next_top_ = 0; |
| 164 | } |
| 165 | |
| 166 | } // namespace analysis |
| 167 | } // namespace frc971 |