-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
widget: added implot real-time line plot widget
- Loading branch information
Showing
14 changed files
with
397 additions
and
108 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/* | ||
* @file rt_line_plot_widget.hpp | ||
* @date 10/26/24 | ||
* @brief this LinePlotWidget serves as an example of how to create a custom | ||
* widget that plots data in real-time | ||
* | ||
* @copyright Copyright (c) 2024 Ruixiang Du (rdu) | ||
*/ | ||
|
||
#ifndef QUICKVIZ_RT_LINE_PLOT_WIDGET_HPP | ||
#define QUICKVIZ_RT_LINE_PLOT_WIDGET_HPP | ||
|
||
#include <unordered_map> | ||
|
||
#include "imview/panel.hpp" | ||
#include "imview/buffer/buffer_registry.hpp" | ||
#include "imview/buffer/scrolling_plot_buffer.hpp" | ||
|
||
namespace quickviz { | ||
class RtLinePlotWidget : public Panel { | ||
public: | ||
struct DataPoint { | ||
float x; // time | ||
float y; // value | ||
}; | ||
|
||
public: | ||
RtLinePlotWidget(const std::string& widget_name); | ||
~RtLinePlotWidget() = default; | ||
|
||
// public methods | ||
void SetPlotTransparency(float alpha); | ||
void SetAxisLabels(const std::string& x_label, const std::string& y_label); | ||
void SetAxisUnits(const std::string& x_unit, const std::string& y_unit); | ||
void SetFixedHistory(float history); | ||
void SetYAxisRange(float min, float max); | ||
void AddLine(const std::string& line_name, const std::string& buffer_name); | ||
|
||
// for internal use | ||
void Draw() override; | ||
|
||
private: | ||
struct PlotSpecs { | ||
std::string name; | ||
ScrollingPlotBuffer internal_buffer; | ||
std::shared_ptr<BufferInterface<DataPoint>> input_buffer; | ||
}; | ||
|
||
float alpha_ = 1.0f; | ||
std::string x_label_; | ||
std::string y_label_; | ||
std::string x_unit_; | ||
std::string y_unit_; | ||
float t_ = 0; | ||
bool fixed_history_ = true; | ||
float history_ = 10.0f; | ||
float y_min_ = 0; | ||
float y_max_ = 1; | ||
std::unordered_map<std::string, PlotSpecs> line_specs_; | ||
}; | ||
} // namespace quickviz | ||
|
||
#endif // QUICKVIZ_RT_LINE_PLOT_WIDGET_HPP |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/* | ||
* scrolling_plot_buffer.cpp | ||
* | ||
* Created on: Mar 25, 2021 17:39 | ||
* Description: | ||
* | ||
* Copyright (c) 2021 Ruixiang Du (rdu) | ||
*/ | ||
|
||
#include "imview/buffer/scrolling_plot_buffer.hpp" | ||
|
||
#include <cmath> | ||
|
||
namespace quickviz { | ||
ScrollingPlotBuffer::ScrollingPlotBuffer(uint32_t size) : buffer_size_(size) { | ||
data_.reserve(size); | ||
} | ||
|
||
void ScrollingPlotBuffer::Resize(uint32_t size) { | ||
data_.reserve(size); | ||
buffer_size_ = size; | ||
} | ||
|
||
std::size_t ScrollingPlotBuffer::GetSize() const { return data_.size(); } | ||
|
||
std::size_t ScrollingPlotBuffer::GetOffset() const { return offset_; } | ||
|
||
void ScrollingPlotBuffer::Erase() { | ||
if (data_.size() > 0) { | ||
data_.shrink(0); | ||
offset_ = 0; | ||
} | ||
} | ||
|
||
void ScrollingPlotBuffer::AddPoint(float x, float y) { | ||
if (data_.size() < buffer_size_) | ||
data_.push_back(ImVec2(x, y)); | ||
else { | ||
data_[offset_] = ImVec2(x, y); | ||
offset_ = (offset_ + 1) % buffer_size_; | ||
} | ||
} | ||
|
||
ImVec2 &ScrollingPlotBuffer::operator[](std::size_t index) { | ||
assert(index < data_.size()); | ||
return data_[index]; | ||
} | ||
} // namespace quickviz |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
/* | ||
* @file line_plot_widget.cpp | ||
* @date 10/26/24 | ||
* @brief | ||
* | ||
* @copyright Copyright (c) 2024 Ruixiang Du (rdu) | ||
*/ | ||
|
||
#include "imview/widget/rt_line_plot_widget.hpp" | ||
|
||
#include <cmath> | ||
#include <iostream> | ||
|
||
#include "implot/implot.h" | ||
|
||
namespace quickviz { | ||
RtLinePlotWidget::RtLinePlotWidget(const std::string& widget_name) | ||
: Panel(widget_name) { | ||
this->SetAutoLayout(false); | ||
this->SetWindowNoMenuButton(); | ||
this->SetNoBackground(true); | ||
} | ||
|
||
void RtLinePlotWidget::SetPlotTransparency(float alpha) { alpha_ = alpha; } | ||
|
||
void RtLinePlotWidget::SetAxisLabels(const std::string& x_label, | ||
const std::string& y_label) { | ||
x_label_ = x_label; | ||
y_label_ = y_label; | ||
} | ||
|
||
void RtLinePlotWidget::SetAxisUnits(const std::string& x_unit, | ||
const std::string& y_unit) { | ||
x_unit_ = x_unit; | ||
y_unit_ = y_unit; | ||
} | ||
|
||
void RtLinePlotWidget::SetFixedHistory(float history) { | ||
fixed_history_ = true; | ||
history_ = history; | ||
} | ||
|
||
void RtLinePlotWidget::SetYAxisRange(float min, float max) { | ||
y_min_ = min; | ||
y_max_ = max; | ||
} | ||
|
||
void RtLinePlotWidget::AddLine(const std::string& line_name, | ||
const std::string& buffer_name) { | ||
line_specs_[line_name].name = line_name; | ||
line_specs_[line_name].internal_buffer = ScrollingPlotBuffer(); | ||
auto& buffer_registry = BufferRegistry::GetInstance(); | ||
line_specs_[line_name].input_buffer = | ||
buffer_registry.GetBuffer<DataPoint>(buffer_name); | ||
} | ||
|
||
void RtLinePlotWidget::Draw() { | ||
Begin(); | ||
{ | ||
ImVec2 contentSize = ImGui::GetContentRegionAvail(); | ||
float width = contentSize.x; | ||
float height = contentSize.y; | ||
|
||
// fetch data from buffer and find the latest time | ||
for (auto& line : line_specs_) { | ||
auto& spec = line.second; | ||
auto size = spec.input_buffer->GetOccupiedSize(); | ||
for (int i = 0; i < size; i++) { | ||
DataPoint pt; | ||
if (spec.input_buffer->Read(pt) != 0) { | ||
if (pt.x > t_) t_ = pt.x; | ||
spec.internal_buffer.AddPoint(pt.x, pt.y); | ||
} | ||
} | ||
} | ||
|
||
static ImPlotAxisFlags flags = | ||
ImPlotAxisFlags_None; // ImPlotAxisFlags_NoTickLabels; | ||
|
||
auto frame_bg = ImGui::GetStyleColorVec4(ImGuiCol_FrameBg); | ||
auto plot_bg = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg); | ||
auto popup_bg = ImGui::GetStyleColorVec4(ImGuiCol_PopupBg); | ||
frame_bg.w = alpha_; | ||
plot_bg.w = alpha_; | ||
popup_bg.w = alpha_; | ||
ImPlot::PushStyleColor(ImPlotCol_FrameBg, frame_bg); | ||
ImPlot::PushStyleColor(ImPlotCol_PlotBg, plot_bg); | ||
ImPlot::PushStyleColor(ImPlotCol_LegendBg, popup_bg); | ||
{ | ||
float plot_height = height - ImGui::GetFrameHeight() * 1.4; | ||
if (fixed_history_) plot_height = height; | ||
if (ImPlot::BeginPlot(("##" + GetName()).c_str(), | ||
ImVec2(-1, plot_height))) { | ||
char* x_label = nullptr; | ||
char* y_label = nullptr; | ||
if (!x_label_.empty()) x_label = &x_label_[0]; | ||
if (!y_label_.empty()) y_label = &y_label_[0]; | ||
ImPlot::SetupAxes(x_label, y_label, flags, flags); | ||
if (!x_unit_.empty()) | ||
ImPlot::SetupAxisFormat(ImAxis_X1, ("%g " + x_unit_).c_str()); | ||
if (!y_unit_.empty()) | ||
ImPlot::SetupAxisFormat(ImAxis_Y1, ("%g " + y_unit_).c_str()); | ||
ImPlot::SetupAxisLimits(ImAxis_X1, t_ - history_, t_, ImGuiCond_Always); | ||
ImPlot::SetupAxisLimits(ImAxis_Y1, y_min_, y_max_); | ||
|
||
for (auto& line : line_specs_) { | ||
auto& spec = line.second; | ||
if (spec.internal_buffer.GetSize() == 0) continue; | ||
ImPlot::PlotLine(spec.name.c_str(), &spec.internal_buffer[0].x, | ||
&spec.internal_buffer[0].y, | ||
spec.internal_buffer.GetSize(), 0, | ||
spec.internal_buffer.GetOffset(), 2 * sizeof(float)); | ||
} | ||
ImPlot::EndPlot(); | ||
} | ||
|
||
if (!fixed_history_) { | ||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - 60); | ||
ImGui::SliderFloat("History", &history_, 1, 30, "%.1f s"); | ||
} | ||
} | ||
ImPlot::PopStyleColor(3); | ||
} | ||
End(); | ||
} | ||
} // namespace quickviz |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.