v01
This commit is contained in:
53
thirdparty/Pangolin/tools/Plotter/CMakeLists.txt
vendored
Normal file
53
thirdparty/Pangolin/tools/Plotter/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
# Find Pangolin (https://github.com/stevenlovegrove/Pangolin)
|
||||
find_package(Pangolin 0.4 REQUIRED)
|
||||
include_directories(${Pangolin_INCLUDE_DIRS})
|
||||
|
||||
add_executable(Plotter main.cpp)
|
||||
target_link_libraries(Plotter ${Pangolin_LIBRARIES})
|
||||
|
||||
|
||||
# Make file association
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux" AND ${CMAKE_MAJOR_VERSION} VERSION_GREATER "2.9.9" )
|
||||
file( GENERATE
|
||||
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/pangoplot.desktop"
|
||||
CONTENT
|
||||
"[Desktop Entry]
|
||||
Version=1.0
|
||||
Type=Application
|
||||
Categories=Utility
|
||||
Name=PangoPlotter
|
||||
GenericName=Plotter
|
||||
Comment=View CSV data series
|
||||
Exec=$<TARGET_FILE:Plotter> %U
|
||||
TryExec=$<TARGET_FILE:Plotter>
|
||||
Icon=application-x-pango
|
||||
Terminal=false
|
||||
StartupNotify=false
|
||||
MimeType=text/csv;text/comma-separated-values;application/x-pangoplot;application/csv"
|
||||
)
|
||||
|
||||
add_custom_target(
|
||||
register-mime-info-plotter
|
||||
COMMAND mkdir -p $ENV{HOME}/.local/share/mime/packages/
|
||||
COMMAND mkdir -p $ENV{HOME}/.local/share/applications/
|
||||
COMMAND mkdir -p $ENV{HOME}/.local/share/icons/hicolor/scalable/mimetypes/
|
||||
COMMAND cp "${CMAKE_CURRENT_SOURCE_DIR}/application-x-pangoplot.xml" $ENV{HOME}/.local/share/mime/packages/
|
||||
COMMAND cp "${CMAKE_CURRENT_SOURCE_DIR}/../VideoViewer/application-x-pango.svg" $ENV{HOME}/.local/share/icons/hicolor/scalable/mimetypes/
|
||||
COMMAND cp "${CMAKE_CURRENT_BINARY_DIR}/pangoplot.desktop" $ENV{HOME}/.local/share/applications/
|
||||
COMMAND gtk-update-icon-cache $ENV{HOME}/.local/share/icons/hicolor -f -t
|
||||
COMMAND update-mime-database $ENV{HOME}/.local/share/mime
|
||||
COMMAND update-desktop-database $ENV{HOME}/.local/share/applications
|
||||
DEPENDS Plotter
|
||||
VERBATIM
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
#######################################################
|
||||
## Install
|
||||
|
||||
install(TARGETS Plotter
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib
|
||||
)
|
||||
9
thirdparty/Pangolin/tools/Plotter/application-x-pangoplot.xml
vendored
Normal file
9
thirdparty/Pangolin/tools/Plotter/application-x-pangoplot.xml
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
|
||||
<mime-type type="application/x-pangoplot">
|
||||
<comment>Pangolin Video File</comment>
|
||||
<icon name="application-x-pango"/>
|
||||
<glob-deleteall/>
|
||||
<glob pattern="*.csv"/>
|
||||
</mime-type>
|
||||
</mime-info>
|
||||
87
thirdparty/Pangolin/tools/Plotter/csv_data_loader.h
vendored
Normal file
87
thirdparty/Pangolin/tools/Plotter/csv_data_loader.h
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
#pragma once
|
||||
|
||||
#include <pangolin/platform.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
|
||||
class CsvDataLoader
|
||||
{
|
||||
public:
|
||||
CsvDataLoader(const std::vector<std::string>& csv_files, char delim = ',')
|
||||
: delim(delim)
|
||||
{
|
||||
for(const auto& f : csv_files) {
|
||||
if(f == "-") {
|
||||
streams.push_back(&std::cin);
|
||||
}else{
|
||||
std::ifstream* pFile = new std::ifstream(f);
|
||||
owned_streams.emplace_back(pFile);
|
||||
streams.push_back(pFile);
|
||||
PANGO_ASSERT(pFile->is_open());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SkipStreamRows(const std::vector<size_t>& rows_to_skip)
|
||||
{
|
||||
if(rows_to_skip.size()) {
|
||||
PANGO_ASSERT(rows_to_skip.size() == streams.size());
|
||||
std::vector<std::string> dummy_row;
|
||||
|
||||
for(size_t i=0; i < streams.size(); ++i) {
|
||||
for(size_t r=0; r < rows_to_skip[i]; ++r) {
|
||||
if(!AppendColumns(dummy_row, *streams[i], delim)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReadRow(std::vector<std::string>& row)
|
||||
{
|
||||
row.clear();
|
||||
|
||||
for(auto& s : streams) {
|
||||
if(!AppendColumns(row, *s, delim)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
static bool AppendColumns(std::vector<std::string>& cols, std::istream& s, char delim)
|
||||
{
|
||||
// Read line from stream
|
||||
std::string row;
|
||||
std::getline(s,row);
|
||||
|
||||
// Failure if no lines to read
|
||||
if(!s.good()) return false;
|
||||
|
||||
std::stringstream row_stream(row);
|
||||
std::string cell;
|
||||
|
||||
// Read cells
|
||||
while(std::getline(row_stream, cell, delim)) {
|
||||
cols.push_back(cell);
|
||||
}
|
||||
|
||||
// Check for an empty trailing cell
|
||||
if (!row_stream && cell.empty()) {
|
||||
cols.push_back("");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
char delim;
|
||||
std::vector<std::istream*> streams;
|
||||
std::vector<std::unique_ptr<std::istream>> owned_streams;
|
||||
};
|
||||
126
thirdparty/Pangolin/tools/Plotter/main.cpp
vendored
Normal file
126
thirdparty/Pangolin/tools/Plotter/main.cpp
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
#include <pangolin/pangolin.h>
|
||||
#include <pangolin/utils/argagg.hpp>
|
||||
#include <pangolin/utils/file_utils.h>
|
||||
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
|
||||
#include "csv_data_loader.h"
|
||||
|
||||
namespace argagg{ namespace convert {
|
||||
|
||||
template<>
|
||||
pangolin::Rangef arg<pangolin::Rangef>(char const* str)
|
||||
{
|
||||
std::stringstream ss(str);
|
||||
pangolin::Rangef r;
|
||||
ss >> r.min; ss.get(); ss >> r.max;
|
||||
return r;
|
||||
}
|
||||
}}
|
||||
|
||||
int main( int argc, char* argv[] )
|
||||
{
|
||||
// Parse command line
|
||||
argagg::parser argparser {{
|
||||
{ "help", {"-h", "--help"}, "Print usage information and exit.", 0},
|
||||
{ "header", {"-H","--header"}, "Treat 1st row as column titles", 0},
|
||||
{ "x", {"-x"}, "X-axis series to plot, seperated by commas (default: '$i')", 1},
|
||||
{ "y", {"-y"}, "Y-axis series to plot, seperated by commas (eg: '$0,sin($1),sqrt($2+$3)' )", 1},
|
||||
{ "delim", {"-d"}, "Expected column delimitter (default: ',')", 1},
|
||||
{ "xrange", {"-X","--x-range"}, "X-Axis min:max view (default: '0:100')", 1},
|
||||
{ "yrange", {"-Y","--y-range"}, "Y-Axis min:max view (default: '0:100')", 1},
|
||||
{ "skip", {"-s","--skip"}, "Skip n rows of file, seperated by commas per file (default: '0,...')", 1},
|
||||
}};
|
||||
|
||||
argagg::parser_results args = argparser.parse(argc, argv);
|
||||
if ( (bool)args["help"] || !args.pos.size()) {
|
||||
std::cerr << "Usage: Plotter [options] file1.csv [fileN.csv]*" << std::endl
|
||||
<< argparser << std::endl
|
||||
<< " where: $i is a placeholder for the datum index," << std::endl
|
||||
<< " $0, $1, ... are placeholders for the 0th, 1st, ... sequential datum values over the input files" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Default values
|
||||
const std::string xs = args["x"].as<std::string>("$i");
|
||||
const std::string ys = args["y"].as<std::string>("$0");
|
||||
const char delim = args["delim"].as<char>(',');
|
||||
const pangolin::Rangef xrange = args["xrange"].as<>(pangolin::Rangef(0.0f,100.0f));
|
||||
const pangolin::Rangef yrange = args["yrange"].as<>(pangolin::Rangef(0.0f,100.0f));
|
||||
const std::string skips = args["skip"].as<std::string>("");
|
||||
const std::vector<std::string> skipvecstr = pangolin::Split(skips,',');
|
||||
std::vector<size_t> skipvec;
|
||||
for(const std::string& s : skipvecstr) {
|
||||
skipvec.push_back(std::stoul(s));
|
||||
}
|
||||
if( !(skipvec.size() == 0 || skipvec.size() == args.count()) )
|
||||
{
|
||||
std::cerr << "Skip argument must be empty or correspond to the number of files specified (" << args.count() << ")" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
pangolin::DataLog log;
|
||||
|
||||
CsvDataLoader csv_loader(args.all_as<std::string>(), delim);
|
||||
|
||||
if(args["header"]) {
|
||||
std::vector<std::string> labels;
|
||||
csv_loader.ReadRow(labels);
|
||||
log.SetLabels(labels);
|
||||
}
|
||||
|
||||
// Load asynchronously incase the file is large or is being read interactively from stdin
|
||||
bool keep_loading = true;
|
||||
std::thread data_thread([&](){
|
||||
if(!csv_loader.SkipStreamRows(skipvec)) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> row;
|
||||
|
||||
while(keep_loading && csv_loader.ReadRow(row)) {
|
||||
std::vector<float> row_num(row.size(), std::numeric_limits<float>::quiet_NaN() );
|
||||
for(size_t i=0; i< row_num.size(); ++i) {
|
||||
try{
|
||||
row_num[i] = std::stof(row[i]);
|
||||
}catch(const std::invalid_argument& e){
|
||||
std::cerr << "Warning: couldn't parse '" << row[i] << "' as numeric data (use -H option to include header)" << std::endl;
|
||||
}
|
||||
}
|
||||
log.Log(row_num);
|
||||
}
|
||||
});
|
||||
|
||||
pangolin::CreateWindowAndBind("Plotter", 640, 480);
|
||||
|
||||
pangolin::Plotter plotter(&log, xrange.min, xrange.max, yrange.min, yrange.max, 0.001, 0.001);
|
||||
if( (bool)args["x"] || (bool)args["y"]) {
|
||||
plotter.ClearSeries();
|
||||
std::vector<std::string> xvec = pangolin::Split(xs,',');
|
||||
std::vector<std::string> yvec = pangolin::Split(ys,',');
|
||||
|
||||
if( !(xvec.size() == 1 || xvec.size() == yvec.size()) ) {
|
||||
std::cout << "x-series dimensions must be one, or equal to y-series dimensions" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(size_t i=0; i < yvec.size(); ++i) {
|
||||
plotter.AddSeries( (xvec.size()==1) ? xvec[0] : xvec[i],yvec[i]);
|
||||
}
|
||||
}
|
||||
|
||||
plotter.SetBounds(0.0, 1.0, 0.0, 1.0);
|
||||
pangolin::DisplayBase().AddDisplay(plotter);
|
||||
|
||||
while( !pangolin::ShouldQuit() )
|
||||
{
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
pangolin::FinishFrame();
|
||||
}
|
||||
|
||||
keep_loading = false;
|
||||
data_thread.join();
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user