X Tutup
#include "gnuplotpp/data.hpp" #include #include #include #include namespace gnuplotpp { namespace { std::string available_columns(const std::unordered_map>& cols) { std::vector names; names.reserve(cols.size()); for (const auto& [name, _] : cols) { names.push_back(name); } std::sort(names.begin(), names.end()); std::string out; for (std::size_t i = 0; i < names.size(); ++i) { out += names[i]; if (i + 1 < names.size()) { out += ", "; } } return out; } } // namespace const std::vector& DataTable::column(const std::string& name) const { const auto it = columns.find(name); if (it == columns.end()) { throw std::out_of_range("column not found: " + name + " (available: " + available_columns(columns) + ")"); } return it->second; } bool DataTable::has_column(const std::string& name) const { return columns.find(name) != columns.end(); } void DataTable::require_columns(std::span names) const { for (const auto& name : names) { if (!has_column(name)) { throw std::out_of_range("required column missing: " + name + " (available: " + available_columns(columns) + ")"); } } } std::size_t DataTable::row_count() const { if (columns.empty()) { return 0; } const auto first = columns.begin()->second.size(); for (const auto& [name, values] : columns) { if (values.size() != first) { throw std::runtime_error("inconsistent row count in column: " + name); } } return first; } void DataTable::add_line(Axes& ax, SeriesSpec spec, const std::string& x_name, const std::string& y_name) const { spec.type = SeriesType::Line; ax.add_series(spec, column(x_name), column(y_name)); } void DataTable::add_scatter(Axes& ax, SeriesSpec spec, const std::string& x_name, const std::string& y_name) const { spec.type = SeriesType::Scatter; ax.add_series(spec, column(x_name), column(y_name)); } DataTable read_csv_numeric(const std::filesystem::path& path, char delimiter) { std::ifstream in(path); if (!in.is_open()) { throw std::runtime_error("failed to open CSV: " + path.string()); } std::string header; if (!std::getline(in, header)) { throw std::runtime_error("CSV is empty: " + path.string()); } std::vector names; { std::stringstream ss(header); std::string token; while (std::getline(ss, token, delimiter)) { names.push_back(token); } } if (names.empty()) { throw std::runtime_error("CSV header parse failed: " + path.string()); } DataTable tbl; for (const auto& name : names) { tbl.columns[name] = {}; } std::string line; std::size_t line_no = 1; while (std::getline(in, line)) { ++line_no; if (line.empty()) { continue; } std::stringstream ss(line); std::string token; std::size_t i = 0; while (std::getline(ss, token, delimiter) && i < names.size()) { tbl.columns[names[i++]].push_back(std::stod(token)); } if (i != names.size()) { throw std::runtime_error("CSV row has wrong number of fields at line " + std::to_string(line_no)); } } (void)tbl.row_count(); return tbl; } std::string label_with_unit(const std::string& name, const std::string& unit) { if (unit.empty()) { return name; } return name + " [" + unit + "]"; } } // namespace gnuplotpp
X Tutup