• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

paulmthompson / WhiskerToolbox / 17270491352

27 Aug 2025 02:57PM UTC coverage: 65.333%. Remained the same
17270491352

push

github

paulmthompson
Merge branch 'main' of https://github.com/paulmthompson/WhiskerToolbox

352 of 628 new or added lines in 92 files covered. (56.05%)

357 existing lines in 24 files now uncovered.

26429 of 40453 relevant lines covered (65.33%)

1119.34 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/DataManager/DigitalTimeSeries/IO/CSV/Digital_Event_Series_CSV.cpp
1
#include "Digital_Event_Series_CSV.hpp"
2

3
#include "DigitalTimeSeries/Digital_Event_Series.hpp"
4
#include "loaders/loading_utils.hpp"
5

6
#include <fstream>
7
#include <sstream>
8
#include <filesystem>
9
#include <iostream>
10
#include <map>
11
#include <iomanip>
12

13
std::vector<std::shared_ptr<DigitalEventSeries>> load(CSVEventLoaderOptions const & options) {
×
14
    std::vector<std::shared_ptr<DigitalEventSeries>> result;
×
15
    
16
    std::ifstream file(options.filepath);
×
17
    if (!file.is_open()) {
×
18
        std::cerr << "Error loading digital event series: File " << options.filepath << " not found." << std::endl;
×
19
        return result;
×
20
    }
21

22
    std::string line;
×
23
    bool first_line = true;
×
24
    
25
    // Map to store events by identifier (for multi-column case)
26
    std::map<std::string, std::vector<float>> events_by_identifier;
×
27
    
28
    // Vector to store events (for single column case)
29
    std::vector<float> single_events;
×
30
    
31
    bool has_identifier_column = (options.identifier_column >= 0);
×
32

33
    while (std::getline(file, line)) {
×
34
        // Skip header if present
35
        if (first_line && options.has_header) {
×
36
            first_line = false;
×
37
            continue;
×
38
        }
39
        first_line = false;
×
40

41
        // Skip empty lines
42
        if (line.empty()) {
×
43
            continue;
×
44
        }
45

46
        // Parse the line
47
        std::vector<std::string> tokens;
×
48
        std::stringstream ss(line);
×
49
        std::string token;
×
50

51
        // Split by delimiter
52
        while (std::getline(ss, token, options.delimiter[0])) {
×
53
            tokens.push_back(token);
×
54
        }
55

56
        // Validate we have enough columns
57
        int required_columns = std::max(options.event_column, 
×
58
                                       has_identifier_column ? options.identifier_column : -1) + 1;
×
59
        if (static_cast<int>(tokens.size()) < required_columns) {
×
60
            std::cerr << "Warning: Line has insufficient columns (expected at least " 
×
61
                      << required_columns << ", got " << tokens.size() << "): " << line << std::endl;
×
62
            continue;
×
63
        }
64

65
        try {
66
            // Parse event timestamp
NEW
67
            float event_time = std::stof(tokens[static_cast<size_t>(options.event_column)]);
×
68
            
69
            if (has_identifier_column) {
×
70
                // Multi-column case: group by identifier
NEW
71
                std::string identifier = tokens[static_cast<size_t>(options.identifier_column)];
×
72
                events_by_identifier[identifier].push_back(event_time);
×
73
            } else {
×
74
                // Single column case: add to main vector
75
                single_events.push_back(event_time);
×
76
            }
77
            
78
        } catch (std::exception const & e) {
×
79
            std::cerr << "Warning: Failed to parse line: " << line << " - " << e.what() << std::endl;
×
80
            continue;
×
81
        }
×
82
    }
×
83

84
    file.close();
×
85

86
    // Create DigitalEventSeries objects
87
    if (has_identifier_column) {
×
88
        // Multi-column case: create one series per identifier
89
        for (auto const & [identifier, events] : events_by_identifier) {
×
90
            if (!events.empty()) {
×
91
                auto series = std::make_shared<DigitalEventSeries>(events);
×
92
                result.push_back(series);
×
93
                std::cout << "Created event series '" << options.base_name << "_" << identifier 
×
94
                          << "' with " << events.size() << " events" << std::endl;
×
95
            }
×
96
        }
97
        
98
        std::cout << "Successfully loaded " << result.size() << " event series from " 
×
99
                  << options.filepath << std::endl;
×
100
    } else {
101
        // Single column case: create one series
102
        if (!single_events.empty()) {
×
103
            auto series = std::make_shared<DigitalEventSeries>(single_events);
×
104
            result.push_back(series);
×
105
            std::cout << "Created event series '" << options.base_name 
×
106
                      << "' with " << single_events.size() << " events" << std::endl;
×
107
        }
×
108
        
109
        std::cout << "Successfully loaded " << single_events.size() << " events from " 
×
110
                  << options.filepath << std::endl;
×
111
    }
112

113
    return result;
×
114
}
×
115

116
void save(DigitalEventSeries const * event_data, CSVEventSaverOptions const & opts) {
×
117
    if (!event_data) {
×
118
        std::cerr << "Error: DigitalEventSeries data is null. Cannot save." << std::endl;
×
119
        return;
×
120
    }
121

122
    auto result = check_dir_and_get_full_path(opts);
×
123
    if (!result.has_value()) {
×
124
        return;
×
125
    }
126

127
    std::string const full_path = result.value();
×
128

129
    std::ofstream fout;
×
130
    fout.open(full_path, std::ios_base::out | std::ios_base::trunc);
×
131

132
    if (!fout.is_open()) {
×
133
        std::cerr << "Error: Could not open file for writing: " << full_path << std::endl;
×
134
        return;
×
135
    }
136

137
    if (opts.save_header && !opts.header.empty()) {
×
138
        fout << opts.header << opts.line_delim;
×
139
    }
140

141
    std::vector<float> const & events = event_data->getEventSeries();
×
142

143
    // Set precision for floating point output
144
    fout << std::fixed << std::setprecision(opts.precision);
×
145

146
    for (auto const & event_time : events) {
×
147
        fout << event_time << opts.line_delim;
×
148
        if (fout.fail()) {
×
149
            std::cerr << "Error: Failed while writing data to file: " << full_path << std::endl;
×
150
            fout.close();
×
151
            return;
×
152
        }
153
    }
154

155
    fout.close();
×
156
    if (fout.fail()) {
×
157
        std::cerr << "Error: Failed to properly close file: " << full_path << std::endl;
×
158
    } else {
159
        std::cout << "Successfully saved digital event series to " << full_path 
160
                  << " (" << events.size() << " events)" << std::endl;
×
161
    }
162
} 
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc