Skip to content

Commit

Permalink
[API] added struct LoadSpec, changed Fityk::load(),
Browse files Browse the repository at this point in the history
using LoadSpec also internally,
updated docs and a test
  • Loading branch information
wojdyr committed May 4, 2015
1 parent 34106a0 commit 7f24167
Show file tree
Hide file tree
Showing 10 changed files with 98 additions and 97 deletions.
3 changes: 2 additions & 1 deletion doc/data.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ where
Column 0 means index of the point: 0 for the first point,
1 for the second, etc.

- *block* is only supported by formats with multiple blocks of data.
- *block* - selects one or more blocks of data from a multi-block file
such as VAMAS

- *filetype* usually can be omitted, because in most of the cases
the filetype can be detected; the list of supported filetypes is
Expand Down
8 changes: 8 additions & 0 deletions doc/script.rst
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,14 @@ Settings
Data
----

.. method:: Fityk.load(spec [, d])

Load data to @*d* slot. The first argument is either a string with path
or LoadSpec struct that apart from the ``path`` has also the following
optional members: ``x_col``, ``y_col``, ``sig_col``, ``blocks``,
``format``, ``options``. The meaning of these parameters is the same
as described in :ref:`dataload`.

.. method:: Fityk.load_data(d, xx, yy, sigmas [, title])

Load data to @*d* slot. *xx* and *yy* must be numeric arrays
Expand Down
73 changes: 30 additions & 43 deletions fityk/data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ string get_file_basename(const string& path)

Data::Data(BasicContext* ctx, Model *model)
: ctx_(ctx), model_(model),
given_x_(INT_MAX), given_y_(INT_MAX), given_s_(INT_MAX),
x_step_(0.), has_sigma_(false)
{
}
Expand All @@ -56,13 +55,15 @@ string Data::get_info() const
s = "No data points.";
else
s = S(p_.size()) + " points, " + S(active_.size()) + " active.";
if (!filename_.empty())
s += "\nFilename: " + filename_;
if (given_x_ != INT_MAX || given_y_ != INT_MAX || given_s_ != INT_MAX)
s += "\nColumns: " + (given_x_ != INT_MAX ? S(given_x_) : S("_"))
+ ", " + (given_y_ != INT_MAX ? S(given_y_) : S("_"));
if (given_s_ != INT_MAX)
s += ", " + S(given_s_);
if (!spec_.path.empty())
s += "\nFilename: " + spec_.path;
if (spec_.x_col != LoadSpec::NN || spec_.y_col != LoadSpec::NN ||
spec_.sig_col != LoadSpec::NN)
s += "\nColumns: "
+ (spec_.x_col != LoadSpec::NN ? S(spec_.x_col) : S("_"))
+ ", " + (spec_.y_col != LoadSpec::NN ? S(spec_.y_col) : S("_"));
if (spec_.sig_col != LoadSpec::NN)
s += ", " + S(spec_.sig_col);
if (!title_.empty())
s += "\nData title: " + title_;
if (active_.size() != p_.size())
Expand All @@ -73,11 +74,8 @@ string Data::get_info() const
// does not clear model
void Data::clear()
{
filename_ = "";
spec_ = LoadSpec();
title_ = "";
given_x_ = given_y_ = given_s_ = INT_MAX;
given_options_.clear();
given_blocks_.clear();
p_.clear();
x_step_ = 0;
active_.clear();
Expand Down Expand Up @@ -144,15 +142,14 @@ void Data::set_points(const vector<Point> &p)

void Data::revert()
{
if (filename_.empty())
if (spec_.path.empty())
throw ExecuteError("Dataset can't be reverted, it was not loaded "
"from file");
string old_title = title_;
string old_filename = filename_;
// this->filename_ should not be passed by ref to load_file(), because it's
// cleared before being used
load_file(old_filename, given_x_, given_y_, given_s_,
given_blocks_, given_format_, given_options_);
LoadSpec old_spec = spec_;
// this->spec_ should not be passed by ref to load_file()
// because path is cleared before being used
load_file(old_spec);
title_ = old_title;
}

Expand All @@ -177,7 +174,7 @@ void Data::load_data_sum(const vector<const Data*>& dd, const string& op)
// data should be sorted after apply_operation()
clear();
title_ = new_title;
filename_ = new_filename;
spec_.path = new_filename;
p_ = new_p;
has_sigma_ = true;
find_step();
Expand Down Expand Up @@ -278,42 +275,38 @@ void Data::verify_options(const xylib::DataSet* ds, const string& options)
}


// for column indices, INT_MAX is used as not given
void Data::load_file (const string& filename,
int idx_x, int idx_y, int idx_s,
const vector<int>& blocks,
const string& format, const string& options)
void Data::load_file(const LoadSpec& spec)
{
if (filename.empty())
if (spec.path.empty())
return;

string block_name;
try {
string ds_options = tr_opt(options);
string ds_options = tr_opt(spec.options);
shared_ptr<const xylib::DataSet> xyds(
xylib::cached_load_file(filename, format, ds_options));
xylib::cached_load_file(spec.path, spec.format, ds_options));
verify_options(xyds.get(), ds_options);
clear(); //removing previous file
vector<int> bb = blocks.empty() ? vector1(0) : blocks;
vector<int> bb = spec.blocks.empty() ? vector1(0) : spec.blocks;

v_foreach (int, b, bb) {
assert(xyds);
const xylib::Block* block = xyds->get_block(*b);
const xylib::Column& xcol
= block->get_column(idx_x != INT_MAX ? idx_x : 1);
= block->get_column(spec.x_col != LoadSpec::NN ? spec.x_col : 1);
const xylib::Column& ycol
= block->get_column(idx_y != INT_MAX ? idx_y : 2);
= block->get_column(spec.y_col != LoadSpec::NN ? spec.y_col : 2);
int n = block->get_point_count();
if (n < 5 && bb.size() == 1)
ctx_->ui()->warn("Only "+S(n)+" data points found in file.");

p_.reserve(p_.size() + n);
if (idx_s == INT_MAX) {
if (spec.sig_col == LoadSpec::NN) {
for (int i = 0; i < n; ++i) {
p_.push_back(Point(xcol.get_value(i), ycol.get_value(i)));
}
} else {
const xylib::Column& scol = block->get_column(idx_s);
const xylib::Column& scol = block->get_column(spec.sig_col);
for (int i = 0; i < n; ++i) {
p_.push_back(Point(xcol.get_value(i), ycol.get_value(i),
scol.get_value(i)));
Expand Down Expand Up @@ -346,23 +339,17 @@ void Data::load_file (const string& filename,
if (!block_name.empty())
title_ = block_name;
else {
title_ = get_file_basename(filename);
if (idx_x != INT_MAX && idx_y != INT_MAX)
title_ += ":" + S(idx_x) + ":" + S(idx_y);
title_ = get_file_basename(spec.path);
if (spec.x_col != LoadSpec::NN && spec.y_col != LoadSpec::NN)
title_ += ":" + S(spec.x_col) + ":" + S(spec.y_col);
}

if (x_step_ == 0 || blocks.size() > 1) {
if (x_step_ == 0 || spec.blocks.size() > 1) {
sort_points();
find_step();
}

filename_ = filename;
given_x_ = idx_x;
given_y_ = idx_y;
given_s_ = idx_s;
given_blocks_ = blocks;
given_options_ = options;

spec_ = spec;
post_load();
}

Expand Down
16 changes: 5 additions & 11 deletions fityk/data.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,7 @@ public :
~Data();
std::string get_info() const;

void load_file(const std::string& filename,
int idx_x, int idx_y, int idx_s,
const std::vector<int>& blocks,
const std::string& format, const std::string& options);
void load_file(const LoadSpec& spec);

int load_arrays(const std::vector<realt>& x, const std::vector<realt>& y,
const std::vector<realt>& sigma,
Expand Down Expand Up @@ -80,9 +77,9 @@ public :
double get_x_max() const;
std::vector<Point> const& points() const { return p_; }
std::vector<Point>& get_mutable_points() { return p_; }
int get_given_x() const { return given_x_; }
int get_given_y() const { return given_y_; }
int get_given_s() const { return given_s_; }
int get_given_x() const { return spec_.x_col; }
int get_given_y() const { return spec_.y_col; }
int get_given_s() const { return spec_.sig_col; }
void revert();
Model* model() { return model_; }
const Model* model() const { return model_; }
Expand All @@ -92,10 +89,7 @@ public :
Model* const model_;
std::string title_;
std::string filename_;
int given_x_, given_y_, given_s_;/// columns given when loading the file
std::vector<int> given_blocks_;
std::string given_format_;
std::string given_options_;
LoadSpec spec_; // given when loading file
double x_step_; // 0.0 if not fixed;
bool has_sigma_;
std::vector<Point> p_;
Expand Down
13 changes: 6 additions & 7 deletions fityk/fityk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,16 +273,15 @@ double Fityk::get_view_boundary(char side)
}
}

void Fityk::load(int dataset, string const& path,
int block, int x_col, int y_col, int sig_col,
string const& format, string const& options)
void Fityk::load(LoadSpec const& spec, int dataset)
throw(ExecuteError)
{
if (dataset == DEFAULT_DATASET)
dataset = priv_->dk.default_idx();
try {
priv_->dk.do_import_dataset(dataset < 0, dataset,
path, x_col, y_col, sig_col == 0 ? INT_MAX : sig_col,
vector1(block), format, options,
priv_, priv_->mgr);
bool new_dataset = (dataset < 0);
priv_->dk.do_import_dataset(new_dataset, dataset, spec,
priv_, priv_->mgr);
}
CATCH_EXECUTE_ERROR
}
Expand Down
21 changes: 18 additions & 3 deletions fityk/fityk.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,21 @@ struct FITYK_API Point
bool operator< (Point const& q) const { return x < q.x; }
};

/// the only use of this struct is as an argument to Fityk::load()
struct FITYK_API LoadSpec
{
enum { NN = -10000 }; // not given, default value
std::string path; // utf8 (ascii is valid utf8)
std::vector<int> blocks;
int x_col;
int y_col;
int sig_col;
std::string format;
std::string options;
LoadSpec() : x_col(NN), y_col(NN), sig_col(NN) {}
explicit LoadSpec(std::string const& p)
: path(p), x_col(NN), y_col(NN), sig_col(NN) {}
};


/// the public API to libfityk
Expand All @@ -167,10 +182,10 @@ class FITYK_API Fityk


/// load data from file (path should be ascii or utf8, col=0 is index)
void load(int dataset, std::string const& path,
int block=0, int x_col=1, int y_col=2, int sig_col=0,
std::string const& format="", std::string const& options="")
void load(LoadSpec const& spec, int dataset=DEFAULT_DATASET)
throw(ExecuteError);
void load(std::string const& path, int dataset=DEFAULT_DATASET)
throw(ExecuteError) { load(LoadSpec(path), dataset); }

/// load data from arrays
void load_data(int dataset,
Expand Down
43 changes: 22 additions & 21 deletions fityk/logic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,29 +156,28 @@ void DataKeeper::import_dataset(int slot, const string& data_path,
// split "data_path" (e.g. "foo.dat:1:2,3::") into filename
// and colon-separated indices
int count_colons = ::count(data_path.begin(), data_path.end(), ':');
string filename;
LoadSpec spec;
vector<int> indices[3];
vector<int> block_range;
if (count_colons >= 4) {
// take filename
string::size_type fn_end = string::npos;
for (int i = 0; i < 4; ++i)
fn_end = data_path.rfind(':', fn_end - 1);
filename = data_path.substr(0, fn_end);
spec.path = data_path.substr(0, fn_end);

// blocks
string::size_type end_pos = data_path.size();
string::size_type bpos = data_path.rfind(':', end_pos - 1);
string::size_type blen = end_pos - bpos - 1;
if (blen > 0) {
int block_count = Data::count_blocks(filename, format, options);
int block_count = Data::count_blocks(spec.path, format, options);
string range = data_path.substr(bpos+1, blen);
block_range = parse_int_range(range, block_count-1);
spec.blocks = parse_int_range(range, block_count-1);
}
end_pos = bpos;

int first_block = block_range.empty() ? 0 : block_range[0];
int col_count = Data::count_columns(filename, format, options,
int first_block = spec.blocks.empty() ? 0 : spec.blocks[0];
int col_count = Data::count_columns(spec.path, format, options,
first_block);
for (int i = 2; i >= 0; --i) {
string::size_type pos = data_path.rfind(':', end_pos - 1);
Expand All @@ -191,7 +190,7 @@ void DataKeeper::import_dataset(int slot, const string& data_path,
}
assert(fn_end == end_pos);
} else {
filename = data_path;
spec.path = data_path;
}

if (indices[0].size() > 1)
Expand All @@ -201,22 +200,24 @@ void DataKeeper::import_dataset(int slot, const string& data_path,
if (indices[1].size() > 1 && !new_dataset)
throw ExecuteError("Multiple y columns can be specified only with @+");

int idx_x = indices[0].empty() ? INT_MAX : indices[0][0];
if (indices[1].empty())
indices[1].push_back(INT_MAX);
int idx_s = indices[2].empty() ? INT_MAX : indices[2][0];
if (!indices[0].empty())
spec.x_col = indices[0][0];
if (!indices[2].empty())
spec.sig_col = indices[2][0];

for (size_t i = 0; i < indices[1].size(); ++i)
do_import_dataset(new_dataset, slot,
filename, idx_x, indices[1][i], idx_s, block_range,
format, options, ctx, mgr);
spec.format = format;
spec.options = options;
if (indices[1].empty())
indices[1].push_back(LoadSpec::NN);
for (size_t i = 0; i < indices[1].size(); ++i) {
spec.y_col = indices[1][i];
do_import_dataset(new_dataset, slot, spec, ctx, mgr);
}
}


void DataKeeper::do_import_dataset(bool new_dataset, int slot,
const string& filename,
int idx_x, int idx_y, int idx_s,
const vector<int>& block_range,
const string& format, const string& options,
const LoadSpec& spec,
BasicContext* ctx, ModelManager &mgr)
{
Data *d;
Expand All @@ -229,7 +230,7 @@ void DataKeeper::do_import_dataset(bool new_dataset, int slot,
auto_d.reset(new Data(ctx, mgr.create_model()));
d = auto_d.get();
}
d->load_file(filename, idx_x, idx_y, idx_s, block_range, format, options);
d->load_file(spec);
if (auto_d.get())
append(auto_d.release());
}
Expand Down
8 changes: 2 additions & 6 deletions fityk/logic.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,8 @@ class FITYK_API DataKeeper
void import_dataset(int slot, const std::string& data_path,
const std::string& format, const std::string& options,
BasicContext* ctx, ModelManager &mgr);
void do_import_dataset(bool new_dataset, int slot,
const std::string& filename,
int idx_x, int idx_y, int idx_s,
const std::vector<int>& block_range,
const std::string& format, const std::string& options,
BasicContext* ctx, ModelManager &mgr);
void do_import_dataset(bool new_dataset, int slot, const LoadSpec& spec,
BasicContext* ctx, ModelManager &mgr);

private:
int default_idx_;
Expand Down
4 changes: 2 additions & 2 deletions tests/test_data_load.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ def test_load(self):
self.ftk.execute("@0 < '%s'" % self.filename)
self.compare(self.ftk.get_data(), 7)
def test_load_with_lua(self):
self.ftk.execute("lua F:load(0, [[%s]])" % self.filename)
self.ftk.execute("lua F:load([[%s]])" % self.filename)
self.compare(self.ftk.get_data(), 7)
def test_load_with_py(self):
self.ftk.load(0, self.filename)
self.ftk.load(self.filename, 0)
self.compare(self.ftk.get_data(), 7)

class TestText(TextFileLoadBase):
Expand Down

0 comments on commit 7f24167

Please sign in to comment.