Changed the way the FilteredCardList on the stats panel selects cards:

used to: by running scripts on cards and comparing to string value of selected group
  now:     by keeping a list of group_ids for all cards, and comparing indices
Added 'bin size' attribute for making a histogram of numeric axes.
Added 'Text length' statistic.

git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@1071 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
twanvl
2008-08-05 23:13:26 +00:00
parent 52ccd7b573
commit 6c782bb033
12 changed files with 186 additions and 105 deletions
+8 -4
View File
@@ -30,10 +30,14 @@ void FilteredCardList::onChangeSet() {
void FilteredCardList::getItems(vector<VoidP>& out) const {
if (filter) {
FOR_EACH(c, set->cards) {
if (filter->keep(c)) {
out.push_back(c);
}
filter->getItems(set->cards,out);
}
}
void CardListFilter::getItems(const vector<CardP>& cards, vector<VoidP>& out) const {
FOR_EACH_CONST(c, cards) {
if (keep(c)) {
out.push_back(c);
}
}
}
+3 -1
View File
@@ -21,7 +21,9 @@ class CardListFilter : public IntrusivePtrVirtualBase {
public:
virtual ~CardListFilter() {}
/// Should a card be shown in the list?
virtual bool keep(const CardP& card) = 0;
virtual bool keep(const CardP& card) const { return false; }
/// Select cards from a card list
virtual void getItems(const vector<CardP>& cards, vector<VoidP>& out) const;
};
// ----------------------------------------------------------------------------- : FilteredCardList
+102 -36
View File
@@ -16,6 +16,7 @@
DECLARE_TYPEOF_COLLECTION(GraphAxisP);
DECLARE_TYPEOF_COLLECTION(GraphElementP);
DECLARE_TYPEOF_COLLECTION(GraphGroup);
DECLARE_TYPEOF_COLLECTION(GraphDataElement*);
DECLARE_TYPEOF_COLLECTION(GraphP);
DECLARE_TYPEOF_COLLECTION(int);
DECLARE_TYPEOF_COLLECTION(vector<int>);
@@ -32,20 +33,22 @@ DEFINE_EVENT_TYPE(EVENT_GRAPH_SELECT);
// ----------------------------------------------------------------------------- : GraphAxis
void GraphAxis::addGroup(const String& name, UInt size) {
groups.push_back(GraphGroup(name, size));
max = std::max(max, size);
if (!groups.empty() && groups.back().name == name) {
groups.back().size += size;
} else {
groups.push_back(GraphGroup(name, size));
}
max = std::max(max, groups.back().size);
total += size;
}
// ----------------------------------------------------------------------------- : GraphData
GraphElement::GraphElement(const String& v1) {
values.push_back(v1);
}
GraphElement::GraphElement(const String& v1, const String& v2) {
values.push_back(v1);
values.push_back(v2);
}
struct ComparingOriginalIndex {
inline bool operator () (const GraphElementP& a, const GraphElementP& b) {
return a->original_index < b->original_index;
}
};
void GraphDataPre::splitList(size_t axis) {
size_t count = elements.size(); // only the elements that were already there
@@ -63,6 +66,8 @@ void GraphDataPre::splitList(size_t axis) {
comma = v.find_first_of(_(','));
}
}
// re-sort by original_index
sort(elements.begin(), elements.end(), ComparingOriginalIndex());
}
@@ -71,11 +76,25 @@ struct SmartLess{
};
DECLARE_TYPEOF(map<String COMMA UInt COMMA SmartLess>);
String to_bin(double value, double bin_size) {
if (bin_size <= 0 || value == 0) {
return String() << (int)value;
} else {
int bin = ceil(value / bin_size);
return String::Format(_("%.0f%c%.0f"), (bin-1) * bin_size + 1, EN_DASH, bin * bin_size);
}
}
int bin_to_group(double value, double bin_size) {
if (bin_size <= 0 || value == 0) {
return 0;
} else {
return ceil(value / bin_size);
}
}
GraphData::GraphData(const GraphDataPre& d)
: axes(d.axes)
{
// total size
size = (UInt)d.elements.size();
// find groups on each axis
size_t i = 0;
FOR_EACH(a, axes) {
@@ -92,19 +111,27 @@ GraphData::GraphData(const GraphDataPre& d)
double d;
if (c.first.ToDouble(&d)) {
// update mean
a->mean += d * c.second;
a->mean_value += d * c.second;
a->max_value = max(a->max_value, d);
numeric_count += c.second;
// add 0 bars before this value
int next = (int)floor(d);
for (int i = prev ; i < next ; i++) {
a->addGroup(String()<<i, 0);
a->addGroup(to_bin(i, a->bin_size), 0);
}
prev = next + 1;
// add
if (a->bin_size) {
a->addGroup(to_bin(d, a->bin_size), c.second);
} else {
a->addGroup(c.first, c.second);
}
} else {
// non-numeric, add anyway
a->addGroup(c.first, c.second);
}
// add
a->addGroup(c.first, c.second);
}
a->mean /= numeric_count;
a->mean_value /= numeric_count;
} else if (a->order) {
// specific group order
FOR_EACH_CONST(gn, *a->order) {
@@ -145,34 +172,49 @@ GraphData::GraphData(const GraphDataPre& d)
++i;
}
// count elements in each position
values.clear();
values.reserve(d.elements.size());
size_t de_size = sizeof(GraphDataElement) + sizeof(int) * (axes.size() - 1);
FOR_EACH_CONST(e, d.elements) {
// make the group_nrs large enough
GraphDataElement* de = reinterpret_cast<GraphDataElement*>(new char[de_size]);
de->original_index = e->original_index;
// find index j in elements
vector<int> group_nrs(axes.size(), -1);
int i = 0;
FOR_EACH(a, axes) {
String v = e->values[i];
int j = 0;
FOR_EACH(g, a->groups) {
if (v == g.name) {
group_nrs[i] = j;
break;
de->group_nrs[i] = -1;
double d;
if (a->numeric && a->bin_size > 0 && v.ToDouble(&d)) {
// calculate group that contains v
de->group_nrs[i] = bin_to_group(d, a->bin_size);
} else {
// find group that contains v
int j = 0;
FOR_EACH(g, a->groups) {
if (v == g.name) {
de->group_nrs[i] = j;
break;
}
++j;
}
++j;
}
++i;
}
values.push_back(group_nrs);
values.push_back(de);
}
}
GraphData::~GraphData() {
FOR_EACH_CONST(v,values) delete v;
}
void GraphData::crossAxis(size_t axis1, size_t axis2, vector<UInt>& out) const {
size_t a1_size = axes[axis1]->groups.size();
size_t a2_size = axes[axis2]->groups.size();
out.clear();
out.resize(a1_size * a2_size, 0);
FOR_EACH_CONST(v, values) {
int v1 = v[axis1], v2 = v[axis2];
int v1 = v->group_nrs[axis1], v2 = v->group_nrs[axis2];
if (v1 >= 0 && v2 >= 0) {
out[a2_size * v1 + v2]++;
}
@@ -186,29 +228,46 @@ void GraphData::crossAxis(size_t axis1, size_t axis2, size_t axis3, vector<UInt>
out.clear();
out.resize(a1_size * a2_size * a3_size, 0);
FOR_EACH_CONST(v, values) {
int v1 = v[axis1], v2 = v[axis2], v3 = v[axis3];
int v1 = v->group_nrs[axis1], v2 = v->group_nrs[axis2], v3 = v->group_nrs[axis3];
if (v1 >= 0 && v2 >= 0 && v3 >= 0) {
out[a3_size * (a2_size * v1 + v2) + v3]++;
}
}
}
bool matches(const GraphDataElement* v, const vector<int>& match) {
for (size_t i = 0 ; i < match.size() ; ++i) {
if (v->group_nrs[i] == -1 || match[i] != -1 && v->group_nrs[i] != match[i]) {
return false;
}
}
return true;
}
UInt GraphData::count(const vector<int>& match) const {
if (match.size() != axes.size()) return 0;
UInt count = 0;
size_t prev_index = (size_t)-1;
FOR_EACH_CONST(v, values) {
bool matches = true;
for (size_t i = 0 ; i < match.size() ; ++i) {
if (v[i] == -1 || match[i] != -1 && v[i] != match[i]) {
matches = false;
break;
}
if (matches(v, match) && v->original_index != prev_index) {
prev_index = v->original_index; // don't count the same index twice
count += matches(v, match);
}
count += matches;
}
return count;
}
void GraphData::indices(const vector<int>& match, vector<size_t>& out) const {
if (match.size() != axes.size()) return;
size_t prev_index = (size_t)-1;
FOR_EACH_CONST(v, values) {
if (matches(v, match) && v->original_index != prev_index) {
prev_index = v->original_index; // don't select the same index twice
out.push_back(v->original_index);
}
}
}
// ----------------------------------------------------------------------------- : Graph1D
void Graph1D::draw(RotatedDC& dc, const vector<int>& current, DrawLayer layer) const {
@@ -620,8 +679,8 @@ void GraphStats::setData(const GraphDataP& d) {
values.clear();
if (!axis.numeric) return;
if (axis.groups.empty()) return;
values.push_back(make_pair(_("max"), axis.groups.back().name));
values.push_back(make_pair(_("mean"), String::Format(_("%.2f"), axis.mean)));
values.push_back(make_pair(_("max"), String::Format(_("%.2f"), axis.max_value)));
values.push_back(make_pair(_("mean"), String::Format(_("%.2f"), axis.mean_value)));
}
RealSize GraphStats::determineSize(RotatedDC& dc) const {
@@ -978,6 +1037,10 @@ void GraphControl::setData(const GraphDataP& data) {
}
Refresh(false);
}
GraphDataP GraphControl::getData() const {
if (graph) return graph->getData();
else return GraphDataP();
}
size_t GraphControl::getDimensionality() const {
if (graph) return graph->getData()->axes.size();
@@ -1067,6 +1130,9 @@ String GraphControl::getSelection(size_t axis) const {
if (i == -1 || (size_t)i >= a.groups.size()) return wxEmptyString;
return a.groups[current_item[axis]].name;
}
vector<int> GraphControl::getSelectionIndices() const {
return current_item;
}
void GraphControl::onMotion(wxMouseEvent& ev) {
if (!graph) return;
+25 -11
View File
@@ -52,13 +52,13 @@ enum AutoColor
/** The sum of groups.sum = sum of all elements in the data */
class GraphAxis : public IntrusivePtrBase<GraphAxis> {
public:
GraphAxis(const String& name, AutoColor auto_color = AUTO_COLOR_EVEN, bool numeric = false, const map<String,Color>* colors = nullptr, const vector<String>* order = nullptr)
GraphAxis(const String& name, AutoColor auto_color = AUTO_COLOR_EVEN, bool numeric = false, double bin_size = 0, const map<String,Color>* colors = nullptr, const vector<String>* order = nullptr)
: name(name)
, auto_color(auto_color)
, numeric(numeric)
, numeric(numeric), bin_size(bin_size)
, max(0)
, total(0)
, mean(0)
, mean_value(0), max_value(-numeric_limits<double>::infinity())
, colors(colors)
, order(order)
{}
@@ -67,9 +67,11 @@ class GraphAxis : public IntrusivePtrBase<GraphAxis> {
AutoColor auto_color; ///< Automatically assign colors to the groups on this axis
vector<GraphGroup> groups; ///< Groups along this axis
bool numeric; ///< Numeric axis?
double bin_size; ///< Group numeric values into bins of this size
UInt max; ///< Maximum size of the groups
UInt total; ///< Sum of the size of all groups
double mean; ///< Mean value, only for numeric axes
double mean_value; ///< Mean value, only for numeric axes
double max_value; ///< Maximal value, only for numeric axes
const map<String,Color>* colors; ///< Colors for each choice (optional)
const vector<String>* order; ///< Order of the items (optional)
@@ -80,11 +82,10 @@ class GraphAxis : public IntrusivePtrBase<GraphAxis> {
/// A single data point of a graph
class GraphElement : public IntrusivePtrBase<GraphElement> {
public:
GraphElement() {}
GraphElement(const String& v1);
GraphElement(const String& v1, const String& v2);
GraphElement(size_t original_index) : original_index(original_index) {}
vector<String> values; ///< Group name for each axis
size_t original_index; ///< Corresponding index in the original input
vector<String> values; ///< Group name for each axis
};
/// Data to be displayed in a graph, not processed yet
@@ -96,14 +97,21 @@ class GraphDataPre {
void splitList(size_t axis);
};
/// A single data point of a graph
struct GraphDataElement {
size_t original_index;
int group_nrs[1]; ///< Group number for each axis
};
/// Data to be displayed in a graph
class GraphData : public IntrusivePtrBase<GraphData> {
public:
GraphData(const GraphDataPre&);
~GraphData();
vector<GraphAxisP> axes; ///< The axes in the data
vector<vector<int> > values; ///< All elements, with the group number for each axis, or -1
UInt size; ///< Total number of elements
vector<GraphAxisP> axes; ///< The axes in the data
vector<GraphDataElement*> values; ///< All elements, with the group number for each axis, or -1
UInt size; ///< Total number of elements
/// Create a cross table for two axes
void crossAxis(size_t axis1, size_t axis2, vector<UInt>& out) const;
@@ -111,6 +119,8 @@ class GraphData : public IntrusivePtrBase<GraphData> {
void crossAxis(size_t axis1, size_t axis2, size_t axis3, vector<UInt>& out) const;
/// Count the number of elements with the given values, -1 is a wildcard
UInt count(const vector<int>& match) const;
/// Get the original_indices of elements matching the selection
void indices(const vector<int>& match, vector<size_t>& out) const;
};
@@ -333,11 +343,15 @@ class GraphControl : public wxControl {
void setData(const GraphDataPre& data);
/// Update the data in the graph
void setData(const GraphDataP& data);
/// Retrieve the data in the graph
GraphDataP getData() const;
/// Is there a selection on the given axis?
bool hasSelection(size_t axis) const;
/// Get the current item along the given axis
String getSelection(size_t axis) const;
/// Get the current item along each axis
vector<int> getSelectionIndices() const;
/// Get the current layout
GraphType getLayout() const;