Commit 5754b81d authored by twanvl's avatar twanvl

Scatter plots

parent 9787240c
...@@ -112,10 +112,13 @@ help: ...@@ -112,10 +112,13 @@ help:
redo: Redoes the last action redo: Redoes the last action
cut: Move the selected text to the clipboard cut: Move the selected text to the clipboard
cut card: Move the selected card to the clipboard cut card: Move the selected card to the clipboard
cut keyword: Move the selected keyword to the clipboard
copy: Place the selected text on the clipboard copy: Place the selected text on the clipboard
copy card: Place the selected card on the clipboard copy card: Place the selected card on the clipboard
copy keyword: Place the selected keyword on the clipboard
paste: Inserts the text from the clipboard paste: Inserts the text from the clipboard
paste card: Inserts the card from the clipboard paste card: Inserts the card from the clipboard
paste keyword: Inserts the keyword from the clipboard
preferences: Change the configuration of Magic Set Editor preferences: Change the configuration of Magic Set Editor
cards: cards:
...@@ -273,6 +276,7 @@ tooltip: ...@@ -273,6 +276,7 @@ tooltip:
new set: New set new set: New set
open set: Open set open set: Open set
save set: Save set save set: Save set
export: Export set
cut: Cut cut: Cut
copy: Copy copy: Copy
......
...@@ -176,6 +176,7 @@ choice colors: ...@@ -176,6 +176,7 @@ choice colors:
artifact : rgb(188,192,195) artifact : rgb(188,192,195)
multicolor : rgb(255,188,14) multicolor : rgb(255,188,14)
land : rgb(109,62,39) land : rgb(109,62,39)
hybrid : rgb(243,26,136) # purple
# Sub menus, same colors # Sub menus, same colors
multicolor 2 color white / blue : rgb(255,188,14) multicolor 2 color white / blue : rgb(255,188,14)
multicolor 2 color blue / black : rgb(255,188,14) multicolor 2 color blue / black : rgb(255,188,14)
......
...@@ -971,31 +971,31 @@ card field: ...@@ -971,31 +971,31 @@ card field:
############################################################## Statistics categories ############################################################## Statistics categories
statistics dimension: #statistics dimension:
name: card color2 # name: card color2
script: primary_card_color(card.card_color) # script: primary_card_color(card.card_color)
icon: stats/card_color.png # icon: stats/card_color.png
colors: # colors:
white : rgb(255,237,202) # white : rgb(255,237,202)
blue : rgb(42,141,255) # blue : rgb(42,141,255)
black : rgb(33,33,33) # black : rgb(33,33,33)
red : rgb(255,52,0) # red : rgb(255,52,0)
green : rgb(138,230,0) # green : rgb(138,230,0)
colorless : rgb(122,85,85) # colorless : rgb(122,85,85)
artifact : rgb(188,192,195) # artifact : rgb(188,192,195)
multicolor : rgb(255,188,14) # multicolor : rgb(255,188,14)
land : rgb(109,62,39) # land : rgb(109,62,39)
hybrid : rgb(243,26,136) # hybrid : rgb(243,26,136)
group: white # group: white
group: blue # group: blue
group: black # group: black
group: red # group: red
group: green # group: green
group: colorless # group: colorless
group: artifact # group: artifact
group: multicolor # group: multicolor
group: land # group: land
group: hybrid # group: hybrid
statistics dimension: statistics dimension:
name: converted mana cost name: converted mana cost
...@@ -1010,11 +1010,16 @@ statistics dimension: ...@@ -1010,11 +1010,16 @@ statistics dimension:
icon: stats/colored_casting_cost.png icon: stats/colored_casting_cost.png
#statistics dimension: #statistics dimension:
# name: power2 # name: p/t
# script: card.power # script: card.pt
# numeric: true # numeric: true
# icon: stats/power.png # icon: stats/power.png
#statistics dimension:
# name: word count
# type: word count
# display: list
#statistics dimension: #statistics dimension:
# name: toughness2 # name: toughness2
# script: card.toughness # script: card.toughness
...@@ -1024,14 +1029,20 @@ statistics dimension: ...@@ -1024,14 +1029,20 @@ statistics dimension:
statistics category: statistics category:
name: color / rarity name: color / rarity
type: stack type: stack
dimension: card color2 dimension: card color
dimension: rarity dimension: rarity
#statistics category: statistics category:
# name: power / toughness name: power / toughness
# type: scatter type: scatter
# dimension: power2 dimension: power
# dimension: toughness2 dimension: toughness
statistics category:
name: color / cost
type: scatter
dimension: card color
dimension: converted mana cost
#statistics field: #statistics field:
# name: creature type # name: creature type
......
...@@ -18,6 +18,7 @@ DECLARE_TYPEOF_COLLECTION(GraphP); ...@@ -18,6 +18,7 @@ DECLARE_TYPEOF_COLLECTION(GraphP);
DECLARE_TYPEOF_COLLECTION(int); DECLARE_TYPEOF_COLLECTION(int);
DECLARE_TYPEOF_COLLECTION(vector<int>); DECLARE_TYPEOF_COLLECTION(vector<int>);
DECLARE_TYPEOF_COLLECTION(String); DECLARE_TYPEOF_COLLECTION(String);
DECLARE_TYPEOF_COLLECTION(UInt);
DECLARE_TYPEOF(map<String COMMA UInt>); DECLARE_TYPEOF(map<String COMMA UInt>);
template <typename T> inline T sgn(T v) { return v < 0 ? -1 : 1; } template <typename T> inline T sgn(T v) { return v < 0 ? -1 : 1; }
...@@ -200,7 +201,7 @@ int find_bar_graph_column(double width, double x, int count) { ...@@ -200,7 +201,7 @@ int find_bar_graph_column(double width, double x, int count) {
double width_space = width / count; // including spacing double width_space = width / count; // including spacing
double space = width_space / 5; double space = width_space / 5;
// Find column in which the point could be located // Find column in which the point could be located
int col = int(x / width_space); int col = floor(x / width_space);
if (col < 0 || col >= count) return -1; // not a column if (col < 0 || col >= count) return -1; // not a column
double in_col = x - col * width_space; double in_col = x - col * width_space;
if (in_col < space / 2) return -1; // left if (in_col < space / 2) return -1; // left
...@@ -254,14 +255,14 @@ void BarGraph2D::draw(RotatedDC& dc, const vector<int>& current, DrawLayer layer ...@@ -254,14 +255,14 @@ void BarGraph2D::draw(RotatedDC& dc, const vector<int>& current, DrawLayer layer
GraphAxis& axis1 = axis1_data(); // the major axis GraphAxis& axis1 = axis1_data(); // the major axis
GraphAxis& axis2 = axis2_data(); // the stacked axis GraphAxis& axis2 = axis2_data(); // the stacked axis
int count = int(axis1.groups.size()); int count = int(axis1.groups.size());
// Bar sizes // Draw
if (layer == LAYER_SELECTION) { if (layer == LAYER_SELECTION) {
// Highlight current column // Highlight current column
Color bg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); Color bg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
int cur1 = this->axis1 < current.size() ? current[this->axis1] : -1; int cur1 = this->axis1 < current.size() ? current[this->axis1] : -1;
int cur2 = this->axis2 < current.size() ? current[this->axis2] : -1; int cur2 = this->axis2 < current.size() ? current[this->axis2] : -1;
if (cur1 >= 0) { if (cur1 >= 0) {
// draw that bar // draw selected bar
int start = 0; int start = 0;
int j = 0; int j = 0;
FOR_EACH_CONST(g2, axis2.groups) { FOR_EACH_CONST(g2, axis2.groups) {
...@@ -278,8 +279,8 @@ void BarGraph2D::draw(RotatedDC& dc, const vector<int>& current, DrawLayer layer ...@@ -278,8 +279,8 @@ void BarGraph2D::draw(RotatedDC& dc, const vector<int>& current, DrawLayer layer
} }
} else if (cur2 >= 0) { } else if (cur2 >= 0) {
// entire row // entire row
}
// TODO // TODO
}
} else if (layer == LAYER_VALUES) { } else if (layer == LAYER_VALUES) {
// Draw bars // Draw bars
dc.SetPen(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); dc.SetPen(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
...@@ -396,6 +397,72 @@ int PieGraph::findItem(const RealPoint& pos, const RealRect& rect) const { ...@@ -396,6 +397,72 @@ int PieGraph::findItem(const RealPoint& pos, const RealRect& rect) const {
// ----------------------------------------------------------------------------- : Scatter Plot // ----------------------------------------------------------------------------- : Scatter Plot
void ScatterGraph::draw(RotatedDC& dc, const vector<int>& current, DrawLayer layer) const {
if (!data || data->axes.size() <= max(axis1,axis2)) return;
// Rectangle for bars
RealRect rect = dc.getInternalRect();
GraphAxis& axis1 = axis1_data(); // the major axis
GraphAxis& axis2 = axis2_data(); // the stacked axis
RealSize size(rect.width / axis1.groups.size(), rect.height / axis2.groups.size()); // size for a single cell
double step = min(size.width, size.height) / sqrt((double)max_value) / 2.01;
// Draw
dc.SetPen(*wxTRANSPARENT_PEN);
if (layer == LAYER_SELECTION) {
Color bg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
int cur1 = this->axis1 < current.size() ? current[this->axis1] : -1;
int cur2 = this->axis2 < current.size() ? current[this->axis2] : -1;
if (cur1 >= 0 && cur2 >= 0) {
UInt value = values[cur1 * axis2.groups.size() + cur2];
if (value) {
dc.SetBrush(lerp(bg,lerp(axis1.groups[cur1].color, axis2.groups[cur2].color, 0.5),0.5));
dc.DrawCircle(RealPoint(rect.left() + cur1 * size.width, rect.bottom() - (cur2+1) * size.height) + size/2, sqrt((double)value) * step + 5);
}
} else if (cur1 >= 0) {
dc.SetBrush(lerp(bg,axis1.groups[cur1].color,0.3));
dc.DrawRectangle(RealRect(rect.x + cur1 * size.width, rect.y, size.width, rect.height));
} else if (cur2 >= 0) {
dc.SetBrush(lerp(bg,axis2.groups[cur2].color,0.3));
dc.DrawRectangle(RealRect(rect.x, rect.bottom() - (cur2+1) * size.height, rect.width, size.height));
}
} else {
size_t i = 0;
double x = rect.left();
FOR_EACH_CONST(g1, axis1.groups) {
double y = rect.bottom() - size.height;
FOR_EACH_CONST(g2, axis2.groups) {
UInt value = values[i++];
dc.SetBrush(lerp(g1.color, g2.color, 0.5));
dc.DrawCircle(RealPoint(x,y) + size/2, sqrt((double)value) * step);
y -= size.height;
}
x += size.width;
}
}
}
bool ScatterGraph::findItem(const RealPoint& pos, const RealRect& rect, vector<int>& out) const {
if (!data || data->axes.size() <= max(axis1,axis2)) return false;
// clicked item
GraphAxis& axis1 = axis1_data();
GraphAxis& axis2 = axis2_data();
int col = floor((pos.x - rect.x) / rect.width * axis1.groups.size());
int row = floor((rect.bottom() - pos.y) / rect.height * axis2.groups.size());
if (col < 0 || col >= (int)axis1.groups.size()) return false;
if (row < 0 || row >= (int)axis2.groups.size()) return false;
// done
out.clear();
out.insert(out.begin(), data->axes.size(), -1);
out.at(this->axis1) = col;
out.at(this->axis2) = row;
return true;
}
void ScatterGraph::setData(const GraphDataP& d) {
Graph2D::setData(d);
// find maximum
max_value = 0;
FOR_EACH(v, values) {
max_value = max(max_value, v);
}
}
// ----------------------------------------------------------------------------- : Graph Legend // ----------------------------------------------------------------------------- : Graph Legend
...@@ -407,6 +474,7 @@ void GraphLabelAxis::draw(RotatedDC& dc, int current, DrawLayer layer) const { ...@@ -407,6 +474,7 @@ void GraphLabelAxis::draw(RotatedDC& dc, int current, DrawLayer layer) const {
GraphAxis& axis = axis_data(); GraphAxis& axis = axis_data();
int count = int(axis.groups.size()); int count = int(axis.groups.size());
// Draw // Draw
dc.SetFont(*wxNORMAL_FONT);
if (layer == LAYER_SELECTION) { if (layer == LAYER_SELECTION) {
// highlight selection // highlight selection
} else if (layer != LAYER_AXES) { } else if (layer != LAYER_AXES) {
...@@ -427,15 +495,18 @@ void GraphLabelAxis::draw(RotatedDC& dc, int current, DrawLayer layer) const { ...@@ -427,15 +495,18 @@ void GraphLabelAxis::draw(RotatedDC& dc, int current, DrawLayer layer) const {
Color fg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); Color fg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
if (draw_lines) { if (draw_lines) {
dc.SetPen(lerp(bg, fg, 0.5)); dc.SetPen(lerp(bg, fg, 0.5));
for (int i = 1 ; i <= count ; ++i) { for (int i = 0 ; i < count ; ++i) {
dc.DrawLine(RealPoint(rect.x + i*width, rect.top()), RealPoint(rect.x + i*width, rect.bottom())); if (draw_lines == DRAW_LINES_BETWEEN) {
dc.DrawLine(RealPoint(rect.x + (i+1.0)*width, rect.top()), RealPoint(rect.x + (i+1.0)*width, rect.bottom()));
} else {
dc.DrawLine(RealPoint(rect.x + (i+0.5)*width, rect.top()), RealPoint(rect.x + (i+0.5)*width, rect.bottom() + 2));
}
} }
} }
// always draw axis line // always draw axis line
dc.SetPen(fg); dc.SetPen(fg);
dc.DrawLine(rect.topLeft(), rect.bottomLeft()); dc.DrawLine(rect.topLeft(), rect.bottomLeft());
} else { } else {
// TODO
double height = rect.height / count; // width of an item double height = rect.height / count; // width of an item
// Draw labels // Draw labels
double y = rect.bottom(); double y = rect.bottom();
...@@ -443,7 +514,7 @@ void GraphLabelAxis::draw(RotatedDC& dc, int current, DrawLayer layer) const { ...@@ -443,7 +514,7 @@ void GraphLabelAxis::draw(RotatedDC& dc, int current, DrawLayer layer) const {
// draw label, aligned bottom center // draw label, aligned bottom center
RealSize text_size = dc.GetTextExtent(g.name); RealSize text_size = dc.GetTextExtent(g.name);
//dc.SetClippingRegion(RealRect(x + 2, rect.bottom() + 3, width - 4, text_size.height)); //dc.SetClippingRegion(RealRect(x + 2, rect.bottom() + 3, width - 4, text_size.height));
dc.DrawText(g.name, align_in_rect(ALIGN_MIDDLE_RIGHT, text_size, RealRect(-3, y, 0, -height))); dc.DrawText(g.name, align_in_rect(ALIGN_MIDDLE_RIGHT, text_size, RealRect(-4, y, 0, -height)));
//dc.DestroyClippingRegion(); //dc.DestroyClippingRegion();
y -= height; y -= height;
} }
...@@ -452,8 +523,12 @@ void GraphLabelAxis::draw(RotatedDC& dc, int current, DrawLayer layer) const { ...@@ -452,8 +523,12 @@ void GraphLabelAxis::draw(RotatedDC& dc, int current, DrawLayer layer) const {
Color fg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); Color fg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
if (draw_lines) { if (draw_lines) {
dc.SetPen(lerp(bg, fg, 0.5)); dc.SetPen(lerp(bg, fg, 0.5));
for (int i = 1 ; i <= count ; ++i) { for (int i = 0 ; i < count ; ++i) {
dc.DrawLine(RealPoint(rect.left(), rect.bottom() - i*height), RealPoint(rect.right(), rect.bottom() - i*height)); if (draw_lines == DRAW_LINES_BETWEEN) {
dc.DrawLine(RealPoint(rect.left(), rect.bottom() - (i+1.0)*height), RealPoint(rect.right(), rect.bottom() - (i+1.0)*height));
} else {
dc.DrawLine(RealPoint(rect.left() - 2, rect.bottom() - (i+0.5)*height), RealPoint(rect.right(), rect.bottom() - (i+0.5)*height));
}
} }
} }
// always draw axis line // always draw axis line
...@@ -466,10 +541,10 @@ int GraphLabelAxis::findItem(const RealPoint& pos, const RealRect& rect) const { ...@@ -466,10 +541,10 @@ int GraphLabelAxis::findItem(const RealPoint& pos, const RealRect& rect) const {
GraphAxis& axis = axis_data(); GraphAxis& axis = axis_data();
int col; int col;
if (direction == HORIZONTAL) { if (direction == HORIZONTAL) {
col = (pos.x - rect.x) / rect.width * axis.groups.size(); col = floor((pos.x - rect.x) / rect.width * axis.groups.size());
if (pos.y < rect.bottom()) return -1; if (pos.y < rect.bottom()) return -1;
} else { } else {
col = (pos.y - rect.y) / rect.height * axis.groups.size(); col = floor((rect.bottom() - pos.y) / rect.height * axis.groups.size());
if (pos.x > rect.left()) return -1; if (pos.x > rect.left()) return -1;
} }
if (col < 0 || col >= (int)axis.groups.size()) return -1; if (col < 0 || col >= (int)axis.groups.size()) return -1;
...@@ -582,12 +657,11 @@ void GraphControl::setLayout(GraphType type) { ...@@ -582,12 +657,11 @@ void GraphControl::setLayout(GraphType type) {
graph = new_intrusive5<GraphWithMargins>(combined, 23,8,7,20); graph = new_intrusive5<GraphWithMargins>(combined, 23,8,7,20);
break; break;
} case GRAPH_TYPE_SCATTER: { } case GRAPH_TYPE_SCATTER: {
// TODO
intrusive_ptr<GraphContainer> combined(new GraphContainer()); intrusive_ptr<GraphContainer> combined(new GraphContainer());
combined->add(new_intrusive4<GraphLabelAxis>(0, HORIZONTAL, false, true)); combined->add(new_intrusive4<GraphLabelAxis>(0, HORIZONTAL, false, DRAW_LINES_MID));
combined->add(new_intrusive4<GraphLabelAxis>(1, VERTICAL, false, true)); combined->add(new_intrusive4<GraphLabelAxis>(1, VERTICAL, false, DRAW_LINES_MID));
//combined->add(new_intrusive2<BarGraph2D>(0,1)); combined->add(new_intrusive2<ScatterGraph>(0,1));
graph = new_intrusive5<GraphWithMargins>(combined, 23,8,7,20); graph = new_intrusive5<GraphWithMargins>(combined, 80,8,7,20);
break; break;
} default: } default:
graph = GraphP(); graph = GraphP();
......
...@@ -181,6 +181,17 @@ class PieGraph : public Graph1D { ...@@ -181,6 +181,17 @@ class PieGraph : public Graph1D {
virtual int findItem(const RealPoint& pos, const RealRect& rect) const; virtual int findItem(const RealPoint& pos, const RealRect& rect) const;
}; };
/// A scatter plot
class ScatterGraph : public Graph2D {
public:
inline ScatterGraph(size_t axis1, size_t axis2) : Graph2D(axis1, axis2) {}
virtual void draw(RotatedDC& dc, const vector<int>& current, DrawLayer layer) const;
virtual bool findItem(const RealPoint& pos, const RealRect& rect, vector<int>& out) const;
virtual void setData(const GraphDataP& d);
private:
UInt max_value; ///< highest value
};
/// The legend, used for pie graphs /// The legend, used for pie graphs
class GraphLegend : public Graph1D { class GraphLegend : public Graph1D {
public: public:
...@@ -192,11 +203,17 @@ class GraphLegend : public Graph1D { ...@@ -192,11 +203,17 @@ class GraphLegend : public Graph1D {
//class GraphTable { //class GraphTable {
//}; //};
enum DrawLines
{ DRAW_LINES_NO
, DRAW_LINES_BETWEEN
, DRAW_LINES_MID
};
/// Draws a horizontal/vertical axis for group labels /// Draws a horizontal/vertical axis for group labels
class GraphLabelAxis : public Graph1D { class GraphLabelAxis : public Graph1D {
public: public:
inline GraphLabelAxis(size_t axis, Direction direction, bool rotate = false, bool draw_lines = false) inline GraphLabelAxis(size_t axis, Direction direction, bool rotate = false, DrawLines draw_lines = DRAW_LINES_NO, bool label = false)
: Graph1D(axis), direction(direction), rotate(rotate), draw_lines(draw_lines) : Graph1D(axis), direction(direction), rotate(rotate), draw_lines(draw_lines), label(label)
{} {}
virtual void draw(RotatedDC& dc, int current, DrawLayer layer) const; virtual void draw(RotatedDC& dc, int current, DrawLayer layer) const;
virtual int findItem(const RealPoint& pos, const RealRect& rect) const; virtual int findItem(const RealPoint& pos, const RealRect& rect) const;
...@@ -204,7 +221,8 @@ class GraphLabelAxis : public Graph1D { ...@@ -204,7 +221,8 @@ class GraphLabelAxis : public Graph1D {
Direction direction; Direction direction;
int levels; int levels;
bool rotate; bool rotate;
bool draw_lines; DrawLines draw_lines;
bool label;
}; };
/// Draws an a vertical axis for counts /// Draws an a vertical axis for counts
......
...@@ -172,6 +172,11 @@ void RotatedDC::DrawRoundedRectangle(const RealRect& r, double radius) { ...@@ -172,6 +172,11 @@ void RotatedDC::DrawRoundedRectangle(const RealRect& r, double radius) {
dc.DrawRoundedRectangle(r_ext.x, r_ext.y, r_ext.width, r_ext.height, trS(radius)); dc.DrawRoundedRectangle(r_ext.x, r_ext.y, r_ext.width, r_ext.height, trS(radius));
} }
void RotatedDC::DrawCircle(const RealPoint& center, double radius) {
wxPoint p = tr(center);
dc.DrawCircle(p.x + 1, p.y + 1, trS(radius));
}
/// Convert radians to degrees /// Convert radians to degrees
double rad_to_deg(double rad) { return rad * (180.0 / M_PI); } double rad_to_deg(double rad) { return rad * (180.0 / M_PI); }
/// Convert degrees to radians /// Convert degrees to radians
......
...@@ -146,6 +146,7 @@ class RotatedDC : public Rotation { ...@@ -146,6 +146,7 @@ class RotatedDC : public Rotation {
void DrawLine (const RealPoint& p1, const RealPoint& p2); void DrawLine (const RealPoint& p1, const RealPoint& p2);
void DrawRectangle(const RealRect& r); void DrawRectangle(const RealRect& r);
void DrawRoundedRectangle(const RealRect& r, double radius); void DrawRoundedRectangle(const RealRect& r, double radius);
void DrawCircle(const RealPoint& center, double radius);
/// Draw an arc of an ellipse, angles are in radians /// Draw an arc of an ellipse, angles are in radians
void DrawEllipticArc(const RealPoint& center, const RealSize& size, double start, double end); void DrawEllipticArc(const RealPoint& center, const RealSize& size, double start, double end);
/// Draw spokes of an ellipse /// Draw spokes of an ellipse
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment