1 #include <iostream>
2
3 #include <string>
4 #include <vector>
5 #include <cassert>
6 #include <fstream>
7 #include <sstream>
8 #include <algorithm>
9 #include <limits>
10 #include <cstdlib>
11 #include "graph.h"
12
13 struct GNUplotColor {
14 int M_color; // GNUplot color index.
15 int M_Red, M_Green, M_blue; // RGB value.
16 char const* M_name; // A human readable name for the color.
17 char M_c; // Corresponding symbol used by GNUplot (@ = square, 0 = diamond, ^ = triangle).
18 };
19
20 GNUplotColor const gnuplot_colors[] = {
21 { -1, 0, 0, 0, "black", ' ' },
22 { 0, 160, 160, 160, "gray", '.' },
23 { 1, 255, 0, 0, "red", '+' },
24 { 2, 0, 192, 0, "mid green", 'x' },
25 { 3, 0, 128, 255, "dark sky blue", '*' },
26 { 4, 192, 0, 255, "purple", '@' },
27 { 5, 0, 238, 238, "cyan", 'O' },
28 { 6, 192, 64, 0, "red brown", '^' },
29 { 7, 238, 238, 0, "dirty yellow", '+' },
30 { 8, 32, 32, 192, "dark blue", 'x' },
31 { 9, 255, 192, 32, "orange", '*' },
32 { 10, 0, 128, 64, "forest green", '@' },
33 { 11, 160, 128, 255, "light purple", 'O' },
34 { 12, 128, 64, 0, "brown", '^' },
35 { 13, 255, 128, 255, "pink", '+' },
36 { 14, 0, 192, 96, "blueish green", 'x' },
37 { 15, 0, 192, 192, "sky blue", '*' },
38 { 16, 0, 96, 128, "Delfts blue", '@' },
39 { 17, 192, 96, 128, "pink purple", '0' },
40 { 18, 0, 128, 0, "dark green", '^' },
41 { 19, 64, 255, 128, "bright light green", '+' },
42 { 20, 48, 96, 128, "grayish blue", 'x' },
43 { 21, 128, 96, 0, "light brown", '*' },
44 { 22, 64, 64, 64, "dark gray", '@' },
45 { 23, 64, 128, 0, "yellowish dark green", '0' },
46 { 24, 0, 0, 128, "navy blue", '^' },
47 { 25, 128, 96, 16, "light brown 2", '+' },
48 { 26, 128, 96, 96, "purple brown", 'x' },
49 { 27, 128, 96, 128, "brownish purple", '*' },
50 { 28, 0, 0, 192, "dark blue 2", '@' },
51 { 29, 0, 0, 255, "blue", '0' },
52 { 30, 0, 96, 0, "dark forest green", '^' },
53 { 31, 227, 176, 192, "light pink", '+' },
54 { 32, 64, 192, 128, "blue green", 'x' },
55 { 33, 96, 160, 192, "blue gray", '*' }
56 };
57
M_new_color(void)58 int Graph::M_new_color(void)
59 {
60 color_list_type::iterator iter;
61 do
62 {
63 for (iter = M_colors.begin(); iter != M_colors.end(); ++iter)
64 if (iter->get_color() == M_color_hint)
65 break;
66 ++M_color_hint;
67 }
68 while (iter != M_colors.end());
69 return M_color_hint - 1;
70 }
71
add_point(int x,int y,int column)72 bool Graph::add_point(int x, int y, int column)
73 {
74 color_list_type::iterator iter;
75 for (iter = M_colors.begin(); iter != M_colors.end(); ++iter)
76 if (column == iter->get_column())
77 {
78 M_data.push_back(DataPoint(x, y, iter));
79 return true;
80 }
81 return false;
82 }
83
add_point(int x,int y,std::string const & label,int color)84 int Graph::add_point(int x, int y, std::string const& label, int color)
85 {
86 int column = -1;
87 color_list_type::iterator iter;
88 if (color == -2)
89 {
90 for (iter = M_colors.begin(); iter != M_colors.end(); ++iter)
91 if (label == iter->get_label())
92 {
93 color = iter->get_color();
94 column = iter->get_column();
95 break;
96 }
97 }
98 else
99 {
100 for (iter = M_colors.begin(); iter != M_colors.end(); ++iter)
101 if (color == iter->get_color())
102 {
103 assert(iter->get_label() == label);
104 column = iter->get_column();
105 break;
106 }
107 }
108 if (iter == M_colors.end())
109 {
110 if (color == -2)
111 color = M_new_color();
112 column = M_next_column++;
113 iter = M_colors.insert(M_colors.end(), Color(color, column, label));
114 }
115 M_data.push_back(DataPoint(x, y, iter));
116 return column;
117 }
118
plot(void)119 void Graph::plot(void)
120 {
121 int total = 0;
122 int min_x = std::numeric_limits<int>::max();
123 int max_x = std::numeric_limits<int>::min();
124 int min_y = std::numeric_limits<int>::max();
125 int max_y = std::numeric_limits<int>::min();
126
127 for (std::vector<DataPoint>::const_iterator iter = M_data.begin(); iter != M_data.end() ; ++iter)
128 {
129 int x = iter->get_x();
130 int y = iter->get_y();
131 if (x > max_x)
132 max_x = x;
133 if (x < min_x)
134 min_x = x;
135 if (y > max_y)
136 max_y = y;
137 if (y < min_y)
138 min_y = y;
139 total += y;
140 }
141
142 std::ofstream f;
143
144 std::ostringstream plot_filename;
145 plot_filename << "plot" << M_basename << ".dat";
146 f.open(plot_filename.str().c_str());
147
148 f << "set terminal png small color picsize 500 400\n"
149 "set output \"" << "data" << M_basename << ".png\"\n"
150 "set style fill solid 1 border -1\n"
151 "set grid ytics mytics back linetype -1 linewidth 0.8, linetype 2 linewidth 0.25\n"
152 "set title \"" << M_title << "\"\n"
153 "set boxwidth 1 absolute\n"
154 "set xlabel \"Number of points on the curve\"\n"
155 "set ylabel \"Number of curves\"\n"
156 "set xrange [ " << min_x - 0.5 << " : " << max_x + 0.5 << " ]\n";
157
158 int xrange = max_x - min_x + 1;
159 int yrange = (int)((max_y + 1) * 1.1);
160 int xtics = 1;
161 int ms = 20; // m < 7 ? 20 : 10;
162 while (xrange / xtics > ms)
163 xtics <<= 1;
164
165 f << "set yrange [ 0 : " << yrange << " ]\n"
166 "set label 12 \"Total number of curves: " << total << "\" at " <<
167 ((min_x - 0.5) + 0.03 * xrange) << ", " << (0.97 * yrange) << " front nopoint tc lt -1\n"
168 "set xtics " << xtics << "\n";
169 if (xtics > 1)
170 f << "set mxtics " << std::min(xtics, 4) << "\n";
171
172 #if 0
173 f << "set ytics " << m << "\n"
174 "set mytics " << m << "\n";
175 #endif
176
177 f << "plot \\\n";
178 for (int column = 0; column < (int)M_colors.size(); ++column)
179 {
180 for (color_list_type::const_iterator color = M_colors.begin(); color != M_colors.end(); ++color)
181 if (color->get_column() == column)
182 {
183 f << " \"data" << M_basename << ".dat\" using 1:" << (column + 2) <<
184 " title \"" << color->get_label() << "\" with boxes lt " << color->get_color();
185 if (column != (int)M_colors.size() - 1)
186 f << ", \\";
187 f << '\n';
188 }
189 }
190 f.close();
191
192 std::ostringstream data_filename;
193 data_filename << "data" << M_basename << ".dat";
194 f.open(data_filename.str().c_str());
195
196 std::sort(M_data.begin(), M_data.end());
197 int prev_x_init = M_data[0].get_x() - 1;
198 int prev_x = prev_x_init;
199 int prev_column = -1;
200 int max_column = M_colors.size();
201 int y_offset = 0; // Initialized to avoid compiler warning.
202 for (std::vector<DataPoint>::const_iterator iter = M_data.begin(); iter != M_data.end() ; ++iter)
203 {
204 #if 0
205 std::cout << "Processing: x = " << iter->get_x() << "; y = " << iter->get_y() <<
206 "; column = " << iter->get_color().get_column() << "; color = " << iter->get_color().get_color() << std::endl;
207 #endif
208 int x = iter->get_x();
209 if (x != prev_x)
210 {
211 if (prev_x != prev_x_init)
212 {
213 for (int i = 1; i < max_column - prev_column; ++i)
214 f << " ?";
215 f << '\n';
216 }
217 f << x;
218 prev_x = x;
219 prev_column = -1;
220 y_offset = 0;
221 for (std::vector<DataPoint>::const_iterator iter2 = iter; iter2 != M_data.end() ; ++iter2)
222 if (iter2->get_x() == x)
223 y_offset += iter2->get_y();
224 else
225 break;
226 }
227 int column = iter->get_color().get_column();
228 assert(column - prev_column >= 1); // The same x coordinate but the same columns?!
229 for (int i = 1; i < column - prev_column; ++i)
230 f << " ?";
231 prev_column = column;
232 f << " " << y_offset;
233 y_offset -= iter->get_y();
234 }
235
236 f.close();
237 }
238
swap_columns(int col1,int col2)239 void Graph::swap_columns(int col1, int col2)
240 {
241 if (col1 == col2)
242 return;
243 for (color_list_type::iterator iter1 = M_colors.begin(); iter1 != M_colors.end(); ++iter1)
244 if (iter1->get_column() == col1 || iter1->get_column() == col2)
245 {
246 color_list_type::iterator iter2 = iter1;
247 for (++iter2; iter2 != M_colors.end(); ++iter2)
248 if (iter2->get_column() == col1 || iter2->get_column() == col2)
249 {
250 iter1->swap_column_with(*iter2);
251 return;
252 }
253 }
254 }
255