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