A toolkit for working with phylogenetic data.
v0.20.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
helpers.cpp
Go to the documentation of this file.
1 /*
2  Genesis - A toolkit for working with phylogenetic data.
3  Copyright (C) 2014-2018 Lucas Czech and HITS gGmbH
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  Contact:
19  Lucas Czech <lucas.czech@h-its.org>
20  Exelixis Lab, Heidelberg Institute for Theoretical Studies
21  Schloss-Wolfsbrunnenweg 35, D-69118 Heidelberg, Germany
22 */
23 
32 
41 
42 #include <cassert>
43 #include <stdexcept>
44 
45 namespace genesis {
46 namespace utils {
47 
48 // =================================================================================================
49 // Gradients
50 // =================================================================================================
51 
52 std::map<double, Color> color_stops( ColorMap const& map, ColorNormalization const& norm )
53 {
54  // Super duper ugly code.
55  // Need to do linear last, because the other two are derived from it.
56 
57  auto norm_log = dynamic_cast<ColorNormalizationLogarithmic const*>( &norm );
58  if( norm_log ) {
59  return color_stops( map, *norm_log );
60  }
61  auto norm_div = dynamic_cast<ColorNormalizationDiverging const*>( &norm );
62  if( norm_div ) {
63  return color_stops( map, *norm_div );
64  }
65  auto norm_bnd = dynamic_cast<ColorNormalizationBoundary const*>( &norm );
66  if( norm_bnd ) {
67  return color_stops( map, *norm_bnd );
68  }
69  auto norm_lin = dynamic_cast<ColorNormalizationLinear const*>( &norm );
70  if( norm_lin ) {
71  return color_stops( map, *norm_lin );
72  }
73 
74  return {};
75 }
76 
77 std::map<double, Color> color_stops( ColorMap const& map, ColorNormalizationLinear const& norm )
78 {
79  (void) norm;
80  std::map<double, Color> result;
81  for( size_t i = 0; i < map.size(); ++i ) {
82  auto const offset = static_cast<double>( i ) / static_cast<double>( map.size() - 1 );
83  result[ offset ] = map.color( i );
84  }
85  return result;
86 }
87 
88 std::map<double, Color> color_stops( ColorMap const& map, ColorNormalizationLogarithmic const& norm )
89 {
90  return color_stops( map, dynamic_cast<ColorNormalizationLinear const&>( norm ));
91 }
92 
93 std::map<double, Color> color_stops( ColorMap const& map, ColorNormalizationDiverging const& norm )
94 {
95  std::map<double, Color> result;
96 
97  // Get the fractions of the lower and upper half,
98  // which are needed to scale the colors in a diverging palette correctly.
99  // For example, a palette with 5, 15, 20 for min, mid and max gets
100  // fractions 2/3 and 1/3 here.
101  auto const frac_lower = ( norm.mid_value() - norm.min_value() ) / ( norm.max_value() - norm.min_value() );
102  auto const frac_upper = ( norm.max_value() - norm.mid_value() ) / ( norm.max_value() - norm.min_value() );
103 
104  // Divide the palette in two, so that the mixed mid color counts as half a step
105  // in palettes with even number of colors.
106  auto const scale = 2.0 / static_cast<double>( map.size() - 1 );
107 
108  // Lower half.
109  for( size_t i = 0; i < map.size() / 2; ++i ) {
110  auto const offset = scale * frac_lower * static_cast<double>( i );
111  result[ offset ] = map.color( i );
112  }
113 
114  // For an even number of colors, we need to add a mixed middle color.
115  if( map.size() % 2 == 0 ) {
116  auto const mid_idx = map.size() / 2;
117  auto const mid_color = interpolate(
118  map.color( mid_idx - 1 ), map.color( mid_idx ), 0.5
119  );
120  result[ frac_lower ] = mid_color;
121  }
122 
123  // Upper half, including mid if uneven number of colors.
124  for( size_t i = map.size() / 2; i < map.size(); ++i ) {
125 
126  // Step away from end: We go backwards.
127  auto const step = static_cast<double>( map.size() - i - 1 );
128 
129  // Offset, as before, just going backwards again, so that we end up in right order.
130  auto const offset = 1.0 - ( scale * frac_upper * step );
131  result[ offset ] = map.color( i );
132  }
133 
134  return result;
135 }
136 
137 std::map<double, Color> color_stops( ColorMap const& map, ColorNormalizationBoundary const& norm )
138 {
139  std::map<double, Color> result;
140 
141  // Get range.
142  auto const min = norm.boundaries().front();
143  auto const max = norm.boundaries().back();
144  auto const len = max - min;
145 
146  for( auto const& bound : norm.boundaries() ) {
147  result[ ( bound - min ) / len ] = map( norm, bound );
148  }
149  return result;
150 }
151 
152 // =================================================================================================
153 // Tickmarks
154 // =================================================================================================
155 
156 std::map<double, std::string> color_tickmarks( ColorNormalization const& norm, size_t num_ticks )
157 {
158  // Super duper ugly code.
159  // Need to do linear last, because the other two are derived from it.
160 
161  auto norm_log = dynamic_cast<ColorNormalizationLogarithmic const*>( &norm );
162  if( norm_log ) {
163  return color_tickmarks( *norm_log, num_ticks );
164  }
165  auto norm_div = dynamic_cast<ColorNormalizationDiverging const*>( &norm );
166  if( norm_div ) {
167  return color_tickmarks( *norm_div, num_ticks );
168  }
169  auto norm_bnd = dynamic_cast<ColorNormalizationBoundary const*>( &norm );
170  if( norm_bnd ) {
171  return color_tickmarks( *norm_bnd, num_ticks );
172  }
173  auto norm_lin = dynamic_cast<ColorNormalizationLinear const*>( &norm );
174  if( norm_lin ) {
175  return color_tickmarks( *norm_lin, num_ticks );
176  }
177 
178  return {};
179 }
180 
181 std::map<double, std::string> color_tickmarks( ColorNormalizationLinear const& norm, size_t num_ticks )
182 {
183  std::map<double, std::string> result;
184  auto tm = Tickmarks();
185  auto const tm_labels = tm.linear_labels( norm.min_value(), norm.max_value(), num_ticks );
186  for( auto const& tm_label : tm_labels ) {
187  result[ tm_label.relative_position ] = utils::to_string( tm_label.label );
188  }
189  return result;
190 }
191 
192 std::map<double, std::string> color_tickmarks( ColorNormalizationLogarithmic const& norm, size_t num_ticks )
193 {
194  std::map<double, std::string> result;
195 
196  // Don't use them for log scale.
197  (void) num_ticks;
198 
199  auto tm = Tickmarks();
200  auto const tm_labels_u = tm.logarithmic_labels( norm.min_value(), norm.max_value(), norm.base() );
201  for( auto const& tm_label : tm_labels_u ) {
202  auto label = ( norm.exponential_labels()
203  ? utils::to_string( norm.base() ) + "^" + utils::to_string(
204  std::log( tm_label.label ) / std::log( norm.base() )
205  )
206  : utils::to_string( tm_label.label )
207  );
208  result[ tm_label.relative_position ] = label;
209  }
210 
211  return result;
212 }
213 
214 std::map<double, std::string> color_tickmarks( ColorNormalizationDiverging const& norm, size_t num_ticks )
215 {
216  std::map<double, std::string> result;
217  auto tm = Tickmarks();
218 
219  // Get the fractions of the lower and upper half,
220  // which are needed to scale the colors in a diverging palette correctly.
221  // For example, a palette with 5, 15, 20 for min, mid and max gets
222  // fractions 2/3 and 1/3 here.
223  auto const frac_lower = ( norm.mid_value() - norm.min_value() ) / ( norm.max_value() - norm.min_value() );
224  auto const frac_upper = ( norm.max_value() - norm.mid_value() ) / ( norm.max_value() - norm.min_value() );
225 
226  // Lower half.
227  tm.include_max = false;
228  auto const tm_labels_l = tm.linear_labels(
229  norm.min_value(), norm.mid_value(), frac_lower * num_ticks
230  );
231  for( auto const& tm_label : tm_labels_l ) {
232  auto const pos = frac_lower * tm_label.relative_position;
233  result[ pos ] = utils::to_string( tm_label.label );
234  }
235 
236  // In cases where the mid value is a nice tickmark number (0 for example),
237  // it will be included in the tickmarks, although it is the upper limit for
238  // the lower half (that is, equal to the max for the half).
239  // Thus, we already have a tickmark for the mid value, and now do not need it again
240  // when making the upper half ticks. So, exclude the min for the upper half in this case.
241  if( tm_labels_l.size() > 0 && tm_labels_l.back().relative_position == 1.0 ) {
242  tm.include_min = false;
243  }
244 
245  // Upper half.
246  tm.include_max = true;
247  auto const tm_labels_u = tm.linear_labels(
248  norm.mid_value(), norm.max_value(), frac_upper * num_ticks
249  );
250  for( auto const& tm_label : tm_labels_u ) {
251  auto const pos = frac_lower + frac_upper * tm_label.relative_position;
252  result[ pos ] = utils::to_string( tm_label.label );
253  }
254 
255  return result;
256 }
257 
258 std::map<double, std::string> color_tickmarks( ColorNormalizationBoundary const& norm, size_t num_ticks )
259 {
260  // Ignore. We use the number of boundaries coming from the normalization.
261  (void) num_ticks;
262 
263  // Get range.
264  auto const min = norm.boundaries().front();
265  auto const max = norm.boundaries().back();
266  auto const len = max - min;
267 
268  std::map<double, std::string> result;
269  for( auto const& bound : norm.boundaries() ) {
270  result[ ( bound - min ) / len ] = utils::to_string( bound );
271  }
272  return result;
273 }
274 
275 } // namespace utils
276 } // namespace genesis
void offset(Histogram &h, double value)
Definition: operations.cpp:47
Default Color normalization, using a sequential linear scaling in the range [ min, max ].
Definition: norm_linear.hpp:59
size_t size() const
Return the size of the map, that is, the number of colors in the list.
Definition: map.hpp:238
Store a list of colors and offer them as a map for values in range [ 0.0, 1.0 ].
Definition: map.hpp:61
Color color(size_t index) const
Return a particular color from the palette, module the palette size.
Definition: map.hpp:249
double max_value() const
Minimum value, that is, where to end the color scale.
std::string to_string(T const &v)
Return a string representation of a given value.
Definition: string.hpp:381
Header of Color class.
void scale(Histogram &h, double factor)
Definition: operations.cpp:54
Color interpolate(Color const &color1, Color const &color2, double fraction)
Linearily interpolate between two Colors.
std::map< double, Color > color_stops(ColorMap const &map, ColorNormalization const &norm)
Definition: helpers.cpp:52
Base class for color normalization.
std::map< double, std::string > color_tickmarks(ColorNormalization const &norm, size_t num_ticks)
Definition: helpers.cpp:156
double min_value() const
Minimum value, that is, where to begin the color scale.
Color normalization that maps to discrete intervals.
double mid_value() const
Mid-point value, that is, where the middle value of a diverging_color() is.
Color operators and functions.
std::vector< double > const & boundaries() const
Return the boundaries currently set.
Helper class to find "nice" tickmark intervals for creating scales and axes.
Definition: tickmarks.hpp:48
Color normalization for a diverging scale.
Color normalization for a logarithmic scale.