A toolkit for working with phylogenetic data.
v0.18.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
palette.cpp
Go to the documentation of this file.
1 /*
2  Genesis - A toolkit for working with phylogenetic data.
3  Copyright (C) 2014-2017 Lucas Czech
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 
34 
35 #include <algorithm>
36 #include <cassert>
37 #include <cassert>
38 #include <stdexcept>
39 
40 namespace genesis {
41 namespace utils {
42 
43 // =================================================================================================
44 // Modificators
45 // =================================================================================================
46 
47 ColorPalette& ColorPalette::range( double min, double max )
48 {
49  min_ = min;
50  mid_ = ( min + max ) / 2.0;
51  max_ = max;
52  return *this;
53 }
54 
55 ColorPalette& ColorPalette::range( double min, double mid, double max )
56 {
57  min_ = min;
58  mid_ = mid;
59  max_ = max;
60  return *this;
61 }
62 
63 // =================================================================================================
64 // Palette
65 // =================================================================================================
66 
68 {
69  if( palette_.size() == 0 ) {
70  return Color();
71  }
72  return get_entry_( index % palette_.size() );
73 }
74 
76 {
77  // Perform checks. Might manipulate value.
78  auto const checks = boundary_checks_( value );
79  if( checks.second ) {
80  return checks.first;
81  }
82 
83  // Bring value into the range [ 0.0, 1.0 ].
84  auto const pos = ( value - min_ ) / ( max_ - min_ );
85 
86  // Get the color at that position in the palette.
87  return get_interpolated_color_( pos );
88 }
89 
90 Color ColorPalette::diverging_color( double value ) const
91 {
92  // Perform checks. Might manipulate value.
93  auto const checks = boundary_checks_( value );
94  if( checks.second ) {
95  return checks.first;
96  }
97 
98  // Bring value into the range [ 0.0, 1.0 ].
99  double pos = 0.0;
100  if( value < mid_ ) {
101  pos = ( value - min_ ) / ( mid_ - min_ );
102  pos /= 2.0;
103  } else {
104  pos = ( value - mid_ ) / ( max_ - mid_ );
105  pos /= 2.0;
106  pos += 0.5;
107  }
108 
109  // Get the color at that position in the palette.
110  return get_interpolated_color_( pos );
111 }
112 
113 std::vector<Color> ColorPalette::qualitative_colors( std::vector<size_t> const& values ) const
114 {
115  auto result = std::vector<Color>( values.size() );
116  for( size_t i = 0; i < values.size(); ++i ) {
117  result[i] = qualitative_color( values[i] );
118  }
119  return result;
120 }
121 
122 std::vector<Color> ColorPalette::sequential_colors( std::vector<double> const& values ) const
123 {
124  auto result = std::vector<Color>( values.size() );
125  for( size_t i = 0; i < values.size(); ++i ) {
126  result[i] = sequential_color( values[i] );
127  }
128  return result;
129 }
130 
131 std::vector<Color> ColorPalette::diverging_colors( std::vector<double> const& values ) const
132 {
133  auto result = std::vector<Color>( values.size() );
134  for( size_t i = 0; i < values.size(); ++i ) {
135  result[i] = diverging_color( values[i] );
136  }
137  return result;
138 }
139 
140 // =================================================================================================
141 // Internal Functions
142 // =================================================================================================
143 
144 std::pair<Color, bool> ColorPalette::boundary_checks_( double& value ) const
145 {
146  // Extreme cases check.
147  if( palette_.size() == 0 ) {
148  return { Color( 0.0, 0.0, 0.0 ), true};
149  }
150  if( palette_.size() == 1 ) {
151  return { palette_[0], true };
152  }
153  if( min_ >= max_ ) {
154  throw std::invalid_argument( "Invalid ColorPalette with min >= max." );
155  }
156  if( min_ >= mid_ ) {
157  throw std::invalid_argument( "Invalid ColorPalette with min >= mid." );
158  }
159  if( mid_ >= max_ ) {
160  throw std::invalid_argument( "Invalid ColorPalette with mid >= max." );
161  }
162 
163  // Boundary checks.
164  if( ! std::isfinite( value ) || value == mask_value_ ) {
165  return { mask_color_, true };
166  }
167  if( clip_ ) {
168  value = std::min( std::max( min_, value ), max_ );
169  }
170  if( value < min_ ) {
171  return { under_color_, true };
172  }
173  if( value > max_ ) {
174  return { over_color_, true };
175  }
176 
177  // Nothing bad happend.
178  return{ Color(), false };
179 }
180 
181 Color ColorPalette::get_interpolated_color_( double value ) const
182 {
183  assert( value >= 0.0 && value <= 1.0 );
184  assert( palette_.size() > 0 );
185 
186  // Bring value into the correct range within the palette size.
187  auto const val_entry = static_cast<double>( palette_.size() - 1 ) * value;
188  assert( val_entry >= 0 );
189  assert( val_entry < static_cast<double>( palette_.size() ));
190 
191  // Get the values at the two colors next to the entry.
192  // auto const low_value = min_ + (( std::floor( val_entry ) / max_entry ) * ( max_ - min_ ));
193  // auto const high_value = min_ + (( std::ceil( val_entry ) / max_entry ) * ( max_ - min_ ));
194  // auto const interval_len = ( max_ - min_ ) / max_entry;
195 
196  // Get the color indices next to our chosen value.
197  auto const low_idx = static_cast<size_t>( std::floor( val_entry ) );
198  auto const high_idx = static_cast<size_t>( std::ceil( val_entry ) );
199  if( low_idx == high_idx ) {
200  return get_entry_( low_idx );
201  }
202  assert( low_idx < high_idx );
203 
204  // Get the fraction between the two entries that our value sits on.
205  auto const fraction = val_entry - std::floor( val_entry );
206  assert( fraction >= 0.0 && fraction <= 1.0 );
207 
208  // Return the interpolated result.
209  return interpolate( get_entry_( low_idx ), get_entry_( high_idx ), fraction );
210 }
211 
212 
213 } // namespace utils
214 } // namespace genesis
std::vector< Color > qualitative_colors(std::vector< size_t > const &values) const
Definition: palette.cpp:113
Color qualitative_color(size_t index) const
Definition: palette.cpp:67
Color sequential_color(double value) const
Definition: palette.cpp:75
Color interpolate(Color const &color1, Color const &color2, double fraction)
Linearily interpolate between two Colors.
Color diverging_color(double value) const
Get a color by using the palette for a diverging scale.
Definition: palette.cpp:90
ColorPalette & range(double min, double max)
Definition: palette.cpp:47
std::vector< Color > diverging_colors(std::vector< double > const &values) const
Definition: palette.cpp:131
Color operators and functions.
std::vector< Color > sequential_colors(std::vector< double > const &values) const
Definition: palette.cpp:122