A library for working with phylogenetic and population genetic data.
v0.32.0
norm_boundary.hpp
Go to the documentation of this file.
1 #ifndef GENESIS_UTILS_COLOR_NORM_BOUNDARY_H_
2 #define GENESIS_UTILS_COLOR_NORM_BOUNDARY_H_
3 
4 /*
5  Genesis - A toolkit for working with phylogenetic data.
6  Copyright (C) 2014-2023 Lucas Czech
7 
8  This program is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation, either version 3 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program. If not, see <http://www.gnu.org/licenses/>.
20 
21  Contact:
22  Lucas Czech <lczech@carnegiescience.edu>
23  Department of Plant Biology, Carnegie Institution For Science
24  260 Panama Street, Stanford, CA 94305, USA
25 */
26 
39 
40 #include <algorithm>
41 #include <cassert>
42 #include <cmath>
43 #include <limits>
44 #include <map>
45 #include <stdexcept>
46 #include <string>
47 #include <vector>
48 
49 namespace genesis {
50 namespace utils {
51 
52 // =================================================================================================
53 // Color Normalization Boundary
54 // =================================================================================================
55 
76  : public ColorNormalization
77 {
78 public:
79 
80  // -------------------------------------------------------------------------
81  // Constructors and Rule of Five
82  // -------------------------------------------------------------------------
83 
87  ColorNormalizationBoundary() = default;
88 
92  explicit ColorNormalizationBoundary( std::vector<double> const& boundaries )
93  : boundaries_( boundaries )
94  {
96  }
97 
98  ColorNormalizationBoundary( double min, double max, size_t intervals )
99  {
100  scale( min, max, intervals );
101  }
102 
103  virtual ~ColorNormalizationBoundary() override = default;
104 
107 
110 
111  // -------------------------------------------------------------------------
112  // Accessors
113  // -------------------------------------------------------------------------
114 
118  std::vector<double> const& boundaries() const
119  {
120  return boundaries_;
121  }
122 
126  long interval( double value ) const
127  {
128  // Make sure that the norm is set up correctly.
129  // This is now done while setting, so no need to do this here.
130  // is_valid_or_throw_();
131 
132  // Extreme cases: value is not within the boundaries.
133  // For the upper limit, we return size-1, as this is the first interval index
134  // that is not reachable with valid (within-boundary) values.
135  assert( boundaries_.size() >= 3 );
136  if( value < boundaries_.front() ) {
137  return -1;
138  }
139  if( value > boundaries_.back() ) {
140  return boundaries_.size() - 1;
141  }
142 
143  // Get an iterator to the boundary, and turn it into an interval index upon return.
144  // The index calculation has a special case if the value hits exaclty the highest
145  // boundary value. In that case, the iterator points to the end of the boundary vector.
146  // In all other cases, the iterator points to the end of interval boundary,
147  // so we subtract one to get the interval index.
148  // The first assertion checks this special case.
149  // The second assertion holds because we already checked that the value is not less than
150  // the first boundary.
151  auto const it = std::upper_bound( boundaries_.begin(), boundaries_.end(), value );
152  assert(( it != boundaries_.end() ) xor ( value == boundaries_.back() ));
153  assert( it != boundaries_.begin() );
154 
155  if( it == boundaries_.end() ) {
156  return boundaries_.size() - 2;
157  } else {
158  return std::distance( boundaries_.begin(), it ) - 1;
159  }
160  }
161 
162  // -------------------------------------------------------------------------
163  // Modificators
164  // -------------------------------------------------------------------------
165 
169  ColorNormalizationBoundary& boundaries( std::vector<double> const& values )
170  {
171  boundaries_ = values;
173  return *this;
174  }
175 
180  ColorNormalizationBoundary& scale( double min, double max, size_t intervals )
181  {
182  // Make evenly distributed boundary intervals between min and max.
183  // We add max separately to increase precision.
184  boundaries_.clear();
185  double const interv = ( max - min ) / static_cast<double>( intervals );
186  for( size_t i = 0; i < intervals; ++i ) {
187  boundaries_.push_back( min + static_cast<double>(i) * interv );
188  }
189  boundaries_.push_back( max );
191 
192  return *this;
193  }
194 
199  ColorNormalizationBoundary& autoscale( std::vector<double> const& values, size_t intervals )
200  {
201  return autoscale( values.begin(), values.end(), intervals );
202  }
203 
208  template <class ForwardIterator>
210  ForwardIterator first, ForwardIterator last, size_t intervals
211  ) {
212  // New values, so that we first do not override the current ones.
213  auto min = std::numeric_limits<double>::max();
214  auto max = std::numeric_limits<double>::lowest();
215 
216  size_t cnt = 0;
217  while( first != last ) {
218  if( ! std::isfinite( *first ) || *first == mask_value() ) {
219  ++first;
220  continue;
221  }
222  if( *first < min ) {
223  min = *first;
224  }
225  if( *first > max ) {
226  max = *first;
227  }
228 
229  ++cnt;
230  ++first;
231  }
232 
233  // Only update if we found values.
234  if( cnt == 0 ) {
235  return *this;
236  }
237 
238  scale( min, max, intervals );
239  return *this;
240  }
241 
242  // -------------------------------------------------------------------------
243  // (Pure) Virtual Functions
244  // -------------------------------------------------------------------------
245 
246 protected:
247 
251  virtual bool is_valid_() const override
252  {
253  return boundaries_.size() >= 3 && std::is_sorted( boundaries_.begin(), boundaries_.end() );
254  }
255 
259  virtual void is_valid_or_throw_() const
260  {
261  if( boundaries_.size() < 3 ) {
262  throw std::runtime_error( "Invalid Color Normalization with less than three boundaries." );
263  }
264  if( ! std::is_sorted( boundaries_.begin(), boundaries_.end() ) ) {
265  throw std::runtime_error( "Invalid Color Normalization with unsorted boundaries." );
266  }
267  }
268 
272  virtual double normalize_( double value ) const override
273  {
274  auto const idx = interval( value );
275 
276  // Special cases: the value is outside of the boundaries.
277  if( idx < 0 ) {
278  return -1.0;
279  }
280  if( idx >= static_cast<long>( boundaries_.size() - 1 )) {
281  return 2.0;
282  }
283 
284  // If we are inside the boundaries, calculate a fixed position depending on the interval.
285  // As the index returned for too large values is size-1, we need to use size-2 here
286  // to normalize properly so that the max value corresponds to a normalized value of 1.0.
287  assert( boundaries_.size() >= 3 );
288  return static_cast<double>( idx ) / static_cast<double>( boundaries_.size() - 2 );
289  }
290 
291  // -------------------------------------------------------------------------
292  // Data Members
293  // -------------------------------------------------------------------------
294 
295 private:
296 
297  std::vector<double> boundaries_;
298 
299 };
300 
301 } // namespace utils
302 } // namespace genesis
303 
304 #endif // include guardmask_value_
genesis::utils::ColorNormalizationBoundary::autoscale
ColorNormalizationBoundary & autoscale(ForwardIterator first, ForwardIterator last, size_t intervals)
Set the boundaries similar to scale(), but use the given range to determine min and max first.
Definition: norm_boundary.hpp:209
genesis::utils::ColorNormalization
Base class for color normalization.
Definition: normalization.hpp:52
map.hpp
genesis::utils::ColorNormalizationBoundary::normalize_
virtual double normalize_(double value) const override
Normalization function.
Definition: norm_boundary.hpp:272
genesis::utils::ColorNormalization::mask_value
double mask_value() const
Mask value that identifies invalid values.
Definition: normalization.hpp:83
genesis::utils::ColorNormalizationBoundary::ColorNormalizationBoundary
ColorNormalizationBoundary()=default
string.hpp
Provides some commonly used string utility functions.
genesis::utils::ColorNormalizationBoundary::scale
ColorNormalizationBoundary & scale(double min, double max, size_t intervals)
Set the boundaries to equal-sizes intervals between min and max, using intervals many steps.
Definition: norm_boundary.hpp:180
genesis::utils::ColorNormalizationBoundary::boundaries
ColorNormalizationBoundary & boundaries(std::vector< double > const &values)
Explicitly set the boundaries to the given values. Have to be sorted.
Definition: norm_boundary.hpp:169
genesis::utils::ColorNormalizationBoundary::autoscale
ColorNormalizationBoundary & autoscale(std::vector< double > const &values, size_t intervals)
Set the boundaries similar to scale(), but use the given vector of values to determine min and max fi...
Definition: norm_boundary.hpp:199
genesis::utils::ColorNormalizationBoundary::is_valid_
virtual bool is_valid_() const override
Return whether the boundaries are correct.
Definition: norm_boundary.hpp:251
genesis::utils::ColorNormalizationBoundary
Color normalization that maps to discrete intervals.
Definition: norm_boundary.hpp:75
genesis
Container namespace for all symbols of genesis in order to keep them separate when used as a library.
Definition: placement/formats/edge_color.cpp:42
color.hpp
Header of Color class.
genesis::utils::ColorNormalizationBoundary::boundaries
std::vector< double > const & boundaries() const
Return the boundaries currently set.
Definition: norm_boundary.hpp:118
genesis::utils::ColorNormalizationBoundary::is_valid_or_throw_
virtual void is_valid_or_throw_() const
Throw if the boundaries are incorrect.
Definition: norm_boundary.hpp:259
genesis::utils::ColorNormalizationBoundary::interval
long interval(double value) const
Return the interval index of a value.
Definition: norm_boundary.hpp:126
genesis::utils::ColorNormalizationBoundary::operator=
ColorNormalizationBoundary & operator=(ColorNormalizationBoundary const &)=default
tickmarks.hpp
genesis::utils::ColorNormalizationBoundary::~ColorNormalizationBoundary
virtual ~ColorNormalizationBoundary() override=default
normalization.hpp
genesis::utils::ColorNormalizationBoundary::ColorNormalizationBoundary
ColorNormalizationBoundary(std::vector< double > const &boundaries)
Definition: norm_boundary.hpp:92
genesis::utils::ColorNormalizationBoundary::ColorNormalizationBoundary
ColorNormalizationBoundary(double min, double max, size_t intervals)
Definition: norm_boundary.hpp:98