A library for working with phylogenetic and population genetic data.
v0.32.0
pie_chart.cpp
Go to the documentation of this file.
1 /*
2  Genesis - A toolkit for working with phylogenetic data.
3  Copyright (C) 2014-2023 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 <lczech@carnegiescience.edu>
20  Department of Plant Biology, Carnegie Institution For Science
21  260 Panama Street, Stanford, CA 94305, USA
22 */
23 
32 
38 
39 #include <cassert>
40 #include <cstdlib>
41 #include <numeric>
42 #include <stdexcept>
43 
44 namespace genesis {
45 namespace utils {
46 
47 // =================================================================================================
48 // Svg Pie Chart
49 // =================================================================================================
50 
52  std::vector<double> const& values,
53  std::vector<Color> const& colors,
54  double radius,
55  double start_angle,
56  bool clockwise
57 ) {
58 
59  // Edge cases.
60  if( values.size() == 0 ) {
61  throw std::runtime_error( "No values given to make svg pie chart" );
62  }
63  if( colors.size() == 0 ) {
64  throw std::runtime_error( "No colors given to make svg pie chart" );
65  }
66  if( colors.size() < values.size() ) {
67  throw std::runtime_error(
68  "No enough colors given to make svg pie chart. Given " +
69  std::to_string( colors.size() ) + " colors, but " +
70  std::to_string( values.size() ) + " values."
71  );
72  }
73  auto const all_good = std::all_of( values.cbegin(), values.cend(), []( double v ){
74  return std::isfinite(v) && v >= 0.0;
75  });
76  if( ! all_good ) {
77  throw std::runtime_error(
78  "Invalid negative or non-finite values given to make svg pie chart"
79  );
80  }
81 
82  // Prepare result and helper values.
83  SvgGroup result;
84  double const total = std::accumulate( values.begin(), values.end(), 0.0 );
85  double const dir = clockwise ? 1.0 : -1.0;
86 
87  // Fill the chart. We keep a running sum (in radians) of how much pie we have filled.
88  double sum = 0.0;
89  for( size_t i = 0; i < values.size(); ++i ) {
90  if( values[i] == 0.0 ) {
91  continue;
92  }
93 
94  // We compute the angle that the wedge spans, and where it starts and ends.
95  // If we are going counter clockwise, we have to swap the positions, due to
96  // how our svg_arc helper function takes its arguments (as it always paints clockwise).
97  auto const angle = 2.0 * utils::PI * values[i] / total;
98  auto start_a = start_angle + dir * sum;
99  auto end_a = start_angle + dir * ( sum + angle );
100  if( ! clockwise ) {
101  std::swap( start_a, end_a );
102  }
103  sum += angle;
104 
105  // We create a pie segment as a path, moving to the origin, then an arc with the
106  // specified angles, then back to the origin. The svg_arc function takes care of that.
107  assert( i < colors.size() );
108  result << SvgPath(
109  {{ svg_arc( 0, 0, radius, start_a, end_a, true ) }},
111  SvgFill( colors[ i ] )
112  );
113  }
114 
115  return result;
116 }
117 
118 } // namespace utils
119 } // namespace genesis
genesis::placement::swap
void swap(Sample &lhs, Sample &rhs)
Definition: sample.cpp:104
helper.hpp
genesis::utils::sum
double sum(const Histogram &h)
Definition: utils/math/histogram/stats.cpp:140
genesis::utils::SvgPath
Definition: shapes.hpp:458
shapes.hpp
genesis::utils::svg_arc
std::string svg_arc(double center_x, double center_y, double radius, double start_angle, double end_angle, bool wedge)
Create an arc to use in an SvgPath.
Definition: utils/formats/svg/helper.cpp:50
genesis::population::to_string
std::string to_string(GenomeLocus const &locus)
Definition: function/genome_locus.hpp:52
genesis::utils::SvgStroke
Definition: attributes.hpp:49
pie_chart.hpp
genesis::utils::PI
constexpr double PI
Make the world go round.
Definition: common.hpp:55
genesis::utils::SvgStroke::Type::kNone
@ kNone
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
genesis::utils::SvgFill
Definition: attributes.hpp:131
color.hpp
Header of Color class.
attributes.hpp
genesis::utils::make_svg_pie_chart
SvgGroup make_svg_pie_chart(std::vector< double > const &values, std::vector< Color > const &colors, double radius, double start_angle, bool clockwise)
Make a pie chart in SVG.
Definition: pie_chart.cpp:51
genesis::utils::SvgGroup
Definition: group.hpp:50
object.hpp