A library for working with phylogenetic and population genetic data.
v0.32.0
genome_heatmap.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 
34 
35 #include <cassert>
36 
37 namespace genesis {
38 namespace population {
39 
40 // =================================================================================================
41 // Genome Heatmap
42 // =================================================================================================
43 
45  std::string const& label,
46  utils::Matrix<utils::Color> const& heatmap,
47  utils::SvgGroup x_axis,
48  utils::SvgGroup y_axis,
49  std::pair<utils::SvgGradientLinear, utils::SvgGroup> color_bar
50 ) {
51  using namespace utils;
52 
53  // Make a text, based on the template
54  auto txt = text_template_;
55  txt.text = label;
56 
57  // Add the label, unless it's supposed to be at the bottom, in which case we add it later.
58  if( ! label.empty() ) {
59  switch( text_position_ ) {
60  case TextPosition::kTop: {
61  txt.position = SvgPoint{ 0.0, current_y_ };
62  document_ << txt;
63  current_y_ += text_template_.font.size + 5.0;
64  break;
65  }
66  case TextPosition::kLeft: {
67  txt.position = SvgPoint{ -100.0, current_y_ };
68  document_ << txt;
69  break;
70  }
71  case TextPosition::kRight: {
72  auto const r = static_cast<double>( heatmap.cols() ) * h_scaling_;
73  txt.position = SvgPoint{ r + 10.0, current_y_ };
74  document_ << txt;
75  break;
76  }
77  case TextPosition::kBottom: {
78  break;
79  }
80  default: {
81  assert( false );
82  }
83  }
84  }
85 
86  // Add the heatmap as a bitmap, embedded by encoding it in base64, and using pixelated rendering
87  // (which is not really well defined in svg, but we try hard).
88  std::string matrix_bmp;
89  BmpWriter().write( heatmap, genesis::utils::to_string( matrix_bmp ));
90  auto img = SvgImage(
91  svg_data_uri( "image/bmp", matrix_bmp, true ),
92  SvgPoint{ 0.0, current_y_ },
93  SvgSize{
94  static_cast<double>( heatmap.cols() ) * h_scaling_,
95  static_cast<double>( heatmap.rows() ) * v_scaling_
96  }
97  );
98  img.rendering = SvgImage::ImageRendering::kPixelated;
99  document_ << std::move( img );
100 
101  // If we have other objects at the same position provided, add them too, and move accordingly.
102  if( color_bar.second ) {
103  auto const xpos = 30.0 + static_cast<double>( heatmap.cols() ) * h_scaling_;
104  color_bar.second.transform.append( SvgTransform::Translate( xpos, current_y_ ));
105  document_ << std::move( color_bar.second );
106  document_.defs.push_back( color_bar.first );
107  }
108  if( y_axis ) {
109  auto const ypos = current_y_ + static_cast<double>( heatmap.rows() ) * v_scaling_;
110  y_axis.transform.append( SvgTransform::Translate( 0.0, ypos ));
111  document_ << std::move( y_axis );
112  }
113  if( x_axis ) {
114  // We have added the other two extra groups to the doc first,
115  // so that we can move the current y pos here without affecting them.
116  auto const ypos = current_y_ + static_cast<double>( heatmap.rows() ) * v_scaling_;
117  x_axis.transform.append( SvgTransform::Translate( 0.0, ypos ));
118  current_y_ += x_axis.bounding_box().height();
119  document_ << std::move( x_axis );
120  }
121 
122  // Move to below the added image
123  current_y_ += static_cast<double>( heatmap.rows() ) * v_scaling_;
124 
125  // Add the label if its supposed to be at the bottom, or simply add vertical space as needed.
126  if( ! label.empty() && text_position_ == TextPosition::kBottom ) {
127  current_y_ += text_template_.font.size + 5.0;
128  txt.position = SvgPoint{ 0.0, current_y_ };
129  document_ << txt;
130  }
131  current_y_ += 20.0;
132 }
133 
134 void GenomeHeatmap::write( std::shared_ptr<utils::BaseOutputTarget> target ) const
135 {
136  document_.write( target->ostream() );
137 }
138 
139 } // namespace population
140 } // namespace genesis
genesis::utils::svg_data_uri
std::string svg_data_uri(std::string const &media_type, std::string const &content, bool encode_base64=false)
Definition: utils/formats/svg/helper.hpp:239
genesis::utils::to_string
std::shared_ptr< BaseOutputTarget > to_string(std::string &target_string)
Obtain an output target for writing to a string.
Definition: output_target.hpp:186
genesis::utils::SvgTransform::append
void append(Transformation &&t)
Definition: attributes.cpp:353
genesis::utils::Matrix::cols
size_t cols() const
Definition: containers/matrix.hpp:181
genesis::population::GenomeHeatmap::TextPosition::kBottom
@ kBottom
genesis::utils::SvgDocument::write
void write(std::ostream &out) const
Write the SvgDocument to an output stream.
Definition: svg/document.cpp:70
genome_heatmap.hpp
genesis::utils::Matrix
Definition: placement/function/emd.hpp:53
genesis::population::GenomeHeatmap::write
void write(std::shared_ptr< utils::BaseOutputTarget > target) const
Definition: genome_heatmap.cpp:134
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::SvgBox::height
double height() const
Definition: utils/formats/svg/helper.hpp:162
genesis::utils::SvgGroup::bounding_box
SvgBox bounding_box() const
Definition: group.cpp:50
writer.hpp
genesis::utils::SvgGroup::transform
SvgTransform transform
Definition: group.hpp:159
genesis::utils::Matrix::rows
size_t rows() const
Definition: containers/matrix.hpp:176
genesis::utils::SvgGroup
Definition: group.hpp:50
genesis::population::GenomeHeatmap::TextPosition::kRight
@ kRight
genesis::population::GenomeHeatmap::TextPosition::kTop
@ kTop
genesis::population::GenomeHeatmap::add
void add(std::string const &label, utils::Matrix< utils::Color > const &heatmap, utils::SvgGroup x_axis=utils::SvgGroup{}, utils::SvgGroup y_axis=utils::SvgGroup{}, std::pair< utils::SvgGradientLinear, utils::SvgGroup > color_bar=std::pair< utils::SvgGradientLinear, utils::SvgGroup >{})
Definition: genome_heatmap.cpp:44
genesis::population::GenomeHeatmap::TextPosition::kLeft
@ kLeft