CbmRoot
Loading...
Searching...
No Matches
CbmQaReportBeamerEngine.cxx
Go to the documentation of this file.
1/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Sergei Zharko [committer] */
4
9
11
12#include "CbmQaReportFigure.h"
13#include "CbmQaReportHeader.h"
15#include "CbmQaReportSection.h"
16#include "CbmQaReportTable.h"
17#include "CbmQaReportTail.h"
18#include "Logger.h"
19
20#include <boost/algorithm/string/join.hpp>
21
22#include <chrono>
23#include <ctime>
24#include <iomanip>
25#include <numeric>
26#include <regex>
27#include <sstream>
28
36
37// ---------------------------------------------------------------------------------------------------------------------
38//
39std::string BeamerEngine::FigureBody(const Figure& figure) const
40{
41 size_t nPlots = figure.GetPlots().size();
42 if (nPlots == 0) {
43 LOG(warn) << "No plots provided for figure " << figure.GetLabel() << ". Ignoring.";
44 return "";
45 }
46
47 std::stringstream out;
48 out << "\\begin{frame}{" << figure.GetMother()->GetTitle() << "}\n";
49 out << " \\begin{figure}\n";
50 out << " \\def\\hgt{\\textheight-2\\baselineskip}\n";
51 out << " \\centering\n";
52 if (nPlots == 1) {
53 out << " \\begin{adjustbox}{width=\\textwidth, totalheight=0.9\\hgt, keepaspectratio}\n";
54 out << " \\includegraphics[height=0.75\\paperheight]{" << figure.GetPlots()[0].fsPath << "}\n";
55 out << " \\end{adjustbox}\n";
56 }
57 else {
58 std::vector<size_t> vPlotGrid;
59 bool bDefineDefaultGrid = figure.GetPlotGrid().empty();
60 if (!bDefineDefaultGrid) {
61 size_t nPlotsByGrid = std::accumulate(figure.GetPlotGrid().begin(), figure.GetPlotGrid().end(), 0);
62 if (nPlotsByGrid < nPlots) {
63 LOG(warn) << "Figure " << figure.GetLabel()
64 << ": provided grid does not fit the subfigures, define the default one";
65 bDefineDefaultGrid = true;
66 }
67 }
68
69 if (bDefineDefaultGrid) {
70 if (nPlots < 4) {
71 vPlotGrid.resize(1, nPlots);
72 }
73 else {
74 int nY = nPlots < 13 ? 2 : 3;
75 vPlotGrid.resize(nY, size_t(std::ceil(double(nPlots) / nY)));
76 }
77 }
78 else {
79 vPlotGrid = figure.GetPlotGrid();
80 }
81
82 size_t iPlot = 0;
83 double hSize = 0.9 / vPlotGrid.size();
84 for (size_t iY = 0; iY < vPlotGrid.size(); ++iY) {
85 if (iPlot >= nPlots) {
86 break;
87 }
88 size_t nX = vPlotGrid[iY];
89 if (nX == 0) {
90 continue;
91 }
92 out << " \\begin{adjustbox}{width=\\textwidth, totalheight=" << hSize << "\\hgt, keepaspectratio}\n";
93 for (size_t iX = 0; iX < nX; ++iX) {
94 if (iPlot >= nPlots) {
95 break;
96 }
97 const auto& plot = figure.GetPlots()[iPlot];
98 out << " \\stackunder[1pt]{\\includegraphics[height=0.75\\paperheight]{" << plot.fsPath << "}}{";
99 out << plot.fsCaption << "}\n";
100 if (iX == nX - 1) {
101 out << '\n';
102 }
103 else {
104 out << " \\quad\n";
105 }
106 ++iPlot;
107 }
108 out << " \\end{adjustbox}\n\n";
109 if (iY != vPlotGrid.size() - 1) {
110 out << '\n';
111 }
112 }
113 }
114
115 if (!figure.GetCaption().empty()) {
116 out << " \\caption{" << LatexFormat::Apply(figure.GetCaption()) << "}\n";
117 }
118 out << " \\label{" << figure.GetLabel() << "}\n";
119 out << " \\end{figure}\n";
120 out << "\\end{frame}\n";
121 return out.str();
122}
123
124// ---------------------------------------------------------------------------------------------------------------------
125//
126std::string BeamerEngine::HeaderBody(const Header& header) const
127{
128 std::stringstream out;
129
130 // TODO: Move these definitions to text-file (?)
131 // Settings
132
133 out << "\\documentclass[aspectratio=169,xcolor=dvipsnames]{beamer}\n";
134 out << "\\usetheme{Madrid}\n";
135 out << "\\useinnertheme{circles}\n";
136 out << "\\setbeamerfont{structure}{family=\\sffamily,series=\\mdseries}\n";
137 out << "\\setbeamerfont{title}{size=\\LARGE,parent=structure}\n";
138 out << "\\setbeamerfont{subtitle}{size=\\normalsize,parent=title}\n";
139 out << "\\setbeamerfont{date}{size=\\scriptsize,series=\\mdseries,parent=structure}\n";
140 out << "\\setbeamerfont{author}{size=\\Large,series=\\mdseries,parent=structure}\n";
141 out << "\\setbeamerfont{institute}{size=\\scriptsize,series=\\mdseries,parent=structure}\n";
142 out << "\\setbeamerfont{section in toc}{size=\\Large,parent=structure}\n";
143 out << "\\setbeamerfont{section in head/foot}{size=\\tiny,parent=structure}\n";
144 out << "\\setbeamerfont{subsection in toc}{size=\\large,parent={section in toc}}\n";
145 out << "\\setbeamerfont{frametitle}{parent=structure,size=\\LARGE}\n";
146 out << "\\setbeamerfont{framesubtitle}{parent=frametitle,size=\\Large}\n";
147 out << "\\setbeamerfont{caption}{size=\\footnotesize}\n";
148 out << "\\setbeamerfont{item}{parent=structure,series=\\mdseries}\n";
149 out << "\\setbeamerfont{block title}{size=\\large,series=\\mdseries,parent={structure,block body}}\n";
150 out << "\\definecolor{InvisibleRed}{rgb}{0.92, 0.9, 0.9}\n";
151 out << "\\definecolor{InvisibleGreen}{rgb}{0.9, 0.92, 0.9}\n";
152 out << "\\definecolor{InvisibleBlue}{rgb}{0.9, 0.9, 0.92}\n";
153 out << "\\definecolor{LightBlue}{rgb}{0.4, 0.55, 0.65}\n";
154 out << "\\definecolor{LightBlue}{rgb}{0.4, 0.55, 0.65}\n";
155 out << "\\definecolor{MediumRed}{rgb}{0.92549, 0.34509, 0.34509}\n";
156 out << "\\definecolor{MediumGreen}{rgb}{0.36862, 0.66666, 0.65882}\n";
157 out << "\\definecolor{MediumBlue}{rgb}{0.01176, 0.31372, 0.43529}\n";
158 out << "\\definecolor{DarkBlue}{rgb}{0.05, 0.15, 0.3} \n";
159 out << "\\usecolortheme[named=DarkBlue]{structure}\n";
160 out << "\\setbeamercolor{alerted text}{fg=LightBlue}\n";
161 out << "\\setbeamercolor{palette primary}{bg=DarkBlue,fg=white}\n";
162 out << "\\setbeamercolor{palette secondary}{bg=MediumBlue,fg=white}\n";
163 out << "\\setbeamercolor{palette tertiary}{bg=LightBlue,fg=white}\n";
164 out << "\\setbeamercolor{block title}{bg=MediumBlue}\n";
165 out << "\\setbeamercolor{block body}{bg=InvisibleBlue}\n";
166 out << "\\setbeamercolor{block title example}{bg=MediumGreen}\n";
167 out << "\\setbeamercolor{block body example}{bg=InvisibleGreen}\n";
168 out << "\\setbeamercolor{block title alerted}{bg=MediumRed}\n";
169 out << "\\setbeamercolor{block body alerted}{bg=InvisibleRed}\n";
170 out << "\\setbeamertemplate{footline}[page number]\n";
171 out << "\\setbeamertemplate{navigation symbols}{}\n";
172 out << "\\setbeamertemplate{blocks}[rounded][shadow=true]\n";
173 out << "\\setbeamertemplate{enumerate items}[default]\n";
174 out << "\\setbeamertemplate{section in toc}[sections numbered]\n";
175 out << "\\setbeamertemplate{subsection in toc}[default]\n";
176
177 out << "\\usepackage{hyperref}\n";
178 out << "\\usepackage{graphicx}\n";
179 out << "\\usepackage{booktabs}\n";
180 out << "\\usepackage{listings}\n";
181 out << "\\usepackage{amsmath}\n";
182 out << "\\usepackage{listings}\n";
183 out << "\\usepackage{xcolor}\n";
184 //out << "\\usepackage{adjustbox}\n";
185 out << "\\usepackage{subfig}\n";
186 out << "\\usepackage{hyperref}\n";
187 out << "\\usepackage{stackengine}\n";
188 out << "\\usepackage{longtable}\n";
189 out << "\\usepackage[export]{adjustbox}\n";
190
191 out << "\\setbeamertemplate{caption}[numbered]\n";
192
193 out << "\\AtBeginSection[]{\n";
194 out << " \\begin{frame}\n";
195 out << " \\vfill\n";
196 out << " \\begin{beamercolorbox}[sep=8pt,shadow=true,rounded=true]{title}\n";
197 out << " \\usebeamerfont{title}Section: \\insertsectionhead\\par%\n";
198 out << " \\end{beamercolorbox}\n";
199 out << " \\tableofcontents[currentsection]\n";
200 out << " \\vfill\n";
201 out << " \\end{frame}\n";
202 out << "}\n";
203 out << "\n";
204 out << "\\AtBeginSubsection[]{\n";
205 out << " \\begin{frame}\n";
206 out << " \\vfill\n";
207 out << " \\begin{beamercolorbox}[sep=6pt,shadow=true,rounded=true]{title}\n";
208 out << " \\usebeamerfont{title}Subsection: \\insertsubsectionhead\\par%\n";
209 out << " \\end{beamercolorbox}\n";
210 out << " \\tableofcontents[currentsubsection]\n";
211 out << " \\vfill\n";
212 out << " \\end{frame}\n";
213 out << "}\n";
214
215 //out << "\\usepackage{color}\n";
216 //out << "\\definecolor{hrefcolor}{rgb}{0.2, 0.2, 0.6}\n";
217 //out << "\\hypersetup{color}{colorlinks=true, urlcolor=hrefcolor,linkcolor=black,citecolor=hrefcolor}\n";
218 if (!header.GetPageHeader().empty()) {
219 //out << "\\usepackage{fancyhdr}\n\\pagestyle{fancy}\n\\lhead{"
220 // << LatexFormat::Apply(header.GetPageHeader()) << "}\n";
221 }
222 out << "\n";
223 // Title page settings
224 out << "\\title{" << LatexFormat::Apply(header.GetTitle()) << "}\n";
225 out << "\\subtitle{" << LatexFormat::Apply(header.GetSubtitle()) << "}\n";
226 auto timeNow = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
227 out << "\\date{Generated on " << std::put_time(std::localtime(&timeNow), "%a %d.%m.%Y, %X") << "}\n";
228
229
230 // Title page
231 out << "\\begin{document}\n\n";
232 out << "\\begin{frame}\n";
233 out << " \\titlepage\n";
234 out << " \\begin{tabular}{r@{ }l}\n";
235 out << " author: & " << header.GetAuthor() << " \\\\\n";
236 out << " setup: & " << LatexFormat::Apply(header.GetSetup()) << "\\\\\n";
237 out << " tags: & " << boost::algorithm::join(header.GetTags(), ", ") << '\n';
238 out << " \\end{tabular}\n";
239 out << "\\end{frame}\n";
240
241 // Table of contents
242 out << "\\begin{frame}{Outline}\n";
243 out << " \\tableofcontents\n";
244 out << "\\end{frame}\n";
245
246 out << '\n';
247 return out.str();
248}
249
250
251// ---------------------------------------------------------------------------------------------------------------------
252//
253std::string BeamerEngine::SectionBody(const Section& section) const
254{
255 std::stringstream out;
256 std::string sSectionType = "";
257 if (section.GetLevel() == 0) {
258 sSectionType = "section";
259 }
260 else if (section.GetLevel() == 1) {
261 sSectionType = "subsection";
262 }
263 else {
264 sSectionType = "subsubsection";
265 }
266
267 out << "\\" << sSectionType << "{" << section.GetTitle() << "}\n\n";
268 for (const auto& pElement : section.GetDaughterElements()) {
269 out << pElement->GetBody(*this) << '\n';
270 }
271 out << '\n';
272 return out.str();
273}
274
275// ---------------------------------------------------------------------------------------------------------------------
276//
277std::string BeamerEngine::TableBody(const Table& table) const
278{
279 std::stringstream out;
280 int nRows = table.GetNofRows();
281 int nCols = table.GetNofCols();
282
283 out << "\\begin{frame}{" << table.GetMother()->GetTitle() << "}\n";
284 out << " \\begin{table}\n";
285 out << " \\footnotesize\n";
286 // tabular header
287 if (!table.GetCaption().empty()) {
288 out << " \\caption{" << LatexFormat::Apply(table.GetCaption()) << "}\n";
289 }
290 out << " \\begin{longtable}{" << std::string(nCols, 'c') << "}\n";
291 // table header
292 out << " \\hline\n";
293 out << " ";
294 for (int iCol = 0; iCol < nCols; ++iCol) {
295 out << table.GetColumnTitle(iCol) << ((iCol < nCols - 1) ? " & " : " \\\\\n");
296 }
297 out << " \\hline\n";
298 // table body
299 for (int iRow = 0; iRow < nRows; ++iRow) {
300 out << " ";
301 for (int iCol = 0; iCol < nCols; ++iCol) {
302 out << table(iRow, iCol) << ((iCol < nCols - 1) ? " & " : " \\\\\n");
303 }
304 }
305 out << " \\hline\n";
306
307 out << " \\end{longtable}\n";
308 out << " \\label{" << table.GetLabel() << "}\n";
309 out << " \\end{table}\n";
310 out << "\\end{frame}\n";
311 return out.str();
312}
313
314// ---------------------------------------------------------------------------------------------------------------------
315//
316std::string BeamerEngine::TailBody(const Tail& figure) const
317{
318 std::stringstream out;
319 out << "\\end{document}\n";
320 return out.str();
321}
322
323// ---------------------------------------------------------------------------------------------------------------------
324//
325void BeamerEngine::Compile(const std::string& source) const
326{
327 // Search for compiler program in path
328 std::string compiler = fsLatexCompiler.substr(0, fsLatexCompiler.find_first_of(' ')); // compiler name without opts
329 int bCompilerFonud = false;
330 {
331 std::stringstream stream(getenv("PATH"));
332 std::string dir;
333 while (!bCompilerFonud && std::getline(stream, dir, ':')) {
334 bCompilerFonud = fs::exists(fs::path(dir) / compiler);
335 }
336 }
337
338 if (!bCompilerFonud) {
339 LOG(error) << "cbm::qa::report::BeamerEngine::Compile(): compiler \"" << fsLatexCompiler << "\" not found in PATH. "
340 << "Please use another compiler or compile the sourec in external program";
341 return;
342 }
343
344 // Execute compiler
345 fs::path sourceDir = fs::path(source).parent_path();
346 fs::path currPath = fs::current_path();
347 fs::current_path(sourceDir);
348
349 std::string logFile = compiler + ".log";
350 std::string command = fmt::format("{} {} > {}", fsLatexCompiler, source, logFile);
351 command = command + ";" + command; // compile two times to get contents
352
353 LOG(info) << "cbm::qa::report::BeamerEngine::Compile(): executing command: \n\t" << command;
354 int res = std::system(command.c_str());
355 fs::current_path(currPath);
356
357 LOG(info) << "cbm::qa::report::BemaerEngine::Compile(): compillation " << (res == 0 ? "succeed" : "failed")
358 << "(compiler log: \"" << logFile << "\")";
359}
LaTeX Beamer engine for the cbm::qa::report (header)
Base class for the report figure (header)
Base class for the report header (header)
Common LaTeX utilities (header)
Base class for the report section (header)
Base class for the report table (header)
Plain LaTeX document engine.
void Compile(const std::string &source) const override
Compiles source.
std::string TailBody(const Tail &tail) const override
Creates a body for tail.
std::string TableBody(const Table &table) const override
Creates a body for table.
std::string FigureBody(const Figure &figure) const override
Creates a body for figure.
std::string SectionBody(const Section &section) const override
Creates a body for section.
std::string HeaderBody(const Header &header) const override
Creates a body for header.
const std::vector< std::shared_ptr< Element > > GetDaughterElements() const
Get daughter elements.
const Element * GetMother() const
Gets mother element.
const std::string & GetTitle() const
Gets name.
const std::string & GetLabel() const
Gets label.
Figure in the report.
const std::string & GetCaption() const
Gets caption.
const std::vector< Plot > & GetPlots() const
Gets plot vector.
const std::vector< size_t > & GetPlotGrid() const
Gets plot grid.
Header of the report.
const std::vector< std::string > & GetTags() const
Gets tags.
const std::string & GetPageHeader() const
Gets page header.
const std::string & GetTitle() const
Gets title.
const std::string & GetSubtitle() const
Gets subtitle.
const std::string & GetSetup() const
Gets setup.
const std::string & GetAuthor() const
Gets author.
static std::string Apply(std::string_view input)
Applies a LaTeX-friendly formatting.
Section of the report.
int GetLevel() const
Gets level of the section.
Table element in the report.
const std::string & GetColumnTitle(int iCol) const
Gets column title.
int GetNofRows() const
Gets number of rows.
int GetNofCols() const
Gets number of columns.
const std::string & GetCaption() const
Gets caption.
Tail of the report.