Coverage for pesummary/core/webpage/main.py: 88.2%
848 statements
« prev ^ index » next coverage.py v7.4.4, created at 2025-11-05 13:38 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2025-11-05 13:38 +0000
1# Licensed under an MIT style license -- see LICENSE.md
3import os
4import sys
5import uuid
6from glob import glob
7from pathlib import Path
8import shutil
10import numpy as np
11import math
13import pesummary
14from pesummary import conf, __version_string__
15from pesummary.utils.utils import (
16 logger, LOG_FILE, jensen_shannon_divergence_from_pdfs, safe_round, make_dir
17)
18from pesummary.core.webpage import webpage
20__author__ = ["Charlie Hoy <charlie.hoy@ligo.org>"]
23class PlotCaption(object):
24 """Class to handle the generation of a plot caption
26 Parameters
27 ----------
28 plot: str
29 name of the plot you wish to generate a caption for
30 """
31 def __new__(cls, plot="1d_histogram"):
32 super(PlotCaption, cls).__init__(cls)
33 obj = cls.caption(plot)
34 return obj
36 def __init__(self, plot="1d_histogram"):
37 self.plot = plot
39 @staticmethod
40 def caption(plot):
41 if hasattr(conf, "caption_{}".format(plot)):
42 return getattr(conf, "caption_{}".format(plot))
43 return "No caption found for {}".format(plot)
46class _WebpageGeneration(object):
47 """Super class to handle the webpage generation for a given set of result
48 files
50 Parameters
51 ----------
52 savedir: str
53 the directory to store the plots
54 webdir: str
55 the web directory of the run
56 samples: dict
57 dictionary of posterior samples stored in the result files
58 labels: list
59 list of labels used to distinguish the result files
60 publication: Bool
61 Bool to determine the generation of a publication webpage
62 user: str
63 the user that submitted the job
64 config: list
65 list of configuration files used for each result file
66 same_parameters: list
67 list of paramerers that are common in all result files
68 base_url: str
69 the url corresponding to the web directory
70 file_versions: dict
71 dictionary of file versions for each result file
72 hdf5: Bool
73 Bool to determine if the metafile has been saved as hdf5 or not
74 colors: list
75 colors that you wish to use to distinguish different result files
76 custom_plotting:
77 existing_labels: list
78 list of labels stored in an existing metafile
79 existing_config: list
80 list of configuration files stored in the existing metafile
81 existing_file_version: dict
82 dictionary of file versions stored in the existing metafile
83 existing_injection_data: dict
84 dictionary of injection data stored in an existing metafile
85 existing_samples: dict
86 dictionary of posterior samples stored in an existing metafile
87 existing_metafile: str
88 path to the existing metafile
89 existing_file_kwargs: dict
90 dictionary of file kwargs stored in an existing metafile
91 add_to_existing: Bool
92 Bool to determine if you wish to add to an existing webpage
93 notes: str
94 notes that you wish to put on the webpages
95 disable_comparison: bool
96 Whether to make comparison pages
97 package_information: dict
98 dictionary of package information
99 mcmc_samples: Bool
100 Whether or not mcmc samples have been passed
101 """
102 def __init__(
103 self, webdir=None, samples=None, labels=None, publication=None,
104 user=None, config=None, same_parameters=None, base_url=None,
105 file_versions=None, hdf5=None, colors=None, custom_plotting=None,
106 existing_labels=None, existing_config=None, existing_file_version=None,
107 existing_injection_data=None, existing_samples=None,
108 existing_metafile=None, existing_file_kwargs=None,
109 existing_weights=None, add_to_existing=False, notes=None,
110 disable_comparison=False, disable_interactive=False,
111 package_information={"packages": [], "manager": "pypi"},
112 mcmc_samples=False, external_hdf5_links=False, key_data=None,
113 existing_plot=None, disable_expert=False, analytic_priors=None,
114 ):
115 self.webdir = webdir
116 make_dir(self.webdir)
117 make_dir(os.path.join(self.webdir, "html"))
118 make_dir(os.path.join(self.webdir, "css"))
119 self.samples = samples
120 self.labels = labels
121 self.publication = publication
122 self.user = user
123 self.config = config
124 self.same_parameters = same_parameters
125 self.base_url = base_url
126 self.file_versions = file_versions
127 if self.file_versions is None:
128 self.file_versions = {
129 label: "No version information found" for label in self.labels
130 }
131 self.hdf5 = hdf5
132 self.colors = colors
133 if self.colors is None:
134 self.colors = list(conf.colorcycle)
135 self.custom_plotting = custom_plotting
136 self.existing_labels = existing_labels
137 self.existing_config = existing_config
138 self.existing_file_version = existing_file_version
139 self.existing_samples = existing_samples
140 self.existing_metafile = existing_metafile
141 self.existing_file_kwargs = existing_file_kwargs
142 self.add_to_existing = add_to_existing
143 self.analytic_priors = analytic_priors
144 if self.analytic_priors is None:
145 self.analytic_priors = {label: None for label in self.samples.keys()}
146 self.key_data = key_data
147 _label = self.labels[0]
148 if self.samples is not None:
149 if key_data is None:
150 self.key_data = {
151 label: _samples.key_data for label, _samples in
152 self.samples.items()
153 }
154 self.key_data_headings = sorted(
155 list(self.key_data[_label][list(self.samples[_label].keys())[0]])
156 )
157 self.key_data_table = {
158 label: {
159 param: [
160 safe_round(self.key_data[label][param].get(key, None), 3) for key
161 in self.key_data_headings
162 ] for param in self.samples[label].keys()
163 } for label in self.labels
164 }
165 self.notes = notes
166 self.make_interactive = not disable_interactive
167 self.package_information = package_information
168 self.mcmc_samples = mcmc_samples
169 self.external_hdf5_links = external_hdf5_links
170 self.existing_plot = existing_plot
171 self.expert_plots = not disable_expert
172 self.make_comparison = (
173 not disable_comparison and self._total_number_of_labels > 1
174 )
175 self.preliminary_pages = {label: False for label in self.labels}
176 self.all_pages_preliminary = False
177 if self.add_to_existing:
178 self.add_existing_data()
179 self._additional_1d_pages = {label: [] for label in self.labels}
180 if self.additional_1d_pages is not None:
181 for j, _parameters in self.additional_1d_pages.items():
182 for i in self.labels:
183 if all(
184 param in self.samples[i].keys() for param in
185 _parameters
186 ):
187 self._additional_1d_pages[i].append(j)
188 self.categories = self.default_categories()
189 self.popular_options = self.default_popular_options()
190 self.navbar = {
191 "home": self.make_navbar_for_homepage(),
192 "result_page": self.make_navbar_for_result_page(),
193 "comparison": self.make_navbar_for_comparison_page()
194 }
195 self.image_path = {
196 "home": os.path.join(".", "plots", ""),
197 "other": os.path.join("..", "plots", "")
198 }
199 self.results_path = {
200 "home": "./samples/", "other": "../samples/"
201 }
202 self.config_path = {
203 "home": "./config/", "other": "../config/"
204 }
205 if self.make_comparison:
206 try:
207 self.comparison_stats = self.generate_comparison_statistics()
208 except Exception as e:
209 self.comparison_stats = None
210 logger.info(
211 "Failed to generate comparison statistics because {}. As a "
212 "result they will not be added to the webpages".format(e)
213 )
215 @property
216 def _metafile(self):
217 return (
218 "posterior_samples.json" if not self.hdf5 else
219 "posterior_samples.h5"
220 )
222 @property
223 def _total_number_of_labels(self):
224 _number_of_labels = 0
225 for item in [self.labels, self.existing_labels]:
226 if isinstance(item, list):
227 _number_of_labels += len(item)
228 return _number_of_labels
230 def copy_css_and_js_scripts(self):
231 """Copy css and js scripts from the package to the web directory
232 """
233 import shutil
234 from pesummary import core
235 files_to_copy = []
236 path = core.__path__[0]
237 scripts = glob(os.path.join(path, "js", "*.js"))
238 for i in scripts:
239 files_to_copy.append(
240 [i, os.path.join(self.webdir, "js", os.path.basename(i))]
241 )
242 scripts = glob(os.path.join(path, "css", "*.css"))
243 for i in scripts:
244 files_to_copy.append(
245 [i, os.path.join(self.webdir, "css", os.path.basename(i))]
246 )
247 for _dir in ["js", "css"]:
248 try:
249 os.mkdir(os.path.join(self.webdir, _dir))
250 except FileExistsError:
251 pass
252 for ff in files_to_copy:
253 shutil.copy(ff[0], ff[1])
255 def make_modal_carousel(
256 self, html_file, image_contents, unique_id=False, **kwargs
257 ):
258 """Make a modal carousel for a table of images
260 Parameters
261 ----------
262 html_file: pesummary.core.webpage.webpage.page
263 open html file
264 image_contents: list
265 list of images to place in a table
266 unique_id: Bool, optional
267 if True, assign a unique identifer to the modal
268 **kwargs: dict, optional
269 all additional kwargs passed to `make_table_of_images` function
270 """
271 if unique_id:
272 unique_id = '{}'.format(uuid.uuid4().hex.upper()[:6])
273 else:
274 unique_id = None
275 html_file.make_table_of_images(
276 contents=image_contents, unique_id=unique_id, **kwargs
277 )
278 images = [y for x in image_contents for y in x]
279 html_file.make_modal_carousel(images=images, unique_id=unique_id)
280 return html_file
282 def generate_comparison_statistics(self):
283 """Generate comparison statistics for all parameters that are common to
284 all result files
285 """
286 data = {
287 i: self._generate_comparison_statistics(
288 i, [self.samples[j][i] for j in self.labels]
289 ) for i in self.same_parameters
290 }
291 return data
293 def _generate_comparison_statistics(self, param, samples):
294 """Generate comparison statistics for a set of samples
296 Parameters
297 ----------
298 samples: list
299 list of samples for each result file
300 """
301 from pesummary.utils.utils import kolmogorov_smirnov_test
303 rows = range(len(samples))
304 columns = range(len(samples))
305 ks = [
306 [
307 kolmogorov_smirnov_test([samples[i], samples[j]]) for i in
308 rows
309 ] for j in columns
310 ]
311 # JS divergence is symmetric and therefore we just need to loop over
312 # one triangle
313 js = np.zeros((len(samples), len(samples)))
314 pdfs = self._kde_from_same_samples(param, samples)
315 for num, i in enumerate(range(1, len(js))):
316 for idx, j in enumerate(range(0, i)):
317 js[i][idx] += jensen_shannon_divergence_from_pdfs(
318 [pdfs[i], pdfs[j]]
319 )
320 js = js + js.T
321 return [ks, js.tolist()]
323 def _kde_from_same_samples(self, param, samples, **kwargs):
324 """Generate KDEs for a set of samples
326 Parameters
327 ----------
328 param: str
329 The parameter that the samples belong to
330 samples: list
331 list of samples for each result file
332 """
333 from pesummary.utils.utils import samples_to_kde
334 return samples_to_kde(samples, **kwargs)
336 @staticmethod
337 def get_executable(executable):
338 """Return the path to an executable
340 Parameters
341 ----------
342 executable: str
343 the name of the executable you wish to find
344 """
345 return shutil.which(
346 executable,
347 path=os.pathsep.join((
348 os.getenv("PATH", ""),
349 str(Path(sys.executable).parent),
350 )),
351 )
353 def _result_page_links(self):
354 """Return the navbar structure for the Result Page tab.
355 """
356 return [{i: i} for i in self.labels]
358 def make_navbar_for_homepage(self):
359 """Make a navbar for the homepage
360 """
361 links = [
362 "home", ["Result Pages", self._result_page_links()], "Logging",
363 "Version"
364 ]
365 if self.make_comparison:
366 links[1][1] += ["Comparison"]
367 if self.publication:
368 links.insert(2, "Publication")
369 if self.notes is not None:
370 links.append("Notes")
371 return links
373 def make_navbar_for_result_page(self):
374 """Make a navbar for the result page homepage
375 """
376 links = {
377 i: ["1d Histograms", [{"Custom": i}, {"All": i}]] for i in
378 self.labels
379 }
380 for num, label in enumerate(self.labels):
381 _params = list(self.samples[label].keys())
382 if len(self._additional_1d_pages[label]):
383 _params += self._additional_1d_pages[label]
384 for j in self.categorize_parameters(_params):
385 j = [j[0], [{k: label} for k in j[1]]]
386 links[label].append(j)
388 final_links = {
389 i: [
390 "home", ["Result Pages", self._result_page_links()],
391 {"Corner": i}, {"Config": i}, links[i]
392 ] for i in self.labels
393 }
394 if self.make_comparison:
395 for label in self.labels:
396 final_links[label][1][1] += ["Comparison"]
397 _dummy_label = self.labels[0]
398 if len(final_links[_dummy_label][1][1]) > 1:
399 for label in self.labels:
400 _options = [{l: "switch"} for l in self.labels if l != label]
401 if self.make_comparison:
402 _options.append({"Comparison": "switch"})
403 final_links[label].append(["Switch", _options])
404 if self.make_interactive:
405 for label in self.labels:
406 final_links[label].append(
407 ["Interactive", [{"Interactive_Corner": label}]]
408 )
409 if self.existing_plot is not None:
410 for _label in self.labels:
411 if _label in self.existing_plot.keys():
412 final_links[_label].append(
413 {"Additional": _label}
414 )
415 return final_links
417 def make_navbar_for_comparison_page(self):
418 """Make a navbar for the comparison homepage
419 """
420 if self.same_parameters is not None:
421 links = ["1d Histograms", ["Custom", "All"]]
422 for i in self.categorize_parameters(self.same_parameters):
423 links.append(i)
424 final_links = [
425 "home", ["Result Pages", self._result_page_links()], links
426 ]
427 final_links[1][1] += ["Comparison"]
428 final_links.append(
429 ["Switch", [{l: "switch"} for l in self.labels]]
430 )
431 if self.make_interactive:
432 final_links.append(
433 ["Interactive", ["Interactive_Ridgeline"]]
434 )
435 return final_links
436 return None
438 def categorize_parameters(
439 self, parameters, starting_letter=True, heading_all=True
440 ):
441 """Categorize the parameters into common headings
443 Parameters
444 ----------
445 parameters: list
446 list of parameters that you would like to sort
447 """
448 params = []
449 for heading, category in self.categories.items():
450 if any(
451 any(i[0] in j for j in category["accept"]) for i in parameters
452 ):
453 cond = self._condition(
454 category["accept"], category["reject"],
455 starting_letter=starting_letter
456 )
457 part = self._partition(cond, parameters)
458 if heading_all and len(part):
459 part = ["{}_all".format(heading)] + part
460 params.append([heading, part])
461 used_headings = [i[0] for i in params]
462 other_index = \
463 used_headings.index("others") if "others" in used_headings else None
464 other_params = []
465 for pp in parameters:
466 if not any(pp in j[1] for j in params):
467 if other_index is not None:
468 params[other_index][1].append(pp)
469 else:
470 other_params.append(pp)
471 if other_index is None:
472 params.append(["others", other_params])
473 return params
475 def _condition(self, true, false, starting_letter=False):
476 """Setup a condition
478 Parameters
479 ----------
480 true: list
481 list of strings that you would like to include
482 false: list
483 list of strings that you would like to neglect
484 """
485 def _starting_letter(param, condition):
486 if condition:
487 return param[0]
488 return param
489 if len(true) != 0 and len(false) == 0:
490 condition = lambda j: True if any(
491 i in _starting_letter(j, starting_letter) for i in true
492 ) else False
493 elif len(true) == 0 and len(false) != 0:
494 condition = lambda j: True if any(
495 i not in _starting_letter(j, starting_letter) for i in false
496 ) else False
497 elif len(true) and len(false) != 0:
498 condition = lambda j: True if any(
499 i in _starting_letter(j, starting_letter) and all(
500 k not in _starting_letter(j, starting_letter) for k in false
501 ) for i in true
502 ) else False
503 return condition
505 def _partition(self, condition, array):
506 """Filter the list according to a condition
508 Parameters
509 ----------
510 condition: func
511 lambda function containing the condition that you want to use to
512 filter the array
513 array: list
514 List of parameters that you would like to filter
515 """
516 return sorted(list(filter(condition, array)))
518 def generate_webpages(self):
519 """Generate all webpages for all result files passed
520 """
521 self.make_home_pages()
522 self.make_1d_histogram_pages()
523 self.make_corner_pages()
524 self.make_config_pages()
525 if self.make_comparison:
526 self.make_comparison_pages()
527 if self.make_interactive:
528 self.make_interactive_pages()
529 if self.existing_plot is not None:
530 self.make_additional_plots_pages()
531 self.make_error_page()
532 self.make_version_page()
533 self.make_logging_page()
534 if self.notes is not None:
535 self.make_notes_page()
536 self.make_downloads_page()
537 self.make_about_page()
538 try:
539 self.generate_specific_javascript()
540 except Exception:
541 pass
543 def create_blank_html_pages(self, pages, stylesheets=[]):
544 """Create blank html pages
546 Parameters
547 ----------
548 pages: list
549 list of pages that you wish to create
550 """
551 webpage.make_html(
552 web_dir=self.webdir, pages=pages, stylesheets=stylesheets
553 )
555 def setup_page(
556 self, html_page, links, label=None, title=None, approximant=None,
557 background_colour=None, histogram_download=False, toggle=False
558 ):
559 """Set up each webpage with a header and navigation bar.
561 Parameters
562 ----------
563 html_page: str
564 String containing the html page that you would like to set up
565 links: list
566 List containing the navbar structure that you would like to include
567 label: str, optional
568 The label that prepends your webpage name
569 title: str, optional
570 String that you would like to include in your header
571 approximant: str, optional
572 The approximant that you would like associated with your html_page
573 background_colour: str, optional
574 String containing the background colour of your header
575 histogram_download: bool, optional
576 If true, a download link for the each histogram is displayed in
577 the navbar
578 """
579 html_file = webpage.open_html(
580 web_dir=self.webdir, base_url=self.base_url, html_page=html_page,
581 label=label
582 )
583 _preliminary_keys = self.preliminary_pages.keys()
584 if self.all_pages_preliminary:
585 html_file.make_watermark()
586 elif approximant is not None and approximant in _preliminary_keys:
587 if self.preliminary_pages[approximant]:
588 html_file.make_watermark()
590 html_file.make_header(approximant=approximant)
591 if html_page == "home" or html_page == "home.html":
592 html_file.make_navbar(
593 links=links, samples_path=self.results_path["home"],
594 background_color=background_colour,
595 hdf5=self.hdf5, toggle=toggle
596 )
597 elif histogram_download:
598 html_file.make_navbar(
599 links=links, samples_path=self.results_path["other"],
600 toggle=toggle, histogram_download=os.path.join(
601 "..", "samples", "dat", label, "{}_{}_samples.dat".format(
602 label, html_page
603 )
604 ), background_color=background_colour, hdf5=self.hdf5
605 )
606 else:
607 html_file.make_navbar(
608 links=links, samples_path=self.results_path["home"],
609 background_color=background_colour, hdf5=self.hdf5,
610 toggle=toggle
611 )
612 return html_file
614 def make_home_pages(self):
615 """Wrapper function for _make_home_pages()
616 """
617 pages = ["{}_{}".format(i, i) for i in self.labels]
618 pages.append("home")
619 self.create_blank_html_pages(pages)
620 self._make_home_pages(pages)
622 def _make_home_pages(
623 self, pages, title=None, banner="Summary", make_home=True,
624 make_result=True, return_html=False
625 ):
626 """Make the home pages
628 Parameters
629 ----------
630 pages: list
631 list of pages that you wish to create
632 """
633 if make_home:
634 html_file = self.setup_page("home", self.navbar["home"], title=title)
635 html_file.make_banner(approximant=banner, key="Summary")
636 if return_html:
637 return html_file
638 if not make_result:
639 return
641 for num, i in enumerate(self.labels):
642 html_file = self.setup_page(
643 i, self.navbar["result_page"][i], i, approximant=i,
644 title="{} Summary page".format(i),
645 background_colour=self.colors[num]
646 )
647 images, cli, captions = self.default_images_for_result_page(i)
648 _images_available = [
649 item for sublist in images for item in sublist if os.path.isfile(
650 item.replace(
651 self.image_path["other"], "{}/plots/".format(self.webdir)
652 )
653 )
654 ]
655 if len(_images_available) > 2:
656 html_file.make_banner(approximant=i, key=i)
657 html_file = self.make_modal_carousel(
658 html_file, images, cli=cli, unique_id=True,
659 captions=captions, autoscale=True
660 )
661 else:
662 html_file.make_banner(approximant=i, key="custom", custom="")
664 if self.custom_plotting:
665 custom_plots = glob(
666 "{}/plots/{}_custom_plotting_*".format(self.webdir, i)
667 )
668 path = self.image_path["other"]
669 for num, i in enumerate(custom_plots):
670 custom_plots[num] = path + i.split("/")[-1]
671 image_contents = [
672 custom_plots[i:4 + i] for i in range(
673 0, len(custom_plots), 4
674 )
675 ]
676 html_file = self.make_modal_carousel(
677 html_file, image_contents, unique_id=True
678 )
680 html_file.make_banner(
681 approximant="Summary Table", key="summary_table",
682 _style="font-size: 26px;"
683 )
684 _style = "margin-top:3em; margin-bottom:5em; max-width:1400px"
685 _class = "row justify-content-center"
686 html_file.make_container(style=_style)
687 html_file.make_div(4, _class=_class, _style=None)
689 key_data = self.key_data
690 contents = []
691 headings = [" "] + self.key_data_headings.copy()
692 _injection = False
693 if "injected" in headings:
694 _injection = not all(
695 math.isnan(_data["injected"]) for _data in
696 self.key_data[i].values()
697 )
698 if _injection:
699 headings.append("injected")
700 for j in self.samples[i].keys():
701 row = []
702 row.append(j)
703 row += self.key_data_table[i][j]
704 if _injection:
705 row.append(safe_round(self.key_data[i][j]["injected"], 3))
706 contents.append(row)
708 html_file.make_table(
709 headings=headings, contents=contents, heading_span=1,
710 accordian=False, format="table-hover header-fixed",
711 sticky_header=True
712 )
713 html_file.end_div(4)
714 html_file.end_container()
715 html_file.export(
716 "summary_information_{}.csv".format(i)
717 )
718 html_file.make_footer(user=self.user, rundir=self.webdir)
719 html_file.close()
721 def make_1d_histogram_pages(self):
722 """Wrapper function for _make_1d_histogram pages
723 """
724 pages = [
725 "{}_{}_{}".format(i, i, j) for i in self.labels for j in
726 self.samples[i].keys()
727 ]
728 pages += ["{}_{}_Custom".format(i, i) for i in self.labels]
729 pages += ["{}_{}_All".format(i, i) for i in self.labels]
730 for i in self.labels:
731 if len(self._additional_1d_pages[i]):
732 pages += [
733 "{}_{}_{}".format(i, i, j) for j in
734 self._additional_1d_pages[i]
735 ]
736 pages += [
737 "{}_{}_{}_all".format(i, i, j[0]) for i in self.labels for j in
738 self.categorize_parameters(self.samples[i].keys()) if len(j[1])
739 ]
740 self.create_blank_html_pages(pages)
741 self._make_1d_histogram_pages(pages)
743 def _make_1d_histogram_pages(self, pages):
744 """Make the 1d histogram pages
746 Parameters
747 ----------
748 pages: list
749 list of pages that you wish to create
750 """
751 for num, i in enumerate(self.labels):
752 if len(self._additional_1d_pages[i]):
753 for j in self._additional_1d_pages[i]:
754 _parameters = self.additional_1d_pages[j]
755 html_file = self.setup_page(
756 "{}_{}".format(i, j), self.navbar["result_page"][i],
757 i, title="{} Posterior PDFs describing {}".format(i, j),
758 approximant=i, background_colour=self.colors[num],
759 histogram_download=False, toggle=self.expert_plots
760 )
761 html_file.make_banner(approximant=i, key=i)
762 path = self.image_path["other"]
763 _plots = [
764 path + "{}_1d_posterior_{}.png".format(i, param) for
765 param in _parameters
766 ]
767 contents = [
768 _plots[i:2 + i] for i in range(0, len(_plots), 2)
769 ]
770 html_file.make_table_of_images(
771 contents=contents, code="changeimage",
772 mcmc_samples=self.mcmc_samples, autoscale=True
773 )
774 key_data = self.key_data
775 contents = []
776 headings = [" "] + self.key_data_headings.copy()
777 _injection = False
778 rows = []
779 for param in _parameters:
780 _row = [param]
781 _row += self.key_data_table[i][param]
782 rows.append(_row)
783 _style = "margin-top:3em; margin-bottom:5em; max-width:1400px"
784 _class = "row justify-content-center"
785 html_file.make_container(style=_style)
786 html_file.make_div(4, _class=_class, _style=None)
787 html_file.make_table(
788 headings=headings, contents=rows, heading_span=1,
789 accordian=False, format="table-hover"
790 )
791 html_file.end_div(4)
792 html_file.end_container()
793 html_file.export("summary_information_{}.csv".format(i))
794 html_file.make_footer(user=self.user, rundir=self.webdir)
795 html_file.close()
796 for j in self.samples[i].keys():
797 html_file = self.setup_page(
798 "{}_{}".format(i, j), self.navbar["result_page"][i],
799 i, title="{} Posterior PDF for {}".format(i, j),
800 approximant=i, background_colour=self.colors[num],
801 histogram_download=False, toggle=self.expert_plots
802 )
803 if j.description != "Unknown parameter description":
804 _custom = (
805 "The figures below show the plots for {}: {}"
806 )
807 html_file.make_banner(
808 approximant=i, key="custom",
809 custom=_custom.format(j, j.description)
810 )
811 else:
812 html_file.make_banner(approximant=i, key=i)
813 path = self.image_path["other"]
814 contents = [
815 [path + "{}_1d_posterior_{}.png".format(i, j)],
816 [
817 path + "{}_sample_evolution_{}.png".format(i, j),
818 path + "{}_autocorrelation_{}.png".format(i, j)
819 ]
820 ]
821 captions = [
822 [PlotCaption("1d_histogram").format(j)],
823 [
824 PlotCaption("sample_evolution").format(j),
825 PlotCaption("autocorrelation").format(j)
826 ]
827 ]
828 html_file.make_table_of_images(
829 contents=contents, rows=1, columns=2, code="changeimage",
830 captions=captions, mcmc_samples=self.mcmc_samples
831 )
832 contents = [
833 [path + "{}_2d_contour_{}_log_likelihood.png".format(i, j)],
834 [
835 path + "{}_sample_evolution_{}_{}_colored.png".format(
836 i, j, "log_likelihood"
837 ), path + "{}_1d_posterior_{}_bootstrap.png".format(i, j)
838 ]
839 ]
840 captions = [
841 [PlotCaption("2d_contour").format(j, "log_likelihood")],
842 [
843 PlotCaption("sample_evolution_colored").format(
844 j, "log_likelihood"
845 ),
846 PlotCaption("1d_histogram_bootstrap").format(100, j, 1000)
847 ],
848 ]
849 if self.expert_plots:
850 html_file.make_table_of_images(
851 contents=contents, rows=1, columns=2, code="changeimage",
852 captions=captions, mcmc_samples=self.mcmc_samples,
853 display='none', container_id='expert_div',
854 close_container=False
855 )
856 _additional = self.add_to_expert_pages(path, i)
857 if _additional is not None and j in _additional.keys():
858 html_file.make_table_of_images(
859 contents=_additional[j], code="changeimage",
860 mcmc_samples=self.mcmc_samples,
861 autoscale=True, display='none',
862 add_to_open_container=True,
863 )
864 html_file.end_div()
865 html_file.export(
866 "", csv=False, json=False, shell=False, margin_bottom="1em",
867 histogram_dat=os.path.join(
868 self.results_path["other"], i, "{}_{}.dat".format(i, j)
869 )
870 )
871 key_data = self.key_data
872 contents = []
873 headings = self.key_data_headings.copy()
874 _injection = False
875 if "injected" in headings:
876 _injection = not math.isnan(self.key_data[i][j]["injected"])
877 row = self.key_data_table[i][j]
878 if _injection:
879 headings.append("injected")
880 row.append(safe_round(self.key_data[i][j]["injected"], 3))
881 _style = "margin-top:3em; margin-bottom:5em; max-width:1400px"
882 _class = "row justify-content-center"
883 html_file.make_container(style=_style)
884 html_file.make_div(4, _class=_class, _style=None)
885 html_file.make_table(
886 headings=headings, contents=[row], heading_span=1,
887 accordian=False, format="table-hover"
888 )
889 html_file.end_div(4)
890 html_file.end_container()
891 html_file.export(
892 "summary_information_{}.csv".format(i)
893 )
894 html_file.make_footer(user=self.user, rundir=self.webdir)
895 html_file.close()
896 html_file = self.setup_page(
897 "{}_Custom".format(i), self.navbar["result_page"][i],
898 i, title="{} Posteriors for multiple".format(i),
899 approximant=i, background_colour=self.colors[num]
900 )
901 html_file.make_banner(approximant=i, key=i)
902 ordered_parameters = self.categorize_parameters(
903 self.samples[i].keys()
904 )
905 ordered_parameters = [i for j in ordered_parameters for i in j[1]]
906 popular_options = self.popular_options
907 html_file.make_search_bar(
908 sidebar=[i for i in self.samples[i].keys()],
909 popular_options=popular_options + [{
910 "all": ", ".join(ordered_parameters)
911 }],
912 label=self.labels[num], code="combines"
913 )
914 html_file.make_footer(user=self.user, rundir=self.webdir)
915 html_file.close()
916 html_file = self.setup_page(
917 "{}_All".format(i), self.navbar["result_page"][i],
918 i, title="All posteriors for {}".format(i),
919 approximant=i, background_colour=self.colors[num]
920 )
921 html_file.make_banner(approximant=i, key=i)
922 for j in self.samples[i].keys():
923 html_file.make_banner(
924 approximant=j, _style="font-size: 26px;"
925 )
926 contents = [
927 [path + "{}_1d_posterior_{}.png".format(i, j)],
928 [
929 path + "{}_sample_evolution_{}.png".format(i, j),
930 path + "{}_autocorrelation_{}.png".format(i, j)
931 ]
932 ]
933 html_file.make_table_of_images(
934 contents=contents, rows=1, columns=2, code="changeimage")
935 html_file.close()
936 for j in self.categorize_parameters(self.samples[i].keys()):
937 if not len(j[1]):
938 continue
939 html_file = self.setup_page(
940 "{}_{}_all".format(i, j[0]), self.navbar["result_page"][i],
941 i, title="All posteriors for describing {}".format(j[0]),
942 approximant=i, background_colour=self.colors[num]
943 )
944 for k in j[1][1:]:
945 html_file.make_banner(
946 approximant=k, _style="font-size: 26px;"
947 )
948 contents = [
949 [path + "{}_1d_posterior_{}.png".format(i, k)],
950 [
951 path + "{}_sample_evolution_{}.png".format(i, k),
952 path + "{}_autocorrelation_{}.png".format(i, k)
953 ]
954 ]
955 html_file.make_table_of_images(
956 contents=contents, rows=1, columns=2, code="changeimage"
957 )
958 html_file.make_banner(
959 approximant="Summary Table", key="summary_table",
960 _style="font-size: 26px;"
961 )
962 _style = "margin-top:3em; margin-bottom:5em; max-width:1400px"
963 _class = "row justify-content-center"
964 html_file.make_container(style=_style)
965 html_file.make_div(4, _class=_class, _style=None)
966 headings = [" "] + self.key_data_headings.copy()
967 contents = []
968 for k in j[1][1:]:
969 row = [k]
970 row += self.key_data_table[i][k]
971 contents.append(row)
972 html_file.make_table(
973 headings=headings, contents=contents, heading_span=1,
974 accordian=False, format="table-hover",
975 sticky_header=True
976 )
977 html_file.end_div(4)
978 html_file.end_container()
979 html_file.export("{}_summary_{}.csv".format(j[0], i))
980 html_file.make_footer(user=self.user, rundir=self.webdir)
981 html_file.close()
983 def make_additional_plots_pages(self):
984 """Wrapper function for _make_additional_plots_pages
985 """
986 pages = [
987 "{}_{}_Additional".format(i, i) for i in self.labels if i in
988 self.existing_plot.keys()
989 ]
990 self.create_blank_html_pages(pages)
991 self._make_additional_plots_pages(pages)
993 def _make_additional_plots_pages(self, pages):
994 """Make the additional plots pages
996 Parameters
997 ----------
998 pages: list
999 list of pages that you wish to create
1000 """
1001 from PIL import Image
1002 for num, i in enumerate(self.labels):
1003 if i not in self.existing_plot.keys():
1004 continue
1005 html_file = self.setup_page(
1006 "{}_Additional".format(i), self.navbar["result_page"][i], i,
1007 title="Additional plots for {}".format(i), approximant=i,
1008 background_colour=self.colors[num]
1009 )
1010 html_file.make_banner(approximant=i, key="additional")
1011 if isinstance(self.existing_plot[i], list):
1012 images = sorted(
1013 self.existing_plot[i],
1014 key=lambda _path: Image.open(_path).size[1]
1015 )
1016 tol = 2.
1017 # if all images are of similar height, then grid them uniformly, else
1018 # grid by heights
1019 cond = all(
1020 Image.open(_path).size[1] / tol < Image.open(images[0]).size[1]
1021 for _path in images
1022 )
1023 if cond:
1024 image_contents = [
1025 [
1026 self.image_path["other"] + Path(_path).name for
1027 _path in images[j:4 + j]
1028 ] for j in range(0, len(self.existing_plot[i]), 4)
1029 ]
1030 else:
1031 heights = [Image.open(_path).size[1] for _path in images]
1032 image_contents = [
1033 [self.image_path["other"] + Path(images[0]).name]
1034 ]
1035 row = 0
1036 for num, _height in enumerate(heights[1:]):
1037 if _height / tol < heights[num]:
1038 image_contents[row].append(
1039 self.image_path["other"] + Path(images[num + 1]).name
1040 )
1041 else:
1042 row += 1
1043 image_contents.append(
1044 [self.image_path["other"] + Path(images[num + 1]).name]
1045 )
1046 margin_left = None
1047 else:
1048 image_contents = [
1049 [self.image_path["other"] + Path(self.existing_plot[i]).name]
1050 ]
1051 margin_left = "-250px"
1052 html_file = self.make_modal_carousel(
1053 html_file, image_contents, unique_id=True, autoscale=True,
1054 margin_left=margin_left
1055 )
1056 html_file.make_footer(user=self.user, rundir=self.webdir)
1057 html_file.close()
1059 def make_corner_pages(self):
1060 """Wrapper function for _make_corner_pages
1061 """
1062 pages = ["{}_{}_Corner".format(i, i) for i in self.labels]
1063 self.create_blank_html_pages(pages)
1064 self._make_corner_pages(pages)
1066 def _make_corner_pages(self, pages):
1067 """Make the corner pages
1069 Parameters
1070 ----------
1071 pages: list
1072 list of pages that you wish to create
1073 """
1074 for num, i in enumerate(self.labels):
1075 html_file = self.setup_page(
1076 "{}_Corner".format(i), self.navbar["result_page"][i], i,
1077 title="{} Corner Plots".format(i), approximant=i,
1078 background_colour=self.colors[num]
1079 )
1080 html_file.make_banner(approximant=i, key="corner")
1081 popular_options = self.popular_options
1082 if len(self.default_corner_params()):
1083 params = self.default_corner_params()
1084 included_parameters = [
1085 i for i in list(self.samples[i].keys()) if i in params
1086 ]
1087 popular_options += [{
1088 "all": ", ".join(included_parameters)
1089 }]
1090 else:
1091 included_parameters = list(self.samples[i].keys())
1092 html_file.make_search_bar(
1093 sidebar=included_parameters,
1094 popular_options=popular_options, label=i
1095 )
1096 html_file.make_footer(user=self.user, rundir=self.webdir)
1097 html_file.close()
1099 def make_config_pages(self):
1100 """Wrapper function for _make_config_pages
1101 """
1102 pages = ["{}_{}_Config".format(i, i) for i in self.labels]
1103 self.create_blank_html_pages(pages, stylesheets=pages)
1104 self._make_config_pages(pages)
1106 def _make_config_pages(self, pages):
1107 """Make the config pages
1109 Parameters
1110 ----------
1111 pages: list
1112 list of pages that you wish to create
1113 """
1114 for num, i in enumerate(self.labels):
1115 html_file = self.setup_page(
1116 "{}_Config".format(i), self.navbar["result_page"][i], i,
1117 title="{} Configuration".format(i), approximant=i,
1118 background_colour=self.colors[num]
1119 )
1120 html_file.make_banner(approximant=i, key="config")
1121 if self.config and num < len(self.config) and self.config[num]:
1122 with open(self.config[num], 'r') as f:
1123 contents = f.read()
1124 html_file.make_container()
1125 styles = html_file.make_code_block(
1126 language='ini', contents=contents
1127 )
1128 html_file.end_container()
1129 with open(
1130 "{0:s}/css/{1:s}_{2:s}_Config.css".format(
1131 self.webdir, i, i
1132 ), "w"
1133 ) as f:
1134 f.write(styles)
1135 _fix = False
1136 else:
1137 html_file.add_content(
1138 "<div class='row justify-content-center'; "
1139 "style='font-family: Arial-body; font-size: 14px'>"
1140 "<p style='margin-top:2.5em'> No configuration file was "
1141 "provided </p></div>"
1142 )
1143 _fix = True
1144 if i in self.analytic_priors.keys():
1145 if self.analytic_priors[i] is not None:
1146 html_file.make_div(indent=2, _class='paragraph')
1147 html_file.add_content(
1148 "Below is the prior file for %s" % (i)
1149 )
1150 html_file.end_div()
1151 html_file.make_container()
1152 styles = html_file.make_code_block(
1153 language='ini', contents=self.analytic_priors[i]
1154 )
1155 html_file.end_container()
1156 _fix = False
1157 html_file.make_footer(
1158 user=self.user, rundir=self.webdir, fix_bottom=_fix
1159 )
1160 html_file.close()
1162 def make_comparison_pages(self):
1163 """Wrapper function for _make_comparison_pages
1164 """
1165 pages = ["Comparison_{}".format(i) for i in self.same_parameters]
1166 pages += ["Comparison_Custom"]
1167 pages += ["Comparison_All"]
1168 pages += ["Comparison"]
1169 pages += [
1170 "Comparison_{}_all".format(j[0]) for j in
1171 self.categorize_parameters(self.same_parameters) if len(j[1])
1172 ]
1173 self.create_blank_html_pages(pages)
1174 self._make_comparison_pages(pages)
1176 def _make_comparison_pages(self, pages):
1177 """Make pages to compare all result files
1179 Parameters
1180 ----------
1181 pages: list
1182 list of pages that you wish to create
1183 """
1184 html_file = self.setup_page(
1185 "Comparison", self.navbar["comparison"], approximant="Comparison",
1186 title="Comparison Summary Page"
1187 )
1188 html_file.make_banner(approximant="Comparison", key="Comparison")
1189 path = self.image_path["other"]
1190 if len(self.default_comparison_homepage_plots()):
1191 contents = self.default_comparison_homepage_plots()
1192 html_file = self.make_modal_carousel(
1193 html_file, contents, unique_id=True
1194 )
1195 if self.custom_plotting:
1196 from glob import glob
1198 custom_plots = glob(
1199 os.path.join(
1200 self.webdir, "plots", "combined_custom_plotting_*"
1201 )
1202 )
1203 for num, i in enumerate(custom_plots):
1204 custom_plots[num] = path + i.split("/")[-1]
1205 image_contents = [
1206 custom_plots[i:4 + i] for i in range(0, len(custom_plots), 4)
1207 ]
1208 html_file = self.make_modal_carousel(
1209 html_file, image_contents, unique_id=True
1210 )
1211 path = self.image_path["other"]
1213 if self.comparison_stats is not None:
1214 for _num, _key in enumerate(["KS_test", "JS_test"]):
1215 if _key == "KS_test":
1216 html_file.make_banner(
1217 approximant="KS test", key="ks_test",
1218 _style="font-size: 26px;"
1219 )
1220 else:
1221 html_file.make_banner(
1222 approximant="JS test", key="js_test",
1223 _style="font-size: 26px;"
1224 )
1225 _style = "margin-top:3em; margin-bottom:5em; max-width:1400px"
1226 _class = "row justify-content-center"
1227 html_file.make_container(style=_style)
1228 html_file.make_div(4, _class=_class, _style=None)
1230 rows = range(len(self.labels))
1231 table_contents = {
1232 i: [
1233 [self.labels[j]] + self.comparison_stats[i][_num][j] for
1234 j in rows
1235 ] for i in self.same_parameters
1236 }
1237 _headings = [" "] + self.labels
1238 html_file.make_table(
1239 headings=_headings, format="table-hover scroll-table",
1240 heading_span=1, contents=table_contents, accordian=False,
1241 scroll_table=True
1242 )
1243 html_file.end_div(4)
1244 html_file.end_container()
1245 html_file.export("{}_total.csv".format(_key))
1246 html_file.make_footer(user=self.user, rundir=self.webdir)
1248 for num, i in enumerate(self.same_parameters):
1249 html_file = self.setup_page(
1250 "Comparison_{}".format(i), self.navbar["comparison"],
1251 title="Comparison PDF for {}".format(i),
1252 approximant="Comparison"
1253 )
1254 html_file.make_banner(approximant="Comparison", key="Comparison")
1255 path = self.image_path["other"]
1256 contents = [
1257 [path + "combined_1d_posterior_{}.png".format(i)],
1258 [
1259 path + "combined_cdf_{}.png".format(i),
1260 path + "combined_boxplot_{}.png".format(i)
1261 ]
1262 ]
1263 html_file.make_table_of_images(
1264 contents=contents, rows=1, columns=2, code="changeimage"
1265 )
1266 html_file.make_banner(
1267 approximant="Summary Table", key="summary_table",
1268 _style="font-size: 26px;"
1269 )
1270 _style = "margin-top:3em; margin-bottom:5em; max-width:1400px"
1271 _class = "row justify-content-center"
1272 html_file.make_container(style=_style)
1273 html_file.make_div(4, _class=_class, _style=None)
1274 headings = [" "] + self.key_data_headings.copy()
1275 contents = []
1276 for label in self.labels:
1277 row = [label]
1278 row += self.key_data_table[label][i]
1279 contents.append(row)
1280 html_file.make_table(
1281 headings=headings, contents=contents, heading_span=1,
1282 accordian=False, format="table-hover",
1283 sticky_header=True
1284 )
1285 html_file.end_div(4)
1286 html_file.end_container()
1287 html_file.export("comparison_summary_{}.csv".format(i))
1289 if self.comparison_stats is not None:
1290 for _num, _key in enumerate(["KS_test", "JS_test"]):
1291 if _key == "KS_test":
1292 html_file.make_banner(
1293 approximant="KS test", key="ks_test",
1294 _style="font-size: 26px;"
1295 )
1296 else:
1297 html_file.make_banner(
1298 approximant="JS test", key="js_test",
1299 _style="font-size: 26px;"
1300 )
1301 _style = "margin-top:3em; margin-bottom:5em; max-width:1400px"
1302 _class = "row justify-content-center"
1303 html_file.make_container(style=_style)
1304 html_file.make_div(4, _class=_class, _style=None)
1306 table_contents = [
1307 [self.labels[j]] + self.comparison_stats[i][_num][j]
1308 for j in rows
1309 ]
1310 _headings = [" "] + self.labels
1311 html_file.make_table(
1312 headings=_headings, format="table-hover",
1313 heading_span=1, contents=table_contents, accordian=False
1314 )
1315 html_file.end_div(4)
1316 html_file.end_container()
1317 html_file.export("{}_{}.csv".format(_key, i))
1319 html_file.make_footer(user=self.user, rundir=self.webdir)
1320 html_file.close()
1321 html_file = self.setup_page(
1322 "Comparison_Custom", self.navbar["comparison"],
1323 approximant="Comparison", title="Comparison Posteriors for multiple"
1324 )
1325 html_file.make_search_bar(
1326 sidebar=self.same_parameters, label="None", code="combines",
1327 popular_options=[
1328 {"all": ", ".join(self.same_parameters)}
1329 ]
1330 )
1331 html_file.make_footer(user=self.user, rundir=self.webdir)
1332 html_file.close()
1333 html_file = self.setup_page(
1334 "Comparison_All", self.navbar["comparison"],
1335 title="All posteriors for Comparison", approximant="Comparison"
1336 )
1337 html_file.make_banner(approximant="Comparison", key="Comparison")
1338 for j in self.same_parameters:
1339 html_file.make_banner(
1340 approximant=j, _style="font-size: 26px;"
1341 )
1342 contents = [
1343 [path + "combined_1d_posterior_{}.png".format(j)],
1344 [
1345 path + "combined_cdf_{}.png".format(j),
1346 path + "combined_boxplot_{}.png".format(j)
1347 ]
1348 ]
1349 html_file.make_table_of_images(
1350 contents=contents, rows=1, columns=2, code="changeimage")
1351 html_file.close()
1352 for j in self.categorize_parameters(self.same_parameters):
1353 if not len(j[1]):
1354 continue
1355 html_file = self.setup_page(
1356 "Comparison_{}_all".format(j[0]), self.navbar["comparison"],
1357 title="All posteriors for describing {}".format(j[0]),
1358 approximant="Comparison"
1359 )
1360 for k in j[1][1:]:
1361 html_file.make_banner(
1362 approximant=k, _style="font-size: 26px;"
1363 )
1364 contents = [
1365 [path + "combined_1d_posterior_{}.png".format(k)],
1366 [
1367 path + "combined_cdf_{}.png".format(k),
1368 path + "combined_boxplot_{}.png".format(k)
1369 ]
1370 ]
1371 html_file.make_table_of_images(
1372 contents=contents, rows=1, columns=2, code="changeimage"
1373 )
1374 html_file.make_footer(user=self.user, rundir=self.webdir)
1375 html_file.close()
1377 def make_interactive_pages(self):
1378 """Wrapper function for _make_interactive_pages
1379 """
1380 pages = ["{}_{}_Interactive_Corner".format(i, i) for i in self.labels]
1381 if self.make_comparison:
1382 pages += ["Comparison_Interactive_Ridgeline"]
1383 self.create_blank_html_pages(pages)
1384 savedir = os.path.join(self.webdir, "plots")
1385 html_files = glob(os.path.join(savedir, "*interactive*.html"))
1386 html_files += glob(os.path.join(savedir, "corner", "*interactive*.html"))
1387 self._make_interactive_pages(pages, html_files)
1389 def _make_interactive_pages(self, pages, html_files):
1390 """Make a page that shows all interactive plots
1392 Parameters
1393 ----------
1394 pages: list
1395 list of pages that you wish to create
1396 """
1397 for num, i in enumerate(self.labels):
1398 html_file = self.setup_page(
1399 "{}_Interactive_Corner".format(i),
1400 self.navbar["result_page"][i], i,
1401 title="{} Interactive Corner Plots".format(i), approximant=i,
1402 background_colour=self.colors[num]
1403 )
1404 html_file.make_banner(approximant=i, key="interactive_corner")
1405 html_file.make_container()
1406 corner_files = [
1407 figure for figure in html_files if "/corner/" in figure
1408 and i in figure
1409 ]
1410 for plot in corner_files:
1411 with open(plot, "r") as f:
1412 data = f.read()
1413 html_file.add_content(data)
1414 html_file.end_container()
1415 html_file.make_footer(user=self.user, rundir=self.webdir)
1416 html_file.close()
1417 if not self.make_comparison:
1418 return
1419 html_file = self.setup_page(
1420 "Comparison_Interactive_Ridgeline", self.navbar["comparison"],
1421 approximant="Comparison", title="Interactive Ridgeline Plots"
1422 )
1423 html_file.make_banner(
1424 approximant="Comparison", key="interactive_ridgeline"
1425 )
1426 posterior_files = [
1427 figure for figure in html_files if "ridgeline" in figure
1428 ]
1429 for plot in posterior_files:
1430 with open(plot, "r") as f:
1431 data = f.read()
1432 parameter = \
1433 plot.split("interactive_ridgeline_")[1].split(".html")[0]
1434 html_file.make_banner(
1435 approximant=parameter, _style="font-size: 26px;"
1436 )
1437 html_file.make_container()
1438 html_file.add_content(data)
1439 html_file.end_container()
1440 html_file.make_footer(user=self.user, rundir=self.webdir)
1441 html_file.close()
1443 def make_error_page(self):
1444 """Wrapper function for _make_error_page
1445 """
1446 pages = ["error"]
1447 self.create_blank_html_pages(pages)
1448 self._make_error_page(pages)
1450 def _make_error_page(self, pages):
1451 """Make a page that is shown when something goes wrong
1453 Parameters
1454 ----------
1455 pages: list
1456 list of pages that you wish to create
1457 """
1458 webpage.make_html(web_dir=self.webdir, pages=pages)
1459 html_file = webpage.open_html(
1460 web_dir=self.webdir, base_url=self.base_url, html_page="error"
1461 )
1462 html_file.make_div(
1463 _class="jumbotron text-center",
1464 _style="background-color: #D3D3D3; margin-bottom:0"
1465 )
1466 html_file.make_div(
1467 _class="container",
1468 _style="margin-top:1em; background-color: #D3D3D3; width: 45em"
1469 )
1470 html_file.add_content(
1471 "<h1 style='color:white; font-size: 8em'>404</h1>"
1472 )
1473 html_file.add_content(
1474 "<h2 style='color:white;'> Something went wrong... </h2>"
1475 )
1476 html_file.end_div()
1477 html_file.end_div()
1478 html_file.close()
1480 def make_version_page(self):
1481 """Wrapper function for _make_version_page
1482 """
1483 pages = ["Version"]
1484 self.create_blank_html_pages(pages, stylesheets=pages)
1485 self._make_version_page(pages)
1487 def _make_version_page(self, pages):
1488 """Make a page to display the version information
1490 Parameters
1491 ----------
1492 pages: list
1493 list of pages that you wish to create
1494 """
1495 from pesummary._version_helper import install_path
1497 html_file = webpage.open_html(
1498 web_dir=self.webdir, base_url=self.base_url, html_page="Version"
1499 )
1500 html_file = self.setup_page(
1501 "Version", self.navbar["home"], title="Version Information"
1502 )
1503 html_file.make_banner(approximant="Version", key="Version")
1504 contents = __version_string__
1505 contents += install_path(return_string=True)
1506 for i in self.labels:
1507 contents = (
1508 "# {} version information\n\n{}_version={}\n\n".format(
1509 i, i, self.file_versions[i]
1510 )
1511 ) + contents
1512 html_file.make_container()
1513 styles = html_file.make_code_block(language='shell', contents=contents)
1514 with open('{0:s}/css/Version.css'.format(self.webdir), 'w') as f:
1515 f.write(styles)
1516 html_file.end_container()
1517 packages = self.package_information["packages"]
1518 style = "margin-top:{}; margin-bottom:{};"
1519 if len(packages):
1520 html_file.make_table(
1521 headings=[x.title().replace('_', ' ') for x in packages.dtype.names],
1522 contents=[[pp.decode("utf-8") for pp in pkg] for pkg in packages],
1523 accordian=False, style=style.format("1em", "1em")
1524 )
1525 if self.package_information["manager"] == "conda":
1526 html_file.export(
1527 "environment.yml", margin_top="1em", csv=False,
1528 conda=True
1529 )
1530 else:
1531 html_file.export(
1532 "requirements.txt", margin_top="1em", csv=False,
1533 requirements=True
1534 )
1535 html_file.make_footer(user=self.user, rundir=self.webdir)
1536 html_file.close()
1538 def make_logging_page(self):
1539 """Wrapper function for _make_logging_page
1540 """
1541 pages = ["Logging"]
1542 self.create_blank_html_pages(pages, stylesheets=pages)
1543 self._make_logging_page(pages)
1545 def _make_logging_page(self, pages):
1546 """Make a page to display the logging output from PESummary
1548 Parameters
1549 ----------
1550 pages: list
1551 list of pages that you wish to create
1552 """
1553 html_file = webpage.open_html(
1554 web_dir=self.webdir, base_url=self.base_url, html_page="Logging"
1555 )
1556 html_file = self.setup_page(
1557 "Logging", self.navbar["home"], title="Logger Information"
1558 )
1559 html_file.make_banner(approximant="Logging", key="Logging")
1560 path = pesummary.__file__[:-12]
1561 log_file = LOG_FILE
1562 if not os.path.isfile(log_file):
1563 log_file = ".tmp/pesummary/no_log_information.log"
1564 with open(log_file, "w") as f:
1565 f.writelines(["No log information stored"])
1567 with open(log_file, 'r') as f:
1568 contents = f.read()
1569 html_file.make_container()
1570 styles = html_file.make_code_block(language='shell', contents=contents)
1571 with open('{0:s}/css/Logging.css'.format(self.webdir), 'w') as f:
1572 f.write(styles)
1573 html_file.end_container()
1574 html_file.make_footer(user=self.user, rundir=self.webdir)
1575 html_file.close()
1577 def make_about_page(self):
1578 """Wrapper function for _make_about_page
1579 """
1580 pages = ["About"]
1581 self.create_blank_html_pages(pages, stylesheets=pages)
1582 self._make_about_page(pages)
1584 def _make_about_page(self, pages):
1585 """Make a page informing the user of the run directory, user that ran
1586 the job etc
1588 Parameters
1589 ----------
1590 pages: list
1591 list of pages you wish to create
1592 """
1593 html_file = webpage.open_html(
1594 web_dir=self.webdir, base_url=self.base_url, html_page="About"
1595 )
1596 html_file = self.setup_page(
1597 "About", self.navbar["home"], title="About"
1598 )
1599 html_file.make_banner(approximant="About", key="About")
1600 html_file.make_banner(
1601 approximant="On the command-line", key="command_line",
1602 _style="font-size: 26px;", link=os.getcwd()
1603 )
1604 command = ""
1605 for i in sys.argv:
1606 command += " "
1607 if i[0] == "-":
1608 command += "\n"
1609 command += "{}".format(i)
1610 html_file.make_container()
1611 styles = html_file.make_code_block(language="shell", contents=command)
1612 with open('{0:s}/css/About.css'.format(self.webdir), 'w') as g:
1613 g.write(styles)
1614 html_file.end_container()
1615 html_file.export(
1616 "pesummary.sh", csv=False, json=False, shell=True,
1617 margin_top="-4em"
1618 )
1619 html_file.make_footer(
1620 user=self.user, rundir=self.webdir, fix_bottom=True
1621 )
1622 html_file.close()
1624 def make_downloads_page(self):
1625 """Wrapper function for _make_downloads_page
1626 """
1627 pages = ["Downloads"]
1628 self.create_blank_html_pages(pages)
1629 self._make_downloads_page(pages)
1631 def _make_downloads_page(self, pages, fix_bottom=False):
1632 """Make a page with links to files which can be downloaded
1634 Parameters
1635 ----------
1636 pages: list
1637 list of pages you wish to create
1638 """
1639 html_file = webpage.open_html(
1640 web_dir=self.webdir, base_url=self.base_url, html_page="Downloads"
1641 )
1642 html_file = self.setup_page(
1643 "Downloads", self.navbar["home"], title="Downloads"
1644 )
1645 html_file.make_banner(approximant="Downloads", key="Downloads")
1646 html_file.make_container()
1647 base_string = "{} can be downloaded <a href={} download>here</a>"
1648 style = "margin-top:{}; margin-bottom:{};"
1649 headings = ["Description"]
1650 metafile_row = [
1651 [
1652 base_string.format(
1653 "The complete metafile containing all information "
1654 "about the analysis",
1655 self.results_path["other"] + self._metafile
1656 )
1657 ]
1658 ]
1659 if self.external_hdf5_links:
1660 string = ""
1661 for label in self.labels:
1662 string += (
1663 "The hdf5 sub file for {} can be downloaded "
1664 "<a href={} download>here</a>. ".format(
1665 label, self.results_path["other"] + "_{}.h5".format(
1666 label
1667 )
1668 )
1669 )
1670 metafile_row += [
1671 [
1672 "The complete metafile uses external hdf5 links. Each "
1673 "analysis is therefore stored in seperate meta files. "
1674 "{}".format(string)
1675 ]
1676 ]
1677 metafile_row += [
1678 [
1679 (
1680 "Information about reading this metafile can be seen "
1681 " <a href={}>here</a>".format(
1682 "https://lscsoft.docs.ligo.org/pesummary/"
1683 "stable/data/reading_the_metafile.html"
1684 )
1685 )
1686 ]
1687 ]
1688 html_file.make_table(
1689 headings=headings, contents=metafile_row,
1690 accordian=False, style=style.format("1em", "1em")
1691 )
1692 for num, i in enumerate(self.labels):
1693 table_contents = self._make_entry_in_downloads_table(
1694 html_file, i, num, base_string
1695 )
1696 if table_contents is not None:
1697 html_file.make_table(
1698 headings=headings, contents=table_contents, accordian=False
1699 )
1700 html_file.end_container()
1701 html_file.make_footer(
1702 user=self.user, rundir=self.webdir, fix_bottom=fix_bottom
1703 )
1704 html_file.close()
1706 def _make_entry_in_downloads_table(self, html_file, label, num, base_string):
1707 """Make a label specific entry into the downloads table
1709 Parameters
1710 ----------
1711 label: str
1712 the label you wish to add to the downloads table
1713 base_string: str
1714 the download string
1715 """
1716 import glob
1717 identifier = label if not self.mcmc_samples else "chain"
1718 _original = glob.glob(
1719 os.path.join(self.webdir, "samples", "{}_*".format(identifier))
1720 )
1721 html_file.add_content(
1722 "<div class='banner', style='margin-left:-4em'>{}</div>".format(
1723 label
1724 )
1725 )
1726 if not self.mcmc_samples and len(_original) > 0:
1727 table_contents = [
1728 [
1729 base_string.format(
1730 "Original file provided to PESummary",
1731 self.results_path["other"] + Path(_original[0]).name
1732 )
1733 ]
1734 ]
1735 elif self.mcmc_samples and len(_original) > 0:
1736 table_contents = [
1737 [
1738 base_string.format(
1739 "Original chain {} provided to PESummary".format(num),
1740 self.results_path["other"] + Path(_original[num]).name
1741 )
1742 ] for num in range(len(_original))
1743 ]
1744 else:
1745 table_contents = []
1746 table_contents.append(
1747 [
1748 base_string.format(
1749 "Dat file containing posterior samples",
1750 self.results_path["other"] + "%s_pesummary.dat" % (label)
1751 )
1752 ]
1753 )
1754 if self.config is not None and self.config[num] is not None:
1755 table_contents.append(
1756 [
1757 base_string.format(
1758 "Config file used for this analysis",
1759 self.config_path["other"] + "%s_config.ini" % (label)
1760 )
1761 ]
1762 )
1763 return table_contents
1765 def make_notes_page(self):
1766 """Wrapper function for _make_notes_page
1767 """
1768 pages = ["Notes"]
1769 self.create_blank_html_pages(pages, stylesheets=pages)
1770 self._make_notes_page(pages)
1772 def _make_notes_page(self, pages):
1773 """Make a page to display the custom notes
1775 Parameters
1776 ----------
1777 pages: list
1778 list of pages that you wish to create
1779 """
1780 html_file = webpage.open_html(
1781 web_dir=self.webdir, base_url=self.base_url, html_page="Notes"
1782 )
1783 html_file = self.setup_page(
1784 "Notes", self.navbar["home"], title="Notes"
1785 )
1786 html_file.make_banner(approximant="Notes", key="Notes")
1787 html_file.make_container()
1788 styles = html_file.make_code_block(
1789 language='shell', contents=self.notes
1790 )
1791 with open('{0:s}/css/Notes.css'.format(self.webdir), 'w') as f:
1792 f.write(styles)
1793 html_file.end_container()
1794 html_file.make_footer(user=self.user, rundir=self.webdir)
1795 html_file.close()
1797 def generate_specific_javascript(self):
1798 """Tailor the javascript to the specific situation.
1799 """
1800 path = self.webdir + "/js/grab.js"
1801 existing = open(path)
1802 existing = existing.readlines()
1803 ind = existing.index(" if ( param == approximant ) {\n")
1804 content = existing[:ind]
1805 for i in [list(j.keys())[0] for j in self._result_page_links()]:
1806 content.append(" if ( param == \"%s\" ) {\n" % (i))
1807 content.append(" approx = \"None\" \n")
1808 content.append(" }\n")
1809 for i in existing[ind + 1:]:
1810 content.append(i)
1811 new_file = open(path, "w")
1812 new_file.writelines(content)
1813 new_file.close()
1815 def default_categories(self):
1816 """Return the default categories
1817 """
1818 categories = {
1819 "A-D": {
1820 "accept": ["a", "A", "b", "B", "c", "C", "d", "D"], "reject": []
1821 },
1822 "E-F": {
1823 "accept": ["e", "E", "f", "F", "g", "G", "h", "H"], "reject": []
1824 },
1825 "I-L": {
1826 "accept": ["i", "I", "j", "J", "k", "K", "l", "L"], "reject": []
1827 },
1828 "M-P": {
1829 "accept": ["m", "M", "n", "N", "o", "O", "p", "P"], "reject": []
1830 },
1831 "Q-T": {
1832 "accept": ["q", "Q", "r", "R", "s", "S", "t", "T"], "reject": []
1833 },
1834 "U-X": {
1835 "accept": ["u", "U", "v", "V", "w", "W", "x", "X"], "reject": []
1836 },
1837 "Y-Z": {
1838 "accept": ["y", "Y", "z", "Z"], "reject": []
1839 }
1840 }
1841 return categories
1843 def default_images_for_result_page(self, label):
1844 """Return the default images that will be displayed on the result page
1845 """
1846 return [], [], []
1848 def default_popular_options(self):
1849 """Return a list of default options
1850 """
1851 return []
1853 def default_comparison_homepage_plots(self):
1854 """Return a list of default plots for the comparison homepage
1855 """
1856 return []
1858 def default_corner_params(self):
1859 """Return a list of default corner parameters used by the corner
1860 plotting function
1861 """
1862 return []
1864 def add_existing_data(self):
1865 """
1866 """
1867 from pesummary.utils.utils import _add_existing_data
1869 self = _add_existing_data(self)
1871 def add_to_expert_pages(self, path, label):
1872 """Additional expert plots to add beyond the default. This returns a
1873 dictionary keyed by the parameter, with values providing the path
1874 to the additional plots you wish to add. The plots are a 2d list
1875 where each sublist represents a row in the table of images.
1877 Parameters
1878 ----------
1879 path: str
1880 path to the image directory
1881 label: str
1882 label of the plot you wish to add
1883 """
1884 mydict = {}
1885 contour_base = path + "{}_2d_contour_{}_{}.png"
1886 histogram_base = path + "{}_1d_posterior_{}_{}.png"
1887 if not hasattr(self.samples[label], "debug_keys"):
1888 return mydict
1889 for param in self.samples[label].debug_keys():
1890 if "_non_reweighted" in param:
1891 base_param = param.split("_non_reweighted")[0][1:]
1892 if base_param in self.samples[label].keys():
1893 mydict[base_param] = [[
1894 histogram_base.format(label, base_param, param),
1895 contour_base.format(label, base_param, param)
1896 ]]
1897 return mydict
1899 @property
1900 def additional_1d_pages(self):
1901 """Additional 1d histogram pages beyond one for each parameter. You may,
1902 for instance, want a 1d histogram page which combines multiple
1903 parameters. This returns a dictionary, keyed by the new 1d histogram
1904 page, with values indicating the parameters you wish to include on this
1905 page. Only the 1d marginalized histograms are shown.
1906 """
1907 return None