Coverage for pesummary/gw/webpage/main.py: 76.7%
382 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-12-09 22:34 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2024-12-09 22:34 +0000
1# Licensed under an MIT style license -- see LICENSE.md
3import os
4import numpy as np
6from pesummary.core.webpage.main import _WebpageGeneration as _CoreWebpageGeneration
7from pesummary.core.webpage.main import PlotCaption
8from pesummary.gw.file.standard_names import descriptive_names
9from pesummary.utils.utils import logger
10from pesummary import conf
12__author__ = ["Charlie Hoy <charlie.hoy@ligo.org>"]
15class CommandLineCaption(object):
16 """Class to handle generating the command line used to generate a plot and
17 a caption to describe the plot
19 Parameters
20 ----------
21 """
22 def __init__(self, command_line_arguments, samples=None):
23 self.args = command_line_arguments
24 self.samples = samples
25 self.executable = self.get_executable("summaryplots")
27 @staticmethod
28 def get_executable(executable):
29 """Return the path to an executable
31 Parameters
32 ----------
33 executable: str
34 the name of the executable you wish to find
35 """
36 from subprocess import check_output
38 path = check_output(["which", executable]).decode("utf-8").strip()
39 return path
41 @property
42 def command_line(self):
43 """Generate the command line used to generate the plot
44 """
45 return "{} {}".format(self.executable, " ".join(self.args))
47 @property
48 def caption(self):
49 """Make a caption to describe the plot
50 """
51 general_cli = ""
52 if "1d_histogram" in self.args[0]:
53 return self.histogram_caption()
54 if "skymap" in self.args[0]:
55 return self.skymap_caption()
56 return general_cli
58 def histogram_caption(self):
59 """Return a caption to describe the 1d histogram plot
60 """
61 args = self.args[0].split(" ")
62 parameter = args[args.index("--parameter") + 1]
63 general_cli = (
64 "1d histogram showing the posterior distribution for "
65 "{}.".format(parameter)
66 )
67 if parameter == "chi_p":
68 general_cli += (
69 " chi_p is the precession parameter and quantifies how much "
70 "precession there is in the system. It ranges from 0 to 1 "
71 "with 0 meaning there is no precession in the system and 1 "
72 "meaning there is maximal precession in the system."
73 )
74 if self.samples is not None:
75 general_cli += (
76 " The median of the distribution is {} with 90% confidence "
77 "interval {}".format(
78 np.round(self.samples.average(type="median"), 3),
79 [np.round(i, 3) for i in self.samples.credible_interval()]
80 )
81 )
82 return general_cli
84 def skymap_caption(self):
85 """Return a caption to describe the skymap plot
86 """
87 general_cli = (
88 "Skymap showing the possible location of the source of the "
89 "source of the gravitational waves"
90 )
93class _WebpageGeneration(_CoreWebpageGeneration):
94 """
95 """
96 def __init__(
97 self, webdir=None, samples=None, labels=None, publication=None,
98 user=None, config=None, same_parameters=None, base_url=None,
99 file_versions=None, hdf5=None, colors=None, custom_plotting=None,
100 pepredicates_probs=None, gracedb=None, approximant=None, key_data=None,
101 file_kwargs=None, existing_labels=None, existing_config=None,
102 existing_file_version=None, existing_injection_data=None,
103 existing_samples=None, existing_metafile=None, add_to_existing=False,
104 existing_file_kwargs=None, existing_weights=None, result_files=None,
105 notes=None, disable_comparison=False, pastro_probs=None, gwdata=None,
106 disable_interactive=False, publication_kwargs={}, no_ligo_skymap=False,
107 psd=None, priors=None, package_information={"packages": []},
108 mcmc_samples=False, external_hdf5_links=False, preliminary_pages=False,
109 existing_plot=None, disable_expert=False, analytic_priors=None
110 ):
111 self.pepredicates_probs = pepredicates_probs
112 self.pastro_probs = pastro_probs
113 self.gracedb = gracedb
114 self.approximant = approximant
115 self.file_kwargs = file_kwargs
116 self.publication = publication
117 self.publication_kwargs = publication_kwargs
118 self.result_files = result_files
119 self.gwdata = gwdata
120 self.no_ligo_skymap = no_ligo_skymap
121 self.psd = psd
122 self.priors = priors
124 super(_WebpageGeneration, self).__init__(
125 webdir=webdir, samples=samples, labels=labels,
126 publication=publication, user=user, config=config,
127 same_parameters=same_parameters, base_url=base_url,
128 file_versions=file_versions, hdf5=hdf5, colors=colors,
129 custom_plotting=custom_plotting,
130 existing_labels=existing_labels, existing_config=existing_config,
131 existing_file_version=existing_file_version,
132 existing_injection_data=existing_injection_data,
133 existing_samples=existing_samples,
134 existing_metafile=existing_metafile,
135 existing_file_kwargs=existing_file_kwargs,
136 existing_weights=existing_weights,
137 add_to_existing=add_to_existing, notes=notes,
138 disable_comparison=disable_comparison,
139 disable_interactive=disable_interactive,
140 package_information=package_information, mcmc_samples=mcmc_samples,
141 external_hdf5_links=external_hdf5_links, key_data=key_data,
142 existing_plot=existing_plot, disable_expert=disable_expert,
143 analytic_priors=analytic_priors
144 )
145 if self.file_kwargs is None:
146 self.file_kwargs = {
147 label: {"sampler": {}, "meta_data": {}} for label in self.labels
148 }
149 if self.approximant is None:
150 self.approximant = {label: None for label in self.labels}
151 if self.result_files is None:
152 self.result_files = [None] * len(self.labels)
153 self.psd_path = {"other": os.path.join("..", "psds")}
154 self.calibration_path = {"other": os.path.join("..", "calibration")}
155 self.preliminary_pages = preliminary_pages
156 if not isinstance(self.preliminary_pages, dict):
157 if self.preliminary_pages:
158 self.preliminary_pages = {
159 label: True for label in self.labels
160 }
161 else:
162 self.preliminary_pages = {
163 label: False for label in self.labels
164 }
165 if all(value for value in self.preliminary_pages.values()):
166 self.all_pages_preliminary = True
167 if len(self.labels) > 1:
168 if any(value for value in self.preliminary_pages.values()):
169 self.preliminary_pages["Comparison"] = True
171 def categorize_parameters(self, parameters):
172 """Categorize the parameters into common headings
174 Parameters
175 ----------
176 parameters: list
177 list of parameters that you would like to sort
178 """
179 return super(_WebpageGeneration, self).categorize_parameters(
180 parameters, starting_letter=False
181 )
183 def categorize_2d_parameters(self, samples):
184 """Categorize the default 2d parameters and decide the common
185 headings
187 Parameters
188 ----------
189 parameters: list
190 list of parameters that you would like to sort
191 """
192 sort = {}
193 for params in conf.gw_2d_plots:
194 if not all(p in samples.keys() for p in params):
195 continue
196 if not all(len(np.unique(samples[p])) > 1 for p in params):
197 continue
198 headings = self.categorize_parameters(params)
199 for hh in headings[::-1]:
200 if len(hh[1]) and hh[0] not in ["others"]:
201 heading = hh[0]
202 break
203 elif len(hh[1]) and "geocent_time" in params:
204 heading = "timings"
205 break
206 if heading not in sort.keys():
207 sort[heading] = []
208 sort[heading] += params
209 return sort
211 def _kde_from_same_samples(self, param, samples):
212 """Generate KDEs for a set of samples
214 Parameters
215 ----------
216 param: str
217 The parameter that the samples belong to
218 samples: list
219 list of samples for each result file
220 """
221 from pesummary.utils.bounded_1d_kde import ReflectionBoundedKDE
222 from pesummary.gw.plots.plot import _return_bounds
224 xlow, xhigh = _return_bounds(param, samples, comparison=True)
225 return super(_WebpageGeneration, self)._kde_from_same_samples(
226 param, samples, kde=ReflectionBoundedKDE, xlow=xlow, xhigh=xhigh
227 )
229 def make_navbar_for_homepage(self):
230 """Make a navbar for the homepage
231 """
232 links = super(_WebpageGeneration, self).make_navbar_for_homepage()
233 if self.gwdata is not None:
234 links.append(["Detchar", [i for i in self.gwdata.keys()]])
235 return links
237 def make_navbar_for_result_page(self):
238 """Make a navbar for the result page homepage
239 """
240 links = super(_WebpageGeneration, self).make_navbar_for_result_page()
241 for num, label in enumerate(self.labels):
242 links[label].append(
243 ["2d Histograms", [
244 {"masses": label}, {"spins": label},
245 {"location": label}, {"timings": label}
246 ]]
247 )
248 if self.pepredicates_probs[label] is not None:
249 links[label].append({"Classification": label})
250 return links
252 def generate_webpages(self):
253 """Generate all webpages for all result files passed
254 """
255 super(_WebpageGeneration, self).generate_webpages()
256 self.make_2d_histogram_pages()
257 if self.publication:
258 self.make_publication_pages()
259 if self.gwdata is not None:
260 self.make_detector_pages()
261 if all(val is not None for key, val in self.pepredicates_probs.items()):
262 self.make_classification_pages()
264 def _make_home_pages(self, pages):
265 """Make the home pages
267 Parameters
268 ----------
269 pages: list
270 list of pages that you wish to create
271 """
272 title = None if self.gracedb is None else (
273 "Parameter Estimation Summary Pages for {}".format(self.gracedb)
274 )
275 banner = "Summary" if self.gracedb is None else (
276 "Summary for {}".format(self.gracedb)
277 )
278 html_file = self.setup_page("home", self.navbar["home"], title=title)
279 html_file.make_banner(approximant=banner, key="Summary")
280 path = self.image_path["home"]
282 if self.make_comparison:
283 if not all(self.approximant[i] is not None for i in self.labels):
284 image_contents = []
285 _plot = os.path.join(path, "compare_time_domain_waveforms.png")
286 if os.path.isfile(_plot):
287 image_contents.append(_plot)
288 image_contents = [image_contents]
289 html_file = self.make_modal_carousel(
290 html_file, image_contents, unique_id=True
291 )
293 for i in self.labels:
294 html_file.make_banner(approximant=i, key=i)
295 image_contents, captions = [], []
296 basic_string = os.path.join(self.webdir, "plots", "{}.png")
297 relative_path = os.path.join(path, "{}.png")
298 if os.path.isfile(basic_string.format("%s_strain" % (i))):
299 image_contents.append(relative_path.format("%s_strain" % (i)))
300 captions.append(PlotCaption("strain"))
301 if os.path.isfile(basic_string.format("%s_psd_plot" % (i))):
302 image_contents.append(relative_path.format("%s_psd_plot" % (i)))
303 captions.append(PlotCaption("psd"))
304 if os.path.isfile(
305 basic_string.format("%s_waveform_time_domain" % (i))
306 ):
307 image_contents.append(
308 relative_path.format("%s_waveform_time_domain" % (i))
309 )
310 captions.append(PlotCaption("time_waveform"))
311 if os.path.isfile(
312 basic_string.format("%s_calibration_plot" % (i))
313 ):
314 image_contents.append(
315 relative_path.format("%s_calibration_plot" % (i))
316 )
317 captions.append(PlotCaption("calibration"))
318 image_contents = [image_contents]
319 html_file = self.make_modal_carousel(
320 html_file, image_contents, unique_id=True, extra_div=True,
321 captions=[captions]
322 )
324 for _key in ["sampler", "meta_data"]:
325 if _key == "sampler":
326 html_file.make_banner(
327 approximant="Sampler kwargs", key="sampler_kwargs",
328 _style="font-size: 26px;"
329 )
330 else:
331 html_file.make_banner(
332 approximant="Meta data", key="meta_data",
333 _style="font-size: 26px;"
334 )
335 _style = "margin-top:3em; margin-bottom:5em; max-width:1400px"
336 _class = "row justify-content-center"
337 html_file.make_container(style=_style)
338 html_file.make_div(4, _class=_class, _style=None)
340 base_label = self.labels[0]
341 total_keys = list(self.file_kwargs[base_label][_key].keys())
342 if len(self.labels) > 1:
343 for _label in self.labels[1:]:
344 total_keys += [
345 key for key in self.file_kwargs[_label][_key].keys()
346 if key not in total_keys
347 ]
348 _headings = ["label"] + total_keys
349 table_contents = [
350 [i] + [
351 self.file_kwargs[i][_key][key] if key in
352 self.file_kwargs[i][_key].keys() else "-" for key in
353 total_keys
354 ] for i in self.labels
355 ]
356 html_file.make_table(
357 headings=_headings, format="table-hover", heading_span=1,
358 contents=table_contents, accordian=False
359 )
360 html_file.end_div(4)
361 html_file.end_container()
362 html_file.export("{}.csv".format(_key))
364 html_file.make_footer(user=self.user, rundir=self.webdir)
365 html_file.close()
366 super(_WebpageGeneration, self)._make_home_pages(pages, make_home=False)
368 def make_2d_histogram_pages(self):
369 """Wrapper function for _make_2d_histogram pages
370 """
371 pages = [
372 "{}_{}_{}".format(i, i, j) for i in self.labels for j in
373 self.categorize_2d_parameters(self.samples[i]).keys()
374 ]
375 self.create_blank_html_pages(pages)
376 self._make_2d_histogram_pages(pages)
378 def _make_2d_histogram_pages(self, pages):
379 """Make the 2d histogram pages
380 """
381 for num, i in enumerate(self.labels):
382 for j, k in self.categorize_2d_parameters(self.samples[i]).items():
383 html_file = self.setup_page(
384 "{}_{}".format(i, j), self.navbar["result_page"][i],
385 i, title="{} Posterior PDFs describing the {}".format(i, j),
386 approximant=i, background_colour=self.colors[num],
387 histogram_download=False, toggle=self.expert_plots
388 )
389 html_file.make_banner(approximant=i, key=i)
390 path = self.image_path["other"]
391 contents = [
392 path + "{}_2d_posterior_{}_{}.png".format(i, k[l], k[l+1])
393 for l in range(0, len(k), 2)
394 ]
395 if len(contents) < 2:
396 autoscale = False
397 else:
398 autoscale = True
399 image_contents = [
400 contents[l:2 + l] for l in range(0, len(contents), 2)
401 ]
402 html_file.make_table_of_images(
403 contents=image_contents, code="changeimage",
404 mcmc_samples=False, autoscale=autoscale
405 )
406 key_data = self.key_data
407 contents = []
408 headings = [" "] + self.key_data_headings.copy()
409 _injection = False
410 rows = []
411 for param in np.unique(k):
412 _row = [param]
413 _row += self.key_data_table[i][param]
414 rows.append(_row)
415 _style = "margin-top:3em; margin-bottom:5em; max-width:1400px"
416 _class = "row justify-content-center"
417 html_file.make_container(style=_style)
418 html_file.make_div(4, _class=_class, _style=None)
419 html_file.make_table(
420 headings=headings, contents=rows, heading_span=1,
421 accordian=False, format="table-hover"
422 )
423 html_file.end_div(4)
424 html_file.end_container()
425 html_file.export("summary_information_{}.csv".format(i))
426 html_file.make_footer(user=self.user, rundir=self.webdir)
427 html_file.close()
429 def make_publication_pages(self):
430 """Wrapper function for _make_publication_pages()
431 """
432 pages = ["Publication"]
433 self.create_blank_html_pages(pages)
434 self._make_publication_pages(pages)
436 def _make_publication_pages(self, pages):
437 """Make the publication pages
439 Parameters
440 ----------
441 pages: list
442 list of pages that you wish to create
443 """
444 from glob import glob
446 executable = self.get_executable("summarypublication")
447 general_cli = "%s --webdir %s --samples %s --labels %s --plot {}" % (
448 executable, os.path.join(self.webdir, "plots", "publication"),
449 " ".join(self.result_files), " ".join(self.labels)
450 )
451 if self.publication_kwargs != {}:
452 general_cli += "--publication_kwargs %s" % (
453 " ".join(
454 [
455 "{}:{}".format(key, value) for key, value in
456 self.publication_kwargs.items()
457 ]
458 )
459 )
460 html_file = self.setup_page(
461 "Publication", self.navbar["home"], title="Publication Plots"
462 )
463 html_file.make_banner(approximant="Publication", key="Publication")
464 path = self.image_path["other"]
465 pub_plots = glob(
466 os.path.join(self.webdir, "plots", "publication", "*.png")
467 )
468 for num, i in enumerate(pub_plots):
469 shortened_path = i.split("/plots/")[-1]
470 pub_plots[num] = path + shortened_path
471 cli = []
472 cap = []
473 posterior_name = \
474 lambda i: "{} ({})".format(i, descriptive_names[i]) if i in \
475 descriptive_names.keys() and descriptive_names[i] != "" else i
476 for i in pub_plots:
477 filename = i.split("/")[-1]
478 if "violin_plot" in filename:
479 parameter = filename.split("violin_plot_")[-1].split(".png")[0]
480 cli.append(
481 general_cli.format("violin") + " --parameters %s" % (
482 parameter
483 )
484 )
485 cap.append(
486 PlotCaption("violin").format(posterior_name(parameter))
487 )
488 elif "spin_disk" in filename:
489 cli.append(general_cli.format("spin_disk"))
490 cap.append(PlotCaption("spin_disk"))
491 elif "2d_contour" in filename:
492 parameters = filename.split("2d_contour_plot_")[-1].split(".png")[0]
493 cli.append(
494 general_cli.format("2d_contour") + " --parameters %s" % (
495 parameters.replace("_and_", " ")
496 )
497 )
498 pp = parameters.split("_and_")
499 cap.append(
500 PlotCaption("2d_contour").format(
501 posterior_name(pp[0]), posterior_name(pp[1])
502 )
503 )
504 image_contents = [
505 pub_plots[i:3 + i] for i in range(0, len(pub_plots), 3)
506 ]
507 command_lines = [
508 cli[i:3 + i] for i in range(0, len(cli), 3)
509 ]
510 captions = [cap[i:3 + i] for i in range(0, len(cap), 3)]
511 html_file = self.make_modal_carousel(
512 html_file, image_contents, cli=command_lines, captions=captions
513 )
514 html_file.make_footer(user=self.user, rundir=self.webdir)
515 html_file.close()
517 def make_detector_pages(self):
518 """Wrapper function for _make_publication_pages()
519 """
520 pages = [i for i in self.gwdata.keys()]
521 self.create_blank_html_pages(pages)
522 self._make_detector_pages(pages)
524 def _make_detector_pages(self, pages):
525 """Make the detector characterisation pages
527 Parameters
528 ----------
529 pages: list
530 list of pages that you wish to create
531 """
532 from pesummary.utils.utils import (
533 determine_gps_time_and_window, command_line_dict
534 )
535 from astropy.time import Time
537 executable = self.get_executable("summarydetchar")
538 try:
539 command_line = command_line_dict()
540 except SystemExit:
541 command_line = {"gwdata": {}}
542 if isinstance(command_line["gwdata"], dict):
543 gwdata_command_line = [
544 "{}:{}".format(key, val) for key, val in
545 command_line["gwdata"].items()
546 ]
547 else:
548 gwdata_command_line = command_line["gwdata"]
549 if gwdata_command_line is None:
550 gwdata_command_line = []
551 general_cli = "%s --webdir %s --gwdata %s --plot {}{}" % (
552 executable, os.path.join(self.webdir, "plots"),
553 " ".join(gwdata_command_line)
554 )
555 path = self.image_path["other"]
556 base = os.path.join(path, "{}_{}.png")
557 ADD_DETCHAR_LINK = True
558 try:
559 maxL_samples = {
560 i: {
561 "geocent_time": self.key_data[i]["geocent_time"]["maxL"]
562 } for i in self.labels
563 }
564 except KeyError:
565 # trying a different name for time
566 try:
567 maxL_samples = {
568 i: {
569 "geocent_time": self.key_data[i][
570 "marginalized_geocent_time"
571 ]["maxL"]
572 } for i in self.labels
573 }
574 except KeyError:
575 logger.warning(
576 "Failed to find a time parameter to link to detchar/"
577 "summary pages. Not adding link to webpages."
578 )
579 ADD_DETCHAR_LINK = False
580 if ADD_DETCHAR_LINK:
581 gps_time, window = determine_gps_time_and_window(maxL_samples, self.labels)
582 t = Time(gps_time, format='gps')
583 t = Time(t, format='datetime')
584 link = (
585 "https://ldas-jobs.ligo-wa.caltech.edu/~detchar/summary/day"
586 "/{}{}{}/".format(
587 t.value.year,
588 "0{}".format(t.value.month) if t.value.month < 10 else t.value.month,
589 "0{}".format(t.value.day) if t.value.day < 10 else t.value.day
590 )
591 )
592 else:
593 link = None
594 gps_time, window = None, None
595 for det in self.gwdata.keys():
596 html_file = self.setup_page(
597 det, self.navbar["home"], title="{} Detchar".format(det)
598 )
599 html_file.make_banner(approximant=det, key="detchar", link=link)
600 image_contents = [
601 [base.format("spectrogram", det), base.format("omegascan", det)]
602 ]
603 command_lines = [
604 [
605 general_cli.format("spectrogram", ""),
606 general_cli.format(
607 "omegascan", "--gps %s --vmin 0 --vmax 25 --window %s" % (
608 gps_time, window
609 )
610 )
611 ]
612 ]
613 html_file = self.make_modal_carousel(
614 html_file, image_contents, cli=command_lines, autoscale=True,
615 )
616 html_file.make_footer(user=self.user, rundir=self.webdir)
617 html_file.close()
619 def make_classification_pages(self):
620 """Wrapper function for _make_publication_pages()
621 """
622 pages = ["{}_{}_Classification".format(i, i) for i in self.labels]
623 self.create_blank_html_pages(pages)
624 self._make_classification_pages(pages)
626 def _make_classification_pages(self, pages):
627 """Make the classification pages
629 Parameters
630 ----------
631 pages: list
632 list of pages that you wish to create
633 """
634 executable = self.get_executable("summaryclassification")
635 general_cli = "%s --samples {}" % (executable)
636 for num, label in enumerate(self.labels):
637 html_file = self.setup_page(
638 "{}_Classification".format(label),
639 self.navbar["result_page"][label], label,
640 title="{} Classification".format(label),
641 background_colour=self.colors[num], approximant=label
642 )
643 html_file.make_banner(approximant=label, key="classification")
645 if self.pepredicates_probs[label] is not None:
646 html_file.make_container()
647 _class = "row justify-content-center"
648 html_file.make_div(4, _class=_class, _style=None)
649 keys = list(self.pepredicates_probs[label]["default"].keys())
650 table_contents = [
651 ["{} prior".format(i)] + [
652 self.pepredicates_probs[label][i][j] for j in keys
653 ] for i in ["default", "population"]
654 ]
655 if self.pastro_probs[label] is not None:
656 keys += ["HasNS"]
657 keys += ["HasRemnant"]
658 table_contents[0].append(self.pastro_probs[label]["default"]["HasNS"])
659 table_contents[0].append(
660 self.pastro_probs[label]["default"]["HasRemnant"]
661 )
662 try:
663 table_contents[1].append(
664 self.pastro_probs[label]["population"]["HasNS"]
665 )
666 table_contents[1].append(
667 self.pastro_probs[label]["population"]["HasRemnant"]
668 )
669 except KeyError:
670 table_contents[1].append("-")
671 table_contents[1].append("-")
672 logger.warning(
673 "Failed to add 'em_bright' probabilities for population "
674 "reweighted prior"
675 )
676 html_file.make_table(
677 headings=[" "] + keys, contents=table_contents,
678 heading_span=1, accordian=False
679 )
680 html_file.make_cli_button(
681 general_cli.format(self.result_files[num])
682 )
683 html_file.export(
684 "classification_{}.csv".format(label),
685 margin_top="-1.5em", margin_bottom="0.5em", json=True
686 )
687 html_file.end_div(4)
688 html_file.end_container()
689 path = self.image_path["other"]
690 base = os.path.join(path, "%s_{}_pepredicates{}.png" % (label))
691 image_contents = [
692 [
693 base.format("default", ""), base.format("default", "_bar"),
694 base.format("population", ""),
695 base.format("population", "_bar")
696 ]
697 ]
698 base = (
699 "%s --webdir %s --labels %s --plot {} --prior {}" % (
700 general_cli.format(self.result_files[num]),
701 os.path.join(self.webdir, "plots"), label
702 )
703 )
704 command_lines = [
705 [
706 base.format("mass_1_mass_2", "default"),
707 base.format("bar", "default"),
708 base.format("mass_1_mass_2", "population"),
709 base.format("bar", "population")
710 ]
711 ]
712 captions = [
713 [
714 PlotCaption("default_classification_mass_1_mass_2"),
715 PlotCaption("default_classification_bar"),
716 PlotCaption("population_classification_mass_1_mass_2"),
717 PlotCaption("population_classification_bar")
718 ]
719 ]
720 html_file = self.make_modal_carousel(
721 html_file, image_contents, cli=command_lines, autoscale=True,
722 captions=captions
723 )
724 html_file.make_footer(user=self.user, rundir=self.webdir)
725 html_file.close()
727 def _make_entry_in_downloads_table(self, html_file, label, num, base_string):
728 """Make a label specific entry into the downloads table
730 Parameters
731 ----------
732 label: str
733 the label you wish to add to the downloads table
734 base_string: str
735 the download string
736 """
737 table = super(_WebpageGeneration, self)._make_entry_in_downloads_table(
738 html_file, label, num, base_string
739 )
740 if not self.no_ligo_skymap:
741 table.append(
742 [
743 base_string.format(
744 "Fits file containing skymap for this analysis",
745 self.results_path["other"] + "%s_skymap.fits" % (label)
746 )
747 ]
748 )
749 if self.psd is not None and self.psd != {} and label in self.psd.keys():
750 for ifo in self.psd[label].keys():
751 if len(self.psd[label][ifo]):
752 table.append(
753 [
754 base_string.format(
755 "%s psd file used for this analysis" % (ifo),
756 os.path.join(
757 self.psd_path["other"],
758 "%s_%s_psd.dat" % (label, ifo)
759 )
760 )
761 ]
762 )
763 if self.priors is not None and "calibration" in self.priors.keys():
764 if label in self.priors["calibration"].keys():
765 for ifo in self.priors["calibration"][label].keys():
766 if len(self.priors["calibration"][label][ifo]):
767 table.append(
768 [
769 base_string.format(
770 "%s calibration envelope file used for "
771 "this analysis" % (ifo), os.path.join(
772 self.calibration_path["other"],
773 "%s_%s_cal.txt" % (label, ifo)
774 )
775 )
776 ]
777 )
778 return table
780 def default_images_for_result_page(self, label):
781 """Return the default images that will be displayed on the result page
782 """
783 path = self.image_path["other"]
784 base_string = path + "%s_{}.png" % (label)
785 image_contents = [
786 [
787 base_string.format("1d_posterior_mass_1"),
788 base_string.format("1d_posterior_mass_2"),
789 ], [
790 base_string.format("1d_posterior_a_1"),
791 base_string.format("1d_posterior_a_2"),
792 base_string.format("1d_posterior_chi_eff")
793 ], [
794 base_string.format("1d_posterior_iota"),
795 base_string.format("skymap"),
796 base_string.format("waveform"),
797 base_string.format("1d_posterior_luminosity_distance"),
798 ]
799 ]
800 executable = self.get_executable("summaryplots")
801 general_cli = (
802 "%s --webdir %s --samples %s --burnin %s --plot {} {} "
803 "--labels %s" % (
804 executable, os.path.join(self.webdir, "plots"),
805 self.result_files[self.labels.index(label)], conf.burnin, label
806 )
807 )
808 cli = [
809 [
810 general_cli.format("1d_histogram", "--parameter mass_1"),
811 general_cli.format("1d_histgram", "--parameter mass_2"),
812 ], [
813 general_cli.format("1d_histogram", "--parameter a_1"),
814 general_cli.format("1d_histogram", "--parameter a_2"),
815 general_cli.format("1d_histogram", "--parameter chi_eff")
816 ], [
817 general_cli.format("1d_histogram", "--parameter iota"),
818 general_cli.format("skymap", ""),
819 general_cli.format("waveform", ""),
820 general_cli.format(
821 "1d_histogram", "--parameter luminosity_distance"
822 ),
823 ]
824 ]
826 caption_1d_histogram = PlotCaption("1d_histogram")
827 posterior_name = \
828 lambda i: "{} ({})".format(i, descriptive_names[i]) if i in \
829 descriptive_names.keys() and descriptive_names[i] != "" else i
830 captions = [
831 [
832 caption_1d_histogram.format(posterior_name("mass_1")),
833 caption_1d_histogram.format(posterior_name("mass_2")),
834 ], [
835 caption_1d_histogram.format(posterior_name("a_1")),
836 caption_1d_histogram.format(posterior_name("a_2")),
837 caption_1d_histogram.format(posterior_name("chi_eff"))
838 ], [
839 caption_1d_histogram.format(posterior_name("iota")),
840 PlotCaption("skymap"), PlotCaption("frequency_waveform"),
841 caption_1d_histogram.format(posterior_name("luminosity_distance"))
842 ]
843 ]
844 return image_contents, cli, captions
846 def default_categories(self):
847 """Return the default categories
848 """
849 categories = self.categories = {
850 "masses": {
851 "accept": ["mass"],
852 "reject": ["source", "final", "torus"]
853 },
854 "source": {
855 "accept": ["source"], "reject": ["final", "torus"]
856 },
857 "remnant": {
858 "accept": ["final", "torus"], "reject": []
859 },
860 "inclination": {
861 "accept": ["theta", "iota", "viewing"], "reject": []
862 },
863 "spins": {
864 "accept": ["spin", "chi_p", "chi_eff", "a_1", "a_2", "precession"],
865 "reject": ["lambda", "final", "gamma", "order"]
866 },
867 "spin_angles": {
868 "accept": ["phi", "tilt", "beta"], "reject": []
869 },
870 "tidal": {
871 "accept": [
872 "lambda", "gamma_", "log_pressure",
873 "spectral_decomposition_gamma_", "compactness_",
874 "tidal_disruption"
875 ],
876 "reject": []
877 },
878 "location": {
879 "accept": [
880 "ra", "dec", "psi", "luminosity_distance", "redshift",
881 "comoving_distance"
882 ],
883 "reject": ["mass_ratio", "radiated", "ram", "ran", "rat", "time", "delay"]
884 },
885 "timings": {
886 "accept": ["time", "delay"], "reject": []
887 },
888 "SNR": {
889 "accept": ["snr", "subdominant_multipoles"], "reject": []
890 },
891 "calibration": {
892 "accept": ["spcal", "recalib", "frequency"],
893 "reject": ["minimum", "tidal_disruption", "quasinormal"]
894 },
895 "energy": {
896 "accept": ["peak_luminosity", "radiated"],
897 "reject": []
898 },
899 "others": {
900 "accept": ["phase", "likelihood", "prior", "quasinormal"],
901 "reject": ["spcal", "recalib"]
902 }
903 }
904 return categories
906 def default_popular_options(self):
907 """Return a list of popular options
908 """
909 popular_options = [
910 "mass_1, mass_2", "luminosity_distance, theta_jn, ra, dec",
911 "theta_jn, phi_12, phi_jl, tilt_1, tilt_2"
912 ]
913 return popular_options
915 def default_comparison_homepage_plots(self):
916 """Return a list of default plots for the comparison homepage
917 """
918 path = self.image_path["other"]
919 base = os.path.join(path, "{}.png")
920 contents = [
921 [
922 base.format("combined_skymap"),
923 base.format("compare_time_domain_waveforms"),
924 base.format("compare_waveforms")
925 ]
926 ]
927 return contents
929 def default_corner_params(self):
930 """Return a list of default corner parameters used by the corner
931 plotting function
932 """
933 return conf.gw_corner_parameters
935 def add_to_expert_pages(self, path, label):
936 """Additional expert plots to add beyond the default. This returns a
937 dictionary keyed by the parameter, with values providing the path
938 to the additional plots you wish to add. The plots are a 2d list
939 where each sublist represents a row in the table of images.
941 Parameters
942 ----------
943 path: str
944 path to the image directory
945 label: str
946 label of the plot you wish to add
947 """
948 mydict = super(_WebpageGeneration, self).add_to_expert_pages(
949 path, label
950 )
951 contour_base = path + "{}_2d_contour_{}_log_likelihood.png"
952 mydict.update({
953 "network_precessing_snr": [
954 [
955 contour_base.format(label, "_b_bar"),
956 contour_base.format(label, "_precessing_harmonics_overlap"),
957 ]
958 ]
959 })
960 return mydict
962 @property
963 def additional_1d_pages(self):
964 """Additional 1d histogram pages beyond one for each parameter. You may,
965 for instance, want a 1d histogram page which combines multiple
966 parameters. This returns a dictionary, keyed by the new 1d histogram
967 page, with values indicating the parameters you wish to include on this
968 page. Only the 1d marginalized histograms are shown.
969 """
970 return conf.additional_1d_pages