Coverage for pesummary/gw/webpage/main.py: 78.4%

379 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-05-02 08:42 +0000

1# Licensed under an MIT style license -- see LICENSE.md 

2 

3import os 

4import numpy as np 

5 

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 

11 

12__author__ = ["Charlie Hoy <charlie.hoy@ligo.org>"] 

13 

14 

15class CommandLineCaption(object): 

16 """Class to handle generating the command line used to generate a plot and 

17 a caption to describe the plot 

18 

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") 

26 

27 @staticmethod 

28 def get_executable(executable): 

29 """Return the path to an executable 

30 

31 Parameters 

32 ---------- 

33 executable: str 

34 the name of the executable you wish to find 

35 """ 

36 from subprocess import check_output 

37 

38 path = check_output(["which", executable]).decode("utf-8").strip() 

39 return path 

40 

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)) 

46 

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 

57 

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 

83 

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 ) 

91 

92 

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 

123 

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 

170 

171 def categorize_parameters(self, parameters): 

172 """Categorize the parameters into common headings 

173 

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 ) 

182 

183 def categorize_2d_parameters(self, samples): 

184 """Categorize the default 2d parameters and decide the common 

185 headings 

186 

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 if heading not in sort.keys(): 

204 sort[heading] = [] 

205 sort[heading] += params 

206 return sort 

207 

208 def _kde_from_same_samples(self, param, samples): 

209 """Generate KDEs for a set of samples 

210 

211 Parameters 

212 ---------- 

213 param: str 

214 The parameter that the samples belong to 

215 samples: list 

216 list of samples for each result file 

217 """ 

218 from pesummary.utils.bounded_1d_kde import ReflectionBoundedKDE 

219 from pesummary.gw.plots.plot import _return_bounds 

220 

221 xlow, xhigh = _return_bounds(param, samples, comparison=True) 

222 return super(_WebpageGeneration, self)._kde_from_same_samples( 

223 param, samples, kde=ReflectionBoundedKDE, xlow=xlow, xhigh=xhigh 

224 ) 

225 

226 def make_navbar_for_homepage(self): 

227 """Make a navbar for the homepage 

228 """ 

229 links = super(_WebpageGeneration, self).make_navbar_for_homepage() 

230 if self.gwdata is not None: 

231 links.append(["Detchar", [i for i in self.gwdata.keys()]]) 

232 return links 

233 

234 def make_navbar_for_result_page(self): 

235 """Make a navbar for the result page homepage 

236 """ 

237 links = super(_WebpageGeneration, self).make_navbar_for_result_page() 

238 for num, label in enumerate(self.labels): 

239 links[label].append( 

240 ["2d Histograms", [ 

241 {"masses": label}, {"spins": label}, {"location": label} 

242 ]] 

243 ) 

244 if self.pepredicates_probs[label] is not None: 

245 links[label].append({"Classification": label}) 

246 return links 

247 

248 def generate_webpages(self): 

249 """Generate all webpages for all result files passed 

250 """ 

251 super(_WebpageGeneration, self).generate_webpages() 

252 self.make_2d_histogram_pages() 

253 if self.publication: 

254 self.make_publication_pages() 

255 if self.gwdata is not None: 

256 self.make_detector_pages() 

257 if all(val is not None for key, val in self.pepredicates_probs.items()): 

258 self.make_classification_pages() 

259 

260 def _make_home_pages(self, pages): 

261 """Make the home pages 

262 

263 Parameters 

264 ---------- 

265 pages: list 

266 list of pages that you wish to create 

267 """ 

268 title = None if self.gracedb is None else ( 

269 "Parameter Estimation Summary Pages for {}".format(self.gracedb) 

270 ) 

271 banner = "Summary" if self.gracedb is None else ( 

272 "Summary for {}".format(self.gracedb) 

273 ) 

274 html_file = self.setup_page("home", self.navbar["home"], title=title) 

275 html_file.make_banner(approximant=banner, key="Summary") 

276 path = self.image_path["home"] 

277 

278 if self.make_comparison: 

279 if not all(self.approximant[i] is not None for i in self.labels): 

280 image_contents = [] 

281 _plot = os.path.join(path, "compare_time_domain_waveforms.png") 

282 if os.path.isfile(_plot): 

283 image_contents.append(_plot) 

284 image_contents = [image_contents] 

285 html_file = self.make_modal_carousel( 

286 html_file, image_contents, unique_id=True 

287 ) 

288 

289 for i in self.labels: 

290 html_file.make_banner(approximant=i, key=i) 

291 image_contents, captions = [], [] 

292 basic_string = os.path.join(self.webdir, "plots", "{}.png") 

293 relative_path = os.path.join(path, "{}.png") 

294 if os.path.isfile(basic_string.format("%s_strain" % (i))): 

295 image_contents.append(relative_path.format("%s_strain" % (i))) 

296 captions.append(PlotCaption("strain")) 

297 if os.path.isfile(basic_string.format("%s_psd_plot" % (i))): 

298 image_contents.append(relative_path.format("%s_psd_plot" % (i))) 

299 captions.append(PlotCaption("psd")) 

300 if os.path.isfile( 

301 basic_string.format("%s_waveform_time_domain" % (i)) 

302 ): 

303 image_contents.append( 

304 relative_path.format("%s_waveform_time_domain" % (i)) 

305 ) 

306 captions.append(PlotCaption("time_waveform")) 

307 if os.path.isfile( 

308 basic_string.format("%s_calibration_plot" % (i)) 

309 ): 

310 image_contents.append( 

311 relative_path.format("%s_calibration_plot" % (i)) 

312 ) 

313 captions.append(PlotCaption("calibration")) 

314 image_contents = [image_contents] 

315 html_file = self.make_modal_carousel( 

316 html_file, image_contents, unique_id=True, extra_div=True, 

317 captions=[captions] 

318 ) 

319 

320 for _key in ["sampler", "meta_data"]: 

321 if _key == "sampler": 

322 html_file.make_banner( 

323 approximant="Sampler kwargs", key="sampler_kwargs", 

324 _style="font-size: 26px;" 

325 ) 

326 else: 

327 html_file.make_banner( 

328 approximant="Meta data", key="meta_data", 

329 _style="font-size: 26px;" 

330 ) 

331 _style = "margin-top:3em; margin-bottom:5em; max-width:1400px" 

332 _class = "row justify-content-center" 

333 html_file.make_container(style=_style) 

334 html_file.make_div(4, _class=_class, _style=None) 

335 

336 base_label = self.labels[0] 

337 total_keys = list(self.file_kwargs[base_label][_key].keys()) 

338 if len(self.labels) > 1: 

339 for _label in self.labels[1:]: 

340 total_keys += [ 

341 key for key in self.file_kwargs[_label][_key].keys() 

342 if key not in total_keys 

343 ] 

344 _headings = ["label"] + total_keys 

345 table_contents = [ 

346 [i] + [ 

347 self.file_kwargs[i][_key][key] if key in 

348 self.file_kwargs[i][_key].keys() else "-" for key in 

349 total_keys 

350 ] for i in self.labels 

351 ] 

352 html_file.make_table( 

353 headings=_headings, format="table-hover", heading_span=1, 

354 contents=table_contents, accordian=False 

355 ) 

356 html_file.end_div(4) 

357 html_file.end_container() 

358 html_file.export("{}.csv".format(_key)) 

359 

360 html_file.make_footer(user=self.user, rundir=self.webdir) 

361 html_file.close() 

362 super(_WebpageGeneration, self)._make_home_pages(pages, make_home=False) 

363 

364 def make_2d_histogram_pages(self): 

365 """Wrapper function for _make_2d_histogram pages 

366 """ 

367 pages = [ 

368 "{}_{}_{}".format(i, i, j) for i in self.labels for j in 

369 self.categorize_2d_parameters(self.samples[i]).keys() 

370 ] 

371 self.create_blank_html_pages(pages) 

372 self._make_2d_histogram_pages(pages) 

373 

374 def _make_2d_histogram_pages(self, pages): 

375 """Make the 2d histogram pages 

376 """ 

377 for num, i in enumerate(self.labels): 

378 for j, k in self.categorize_2d_parameters(self.samples[i]).items(): 

379 html_file = self.setup_page( 

380 "{}_{}".format(i, j), self.navbar["result_page"][i], 

381 i, title="{} Posterior PDFs describing the {}".format(i, j), 

382 approximant=i, background_colour=self.colors[num], 

383 histogram_download=False, toggle=self.expert_plots 

384 ) 

385 html_file.make_banner(approximant=i, key=i) 

386 path = self.image_path["other"] 

387 contents = [ 

388 path + "{}_2d_posterior_{}_{}.png".format(i, k[l], k[l+1]) 

389 for l in range(0, len(k), 2) 

390 ] 

391 if len(contents) < 2: 

392 autoscale = False 

393 else: 

394 autoscale = True 

395 image_contents = [ 

396 contents[l:2 + l] for l in range(0, len(contents), 2) 

397 ] 

398 html_file.make_table_of_images( 

399 contents=image_contents, code="changeimage", 

400 mcmc_samples=False, autoscale=autoscale 

401 ) 

402 key_data = self.key_data 

403 contents = [] 

404 headings = [" "] + self.key_data_headings.copy() 

405 _injection = False 

406 rows = [] 

407 for param in np.unique(k): 

408 _row = [param] 

409 _row += self.key_data_table[i][param] 

410 rows.append(_row) 

411 _style = "margin-top:3em; margin-bottom:5em; max-width:1400px" 

412 _class = "row justify-content-center" 

413 html_file.make_container(style=_style) 

414 html_file.make_div(4, _class=_class, _style=None) 

415 html_file.make_table( 

416 headings=headings, contents=rows, heading_span=1, 

417 accordian=False, format="table-hover" 

418 ) 

419 html_file.end_div(4) 

420 html_file.end_container() 

421 html_file.export("summary_information_{}.csv".format(i)) 

422 html_file.make_footer(user=self.user, rundir=self.webdir) 

423 html_file.close() 

424 

425 def make_publication_pages(self): 

426 """Wrapper function for _make_publication_pages() 

427 """ 

428 pages = ["Publication"] 

429 self.create_blank_html_pages(pages) 

430 self._make_publication_pages(pages) 

431 

432 def _make_publication_pages(self, pages): 

433 """Make the publication pages 

434 

435 Parameters 

436 ---------- 

437 pages: list 

438 list of pages that you wish to create 

439 """ 

440 from glob import glob 

441 

442 executable = self.get_executable("summarypublication") 

443 general_cli = "%s --webdir %s --samples %s --labels %s --plot {}" % ( 

444 executable, os.path.join(self.webdir, "plots", "publication"), 

445 " ".join(self.result_files), " ".join(self.labels) 

446 ) 

447 if self.publication_kwargs != {}: 

448 general_cli += "--publication_kwargs %s" % ( 

449 " ".join( 

450 [ 

451 "{}:{}".format(key, value) for key, value in 

452 self.publication_kwargs.items() 

453 ] 

454 ) 

455 ) 

456 html_file = self.setup_page( 

457 "Publication", self.navbar["home"], title="Publication Plots" 

458 ) 

459 html_file.make_banner(approximant="Publication", key="Publication") 

460 path = self.image_path["other"] 

461 pub_plots = glob( 

462 os.path.join(self.webdir, "plots", "publication", "*.png") 

463 ) 

464 for num, i in enumerate(pub_plots): 

465 shortened_path = i.split("/plots/")[-1] 

466 pub_plots[num] = path + shortened_path 

467 cli = [] 

468 cap = [] 

469 posterior_name = \ 

470 lambda i: "{} ({})".format(i, descriptive_names[i]) if i in \ 

471 descriptive_names.keys() and descriptive_names[i] != "" else i 

472 for i in pub_plots: 

473 filename = i.split("/")[-1] 

474 if "violin_plot" in filename: 

475 parameter = filename.split("violin_plot_")[-1].split(".png")[0] 

476 cli.append( 

477 general_cli.format("violin") + " --parameters %s" % ( 

478 parameter 

479 ) 

480 ) 

481 cap.append( 

482 PlotCaption("violin").format(posterior_name(parameter)) 

483 ) 

484 elif "spin_disk" in filename: 

485 cli.append(general_cli.format("spin_disk")) 

486 cap.append(PlotCaption("spin_disk")) 

487 elif "2d_contour" in filename: 

488 parameters = filename.split("2d_contour_plot_")[-1].split(".png")[0] 

489 cli.append( 

490 general_cli.format("2d_contour") + " --parameters %s" % ( 

491 parameters.replace("_and_", " ") 

492 ) 

493 ) 

494 pp = parameters.split("_and_") 

495 cap.append( 

496 PlotCaption("2d_contour").format( 

497 posterior_name(pp[0]), posterior_name(pp[1]) 

498 ) 

499 ) 

500 image_contents = [ 

501 pub_plots[i:3 + i] for i in range(0, len(pub_plots), 3) 

502 ] 

503 command_lines = [ 

504 cli[i:3 + i] for i in range(0, len(cli), 3) 

505 ] 

506 captions = [cap[i:3 + i] for i in range(0, len(cap), 3)] 

507 html_file = self.make_modal_carousel( 

508 html_file, image_contents, cli=command_lines, captions=captions 

509 ) 

510 html_file.make_footer(user=self.user, rundir=self.webdir) 

511 html_file.close() 

512 

513 def make_detector_pages(self): 

514 """Wrapper function for _make_publication_pages() 

515 """ 

516 pages = [i for i in self.gwdata.keys()] 

517 self.create_blank_html_pages(pages) 

518 self._make_detector_pages(pages) 

519 

520 def _make_detector_pages(self, pages): 

521 """Make the detector characterisation pages 

522 

523 Parameters 

524 ---------- 

525 pages: list 

526 list of pages that you wish to create 

527 """ 

528 from pesummary.utils.utils import ( 

529 determine_gps_time_and_window, command_line_dict 

530 ) 

531 from astropy.time import Time 

532 

533 executable = self.get_executable("summarydetchar") 

534 try: 

535 command_line = command_line_dict() 

536 except SystemExit: 

537 command_line = {"gwdata": {}} 

538 if isinstance(command_line["gwdata"], dict): 

539 gwdata_command_line = [ 

540 "{}:{}".format(key, val) for key, val in 

541 command_line["gwdata"].items() 

542 ] 

543 else: 

544 gwdata_command_line = command_line["gwdata"] 

545 if gwdata_command_line is None: 

546 gwdata_command_line = [] 

547 general_cli = "%s --webdir %s --gwdata %s --plot {}{}" % ( 

548 executable, os.path.join(self.webdir, "plots"), 

549 " ".join(gwdata_command_line) 

550 ) 

551 path = self.image_path["other"] 

552 base = os.path.join(path, "{}_{}.png") 

553 ADD_DETCHAR_LINK = True 

554 try: 

555 maxL_samples = { 

556 i: { 

557 "geocent_time": self.key_data[i]["geocent_time"]["maxL"] 

558 } for i in self.labels 

559 } 

560 except KeyError: 

561 # trying a different name for time 

562 try: 

563 maxL_samples = { 

564 i: { 

565 "geocent_time": self.key_data[i][ 

566 "marginalized_geocent_time" 

567 ]["maxL"] 

568 } for i in self.labels 

569 } 

570 except KeyError: 

571 logger.warning( 

572 "Failed to find a time parameter to link to detchar/" 

573 "summary pages. Not adding link to webpages." 

574 ) 

575 ADD_DETCHAR_LINK = False 

576 if ADD_DETCHAR_LINK: 

577 gps_time, window = determine_gps_time_and_window(maxL_samples, self.labels) 

578 t = Time(gps_time, format='gps') 

579 t = Time(t, format='datetime') 

580 link = ( 

581 "https://ldas-jobs.ligo-wa.caltech.edu/~detchar/summary/day" 

582 "/{}{}{}/".format( 

583 t.value.year, 

584 "0{}".format(t.value.month) if t.value.month < 10 else t.value.month, 

585 "0{}".format(t.value.day) if t.value.day < 10 else t.value.day 

586 ) 

587 ) 

588 else: 

589 link = None 

590 gps_time, window = None, None 

591 for det in self.gwdata.keys(): 

592 html_file = self.setup_page( 

593 det, self.navbar["home"], title="{} Detchar".format(det) 

594 ) 

595 html_file.make_banner(approximant=det, key="detchar", link=link) 

596 image_contents = [ 

597 [base.format("spectrogram", det), base.format("omegascan", det)] 

598 ] 

599 command_lines = [ 

600 [ 

601 general_cli.format("spectrogram", ""), 

602 general_cli.format( 

603 "omegascan", "--gps %s --vmin 0 --vmax 25 --window %s" % ( 

604 gps_time, window 

605 ) 

606 ) 

607 ] 

608 ] 

609 html_file = self.make_modal_carousel( 

610 html_file, image_contents, cli=command_lines, autoscale=True, 

611 ) 

612 html_file.make_footer(user=self.user, rundir=self.webdir) 

613 html_file.close() 

614 

615 def make_classification_pages(self): 

616 """Wrapper function for _make_publication_pages() 

617 """ 

618 pages = ["{}_{}_Classification".format(i, i) for i in self.labels] 

619 self.create_blank_html_pages(pages) 

620 self._make_classification_pages(pages) 

621 

622 def _make_classification_pages(self, pages): 

623 """Make the classification pages 

624 

625 Parameters 

626 ---------- 

627 pages: list 

628 list of pages that you wish to create 

629 """ 

630 executable = self.get_executable("summaryclassification") 

631 general_cli = "%s --samples {}" % (executable) 

632 for num, label in enumerate(self.labels): 

633 html_file = self.setup_page( 

634 "{}_Classification".format(label), 

635 self.navbar["result_page"][label], label, 

636 title="{} Classification".format(label), 

637 background_colour=self.colors[num], approximant=label 

638 ) 

639 html_file.make_banner(approximant=label, key="classification") 

640 

641 if self.pepredicates_probs[label] is not None: 

642 html_file.make_container() 

643 _class = "row justify-content-center" 

644 html_file.make_div(4, _class=_class, _style=None) 

645 keys = list(self.pepredicates_probs[label]["default"].keys()) 

646 table_contents = [ 

647 ["{} prior".format(i)] + [ 

648 self.pepredicates_probs[label][i][j] for j in keys 

649 ] for i in ["default", "population"] 

650 ] 

651 if self.pastro_probs[label] is not None: 

652 keys += ["HasNS"] 

653 keys += ["HasRemnant"] 

654 table_contents[0].append(self.pastro_probs[label]["default"]["HasNS"]) 

655 table_contents[0].append( 

656 self.pastro_probs[label]["default"]["HasRemnant"] 

657 ) 

658 try: 

659 table_contents[1].append( 

660 self.pastro_probs[label]["population"]["HasNS"] 

661 ) 

662 table_contents[1].append( 

663 self.pastro_probs[label]["population"]["HasRemnant"] 

664 ) 

665 except KeyError: 

666 table_contents[1].append("-") 

667 table_contents[1].append("-") 

668 logger.warning( 

669 "Failed to add 'em_bright' probabilities for population " 

670 "reweighted prior" 

671 ) 

672 html_file.make_table( 

673 headings=[" "] + keys, contents=table_contents, 

674 heading_span=1, accordian=False 

675 ) 

676 html_file.make_cli_button( 

677 general_cli.format(self.result_files[num]) 

678 ) 

679 html_file.export( 

680 "classification_{}.csv".format(label), 

681 margin_top="-1.5em", margin_bottom="0.5em", json=True 

682 ) 

683 html_file.end_div(4) 

684 html_file.end_container() 

685 path = self.image_path["other"] 

686 base = os.path.join(path, "%s_{}_pepredicates{}.png" % (label)) 

687 image_contents = [ 

688 [ 

689 base.format("default", ""), base.format("default", "_bar"), 

690 base.format("population", ""), 

691 base.format("population", "_bar") 

692 ] 

693 ] 

694 base = ( 

695 "%s --webdir %s --labels %s --plot {} --prior {}" % ( 

696 general_cli.format(self.result_files[num]), 

697 os.path.join(self.webdir, "plots"), label 

698 ) 

699 ) 

700 command_lines = [ 

701 [ 

702 base.format("mass_1_mass_2", "default"), 

703 base.format("bar", "default"), 

704 base.format("mass_1_mass_2", "population"), 

705 base.format("bar", "population") 

706 ] 

707 ] 

708 captions = [ 

709 [ 

710 PlotCaption("default_classification_mass_1_mass_2"), 

711 PlotCaption("default_classification_bar"), 

712 PlotCaption("population_classification_mass_1_mass_2"), 

713 PlotCaption("population_classification_bar") 

714 ] 

715 ] 

716 html_file = self.make_modal_carousel( 

717 html_file, image_contents, cli=command_lines, autoscale=True, 

718 captions=captions 

719 ) 

720 html_file.make_footer(user=self.user, rundir=self.webdir) 

721 html_file.close() 

722 

723 def _make_entry_in_downloads_table(self, html_file, label, num, base_string): 

724 """Make a label specific entry into the downloads table 

725 

726 Parameters 

727 ---------- 

728 label: str 

729 the label you wish to add to the downloads table 

730 base_string: str 

731 the download string 

732 """ 

733 table = super(_WebpageGeneration, self)._make_entry_in_downloads_table( 

734 html_file, label, num, base_string 

735 ) 

736 if not self.no_ligo_skymap: 

737 table.append( 

738 [ 

739 base_string.format( 

740 "Fits file containing skymap for this analysis", 

741 self.results_path["other"] + "%s_skymap.fits" % (label) 

742 ) 

743 ] 

744 ) 

745 if self.psd is not None and self.psd != {} and label in self.psd.keys(): 

746 for ifo in self.psd[label].keys(): 

747 if len(self.psd[label][ifo]): 

748 table.append( 

749 [ 

750 base_string.format( 

751 "%s psd file used for this analysis" % (ifo), 

752 os.path.join( 

753 self.psd_path["other"], 

754 "%s_%s_psd.dat" % (label, ifo) 

755 ) 

756 ) 

757 ] 

758 ) 

759 if self.priors is not None and "calibration" in self.priors.keys(): 

760 if label in self.priors["calibration"].keys(): 

761 for ifo in self.priors["calibration"][label].keys(): 

762 if len(self.priors["calibration"][label][ifo]): 

763 table.append( 

764 [ 

765 base_string.format( 

766 "%s calibration envelope file used for " 

767 "this analysis" % (ifo), os.path.join( 

768 self.calibration_path["other"], 

769 "%s_%s_cal.txt" % (label, ifo) 

770 ) 

771 ) 

772 ] 

773 ) 

774 return table 

775 

776 def default_images_for_result_page(self, label): 

777 """Return the default images that will be displayed on the result page 

778 """ 

779 path = self.image_path["other"] 

780 base_string = path + "%s_{}.png" % (label) 

781 image_contents = [ 

782 [ 

783 base_string.format("1d_posterior_mass_1"), 

784 base_string.format("1d_posterior_mass_2"), 

785 ], [ 

786 base_string.format("1d_posterior_a_1"), 

787 base_string.format("1d_posterior_a_2"), 

788 base_string.format("1d_posterior_chi_eff") 

789 ], [ 

790 base_string.format("1d_posterior_iota"), 

791 base_string.format("skymap"), 

792 base_string.format("waveform"), 

793 base_string.format("1d_posterior_luminosity_distance"), 

794 ] 

795 ] 

796 executable = self.get_executable("summaryplots") 

797 general_cli = ( 

798 "%s --webdir %s --samples %s --burnin %s --plot {} {} " 

799 "--labels %s" % ( 

800 executable, os.path.join(self.webdir, "plots"), 

801 self.result_files[self.labels.index(label)], conf.burnin, label 

802 ) 

803 ) 

804 cli = [ 

805 [ 

806 general_cli.format("1d_histogram", "--parameter mass_1"), 

807 general_cli.format("1d_histgram", "--parameter mass_2"), 

808 ], [ 

809 general_cli.format("1d_histogram", "--parameter a_1"), 

810 general_cli.format("1d_histogram", "--parameter a_2"), 

811 general_cli.format("1d_histogram", "--parameter chi_eff") 

812 ], [ 

813 general_cli.format("1d_histogram", "--parameter iota"), 

814 general_cli.format("skymap", ""), 

815 general_cli.format("waveform", ""), 

816 general_cli.format( 

817 "1d_histogram", "--parameter luminosity_distance" 

818 ), 

819 ] 

820 ] 

821 

822 caption_1d_histogram = PlotCaption("1d_histogram") 

823 posterior_name = \ 

824 lambda i: "{} ({})".format(i, descriptive_names[i]) if i in \ 

825 descriptive_names.keys() and descriptive_names[i] != "" else i 

826 captions = [ 

827 [ 

828 caption_1d_histogram.format(posterior_name("mass_1")), 

829 caption_1d_histogram.format(posterior_name("mass_2")), 

830 ], [ 

831 caption_1d_histogram.format(posterior_name("a_1")), 

832 caption_1d_histogram.format(posterior_name("a_2")), 

833 caption_1d_histogram.format(posterior_name("chi_eff")) 

834 ], [ 

835 caption_1d_histogram.format(posterior_name("iota")), 

836 PlotCaption("skymap"), PlotCaption("frequency_waveform"), 

837 caption_1d_histogram.format(posterior_name("luminosity_distance")) 

838 ] 

839 ] 

840 return image_contents, cli, captions 

841 

842 def default_categories(self): 

843 """Return the default categories 

844 """ 

845 categories = self.categories = { 

846 "masses": { 

847 "accept": ["mass"], 

848 "reject": ["source", "final", "torus"] 

849 }, 

850 "source": { 

851 "accept": ["source"], "reject": ["final", "torus"] 

852 }, 

853 "remnant": { 

854 "accept": ["final", "torus"], "reject": [] 

855 }, 

856 "inclination": { 

857 "accept": ["theta", "iota", "viewing"], "reject": [] 

858 }, 

859 "spins": { 

860 "accept": ["spin", "chi_p", "chi_eff", "a_1", "a_2", "precession"], 

861 "reject": ["lambda", "final", "gamma", "order"] 

862 }, 

863 "spin_angles": { 

864 "accept": ["phi", "tilt", "beta"], "reject": [] 

865 }, 

866 "tidal": { 

867 "accept": [ 

868 "lambda", "gamma_", "log_pressure", 

869 "spectral_decomposition_gamma_", "compactness_", 

870 "tidal_disruption" 

871 ], 

872 "reject": [] 

873 }, 

874 "location": { 

875 "accept": [ 

876 "ra", "dec", "psi", "luminosity_distance", "redshift", 

877 "comoving_distance" 

878 ], 

879 "reject": ["mass_ratio", "radiated", "ram", "ran", "rat"] 

880 }, 

881 "timings": { 

882 "accept": ["time"], "reject": [] 

883 }, 

884 "SNR": { 

885 "accept": ["snr", "subdominant_multipoles"], "reject": [] 

886 }, 

887 "calibration": { 

888 "accept": ["spcal", "recalib", "frequency"], 

889 "reject": ["minimum", "tidal_disruption", "quasinormal"] 

890 }, 

891 "energy": { 

892 "accept": ["peak_luminosity", "radiated"], 

893 "reject": [] 

894 }, 

895 "others": { 

896 "accept": ["phase", "likelihood", "prior", "quasinormal"], 

897 "reject": ["spcal", "recalib"] 

898 } 

899 } 

900 return categories 

901 

902 def default_popular_options(self): 

903 """Return a list of popular options 

904 """ 

905 popular_options = [ 

906 "mass_1, mass_2", "luminosity_distance, theta_jn, ra, dec", 

907 "theta_jn, phi_12, phi_jl, tilt_1, tilt_2" 

908 ] 

909 return popular_options 

910 

911 def default_comparison_homepage_plots(self): 

912 """Return a list of default plots for the comparison homepage 

913 """ 

914 path = self.image_path["other"] 

915 base = os.path.join(path, "{}.png") 

916 contents = [ 

917 [base.format("combined_skymap"), base.format("compare_waveforms")] 

918 ] 

919 return contents 

920 

921 def default_corner_params(self): 

922 """Return a list of default corner parameters used by the corner 

923 plotting function 

924 """ 

925 return conf.gw_corner_parameters 

926 

927 def add_to_expert_pages(self, path, label): 

928 """Additional expert plots to add beyond the default. This returns a 

929 dictionary keyed by the parameter, with values providing the path 

930 to the additional plots you wish to add. The plots are a 2d list 

931 where each sublist represents a row in the table of images. 

932 

933 Parameters 

934 ---------- 

935 path: str 

936 path to the image directory 

937 label: str 

938 label of the plot you wish to add 

939 """ 

940 mydict = super(_WebpageGeneration, self).add_to_expert_pages( 

941 path, label 

942 ) 

943 contour_base = path + "{}_2d_contour_{}_log_likelihood.png" 

944 mydict.update({ 

945 "network_precessing_snr": [ 

946 [ 

947 contour_base.format(label, "_b_bar"), 

948 contour_base.format(label, "_precessing_harmonics_overlap"), 

949 ] 

950 ] 

951 }) 

952 return mydict 

953 

954 @property 

955 def additional_1d_pages(self): 

956 """Additional 1d histogram pages beyond one for each parameter. You may, 

957 for instance, want a 1d histogram page which combines multiple 

958 parameters. This returns a dictionary, keyed by the new 1d histogram 

959 page, with values indicating the parameters you wish to include on this 

960 page. Only the 1d marginalized histograms are shown. 

961 """ 

962 return conf.additional_1d_pages