Coverage for pesummary/core/webpage/main.py: 88.6%

848 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 sys 

5import uuid 

6from glob import glob 

7from pathlib import Path 

8import shutil 

9 

10import numpy as np 

11import math 

12 

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 

19 

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

21 

22 

23class PlotCaption(object): 

24 """Class to handle the generation of a plot caption 

25 

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 

35 

36 def __init__(self, plot="1d_histogram"): 

37 self.plot = plot 

38 

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) 

44 

45 

46class _WebpageGeneration(object): 

47 """Super class to handle the webpage generation for a given set of result 

48 files 

49 

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 self._additional_1d_pages = {label: [] for label in self.labels} 

178 if self.additional_1d_pages is not None: 

179 for j, _parameters in self.additional_1d_pages.items(): 

180 for i in self.labels: 

181 if all( 

182 param in self.samples[i].keys() for param in 

183 _parameters 

184 ): 

185 self._additional_1d_pages[i].append(j) 

186 self.categories = self.default_categories() 

187 self.popular_options = self.default_popular_options() 

188 self.navbar = { 

189 "home": self.make_navbar_for_homepage(), 

190 "result_page": self.make_navbar_for_result_page(), 

191 "comparison": self.make_navbar_for_comparison_page() 

192 } 

193 self.image_path = { 

194 "home": os.path.join(".", "plots", ""), 

195 "other": os.path.join("..", "plots", "") 

196 } 

197 self.results_path = { 

198 "home": "./samples/", "other": "../samples/" 

199 } 

200 self.config_path = { 

201 "home": "./config/", "other": "../config/" 

202 } 

203 if self.make_comparison: 

204 try: 

205 self.comparison_stats = self.generate_comparison_statistics() 

206 except Exception as e: 

207 self.comparison_stats = None 

208 logger.info( 

209 "Failed to generate comparison statistics because {}. As a " 

210 "result they will not be added to the webpages".format(e) 

211 ) 

212 

213 @property 

214 def _metafile(self): 

215 return ( 

216 "posterior_samples.json" if not self.hdf5 else 

217 "posterior_samples.h5" 

218 ) 

219 

220 @property 

221 def _total_number_of_labels(self): 

222 _number_of_labels = 0 

223 for item in [self.labels, self.existing_labels]: 

224 if isinstance(item, list): 

225 _number_of_labels += len(item) 

226 return _number_of_labels 

227 

228 def copy_css_and_js_scripts(self): 

229 """Copy css and js scripts from the package to the web directory 

230 """ 

231 import shutil 

232 from pesummary import core 

233 files_to_copy = [] 

234 path = core.__path__[0] 

235 scripts = glob(os.path.join(path, "js", "*.js")) 

236 for i in scripts: 

237 files_to_copy.append( 

238 [i, os.path.join(self.webdir, "js", os.path.basename(i))] 

239 ) 

240 scripts = glob(os.path.join(path, "css", "*.css")) 

241 for i in scripts: 

242 files_to_copy.append( 

243 [i, os.path.join(self.webdir, "css", os.path.basename(i))] 

244 ) 

245 for _dir in ["js", "css"]: 

246 try: 

247 os.mkdir(os.path.join(self.webdir, _dir)) 

248 except FileExistsError: 

249 pass 

250 for ff in files_to_copy: 

251 shutil.copy(ff[0], ff[1]) 

252 

253 def make_modal_carousel( 

254 self, html_file, image_contents, unique_id=False, **kwargs 

255 ): 

256 """Make a modal carousel for a table of images 

257 

258 Parameters 

259 ---------- 

260 html_file: pesummary.core.webpage.webpage.page 

261 open html file 

262 image_contents: list 

263 list of images to place in a table 

264 unique_id: Bool, optional 

265 if True, assign a unique identifer to the modal 

266 **kwargs: dict, optional 

267 all additional kwargs passed to `make_table_of_images` function 

268 """ 

269 if unique_id: 

270 unique_id = '{}'.format(uuid.uuid4().hex.upper()[:6]) 

271 else: 

272 unique_id = None 

273 html_file.make_table_of_images( 

274 contents=image_contents, unique_id=unique_id, **kwargs 

275 ) 

276 images = [y for x in image_contents for y in x] 

277 html_file.make_modal_carousel(images=images, unique_id=unique_id) 

278 return html_file 

279 

280 def generate_comparison_statistics(self): 

281 """Generate comparison statistics for all parameters that are common to 

282 all result files 

283 """ 

284 data = { 

285 i: self._generate_comparison_statistics( 

286 i, [self.samples[j][i] for j in self.labels] 

287 ) for i in self.same_parameters 

288 } 

289 return data 

290 

291 def _generate_comparison_statistics(self, param, samples): 

292 """Generate comparison statistics for a set of samples 

293 

294 Parameters 

295 ---------- 

296 samples: list 

297 list of samples for each result file 

298 """ 

299 from pesummary.utils.utils import kolmogorov_smirnov_test 

300 

301 rows = range(len(samples)) 

302 columns = range(len(samples)) 

303 ks = [ 

304 [ 

305 kolmogorov_smirnov_test([samples[i], samples[j]]) for i in 

306 rows 

307 ] for j in columns 

308 ] 

309 # JS divergence is symmetric and therefore we just need to loop over 

310 # one triangle 

311 js = np.zeros((len(samples), len(samples))) 

312 pdfs = self._kde_from_same_samples(param, samples) 

313 for num, i in enumerate(range(1, len(js))): 

314 for idx, j in enumerate(range(0, i)): 

315 js[i][idx] += jensen_shannon_divergence_from_pdfs( 

316 [pdfs[i], pdfs[j]] 

317 ) 

318 js = js + js.T 

319 return [ks, js.tolist()] 

320 

321 def _kde_from_same_samples(self, param, samples, **kwargs): 

322 """Generate KDEs for a set of samples 

323 

324 Parameters 

325 ---------- 

326 param: str 

327 The parameter that the samples belong to 

328 samples: list 

329 list of samples for each result file 

330 """ 

331 from pesummary.utils.utils import samples_to_kde 

332 return samples_to_kde(samples, **kwargs) 

333 

334 @staticmethod 

335 def get_executable(executable): 

336 """Return the path to an executable 

337 

338 Parameters 

339 ---------- 

340 executable: str 

341 the name of the executable you wish to find 

342 """ 

343 return shutil.which( 

344 executable, 

345 path=os.pathsep.join(( 

346 os.getenv("PATH", ""), 

347 str(Path(sys.executable).parent), 

348 )), 

349 ) 

350 

351 def _result_page_links(self): 

352 """Return the navbar structure for the Result Page tab. 

353 """ 

354 return [{i: i} for i in self.labels] 

355 

356 def make_navbar_for_homepage(self): 

357 """Make a navbar for the homepage 

358 """ 

359 links = [ 

360 "home", ["Result Pages", self._result_page_links()], "Logging", 

361 "Version" 

362 ] 

363 if self.make_comparison: 

364 links[1][1] += ["Comparison"] 

365 if self.publication: 

366 links.insert(2, "Publication") 

367 if self.notes is not None: 

368 links.append("Notes") 

369 return links 

370 

371 def make_navbar_for_result_page(self): 

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

373 """ 

374 links = { 

375 i: ["1d Histograms", [{"Custom": i}, {"All": i}]] for i in 

376 self.labels 

377 } 

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

379 _params = list(self.samples[label].keys()) 

380 if len(self._additional_1d_pages[label]): 

381 _params += self._additional_1d_pages[label] 

382 for j in self.categorize_parameters(_params): 

383 j = [j[0], [{k: label} for k in j[1]]] 

384 links[label].append(j) 

385 

386 final_links = { 

387 i: [ 

388 "home", ["Result Pages", self._result_page_links()], 

389 {"Corner": i}, {"Config": i}, links[i] 

390 ] for i in self.labels 

391 } 

392 if self.make_comparison: 

393 for label in self.labels: 

394 final_links[label][1][1] += ["Comparison"] 

395 _dummy_label = self.labels[0] 

396 if len(final_links[_dummy_label][1][1]) > 1: 

397 for label in self.labels: 

398 _options = [{l: "switch"} for l in self.labels if l != label] 

399 if self.make_comparison: 

400 _options.append({"Comparison": "switch"}) 

401 final_links[label].append(["Switch", _options]) 

402 if self.make_interactive: 

403 for label in self.labels: 

404 final_links[label].append( 

405 ["Interactive", [{"Interactive_Corner": label}]] 

406 ) 

407 if self.existing_plot is not None: 

408 for _label in self.labels: 

409 if _label in self.existing_plot.keys(): 

410 final_links[_label].append( 

411 {"Additional": _label} 

412 ) 

413 return final_links 

414 

415 def make_navbar_for_comparison_page(self): 

416 """Make a navbar for the comparison homepage 

417 """ 

418 if self.same_parameters is not None: 

419 links = ["1d Histograms", ["Custom", "All"]] 

420 for i in self.categorize_parameters(self.same_parameters): 

421 links.append(i) 

422 final_links = [ 

423 "home", ["Result Pages", self._result_page_links()], links 

424 ] 

425 final_links[1][1] += ["Comparison"] 

426 final_links.append( 

427 ["Switch", [{l: "switch"} for l in self.labels]] 

428 ) 

429 if self.make_interactive: 

430 final_links.append( 

431 ["Interactive", ["Interactive_Ridgeline"]] 

432 ) 

433 return final_links 

434 return None 

435 

436 def categorize_parameters( 

437 self, parameters, starting_letter=True, heading_all=True 

438 ): 

439 """Categorize the parameters into common headings 

440 

441 Parameters 

442 ---------- 

443 parameters: list 

444 list of parameters that you would like to sort 

445 """ 

446 params = [] 

447 for heading, category in self.categories.items(): 

448 if any( 

449 any(i[0] in j for j in category["accept"]) for i in parameters 

450 ): 

451 cond = self._condition( 

452 category["accept"], category["reject"], 

453 starting_letter=starting_letter 

454 ) 

455 part = self._partition(cond, parameters) 

456 if heading_all and len(part): 

457 part = ["{}_all".format(heading)] + part 

458 params.append([heading, part]) 

459 used_headings = [i[0] for i in params] 

460 other_index = \ 

461 used_headings.index("others") if "others" in used_headings else None 

462 other_params = [] 

463 for pp in parameters: 

464 if not any(pp in j[1] for j in params): 

465 if other_index is not None: 

466 params[other_index][1].append(pp) 

467 else: 

468 other_params.append(pp) 

469 if other_index is None: 

470 params.append(["others", other_params]) 

471 return params 

472 

473 def _condition(self, true, false, starting_letter=False): 

474 """Setup a condition 

475 

476 Parameters 

477 ---------- 

478 true: list 

479 list of strings that you would like to include 

480 false: list 

481 list of strings that you would like to neglect 

482 """ 

483 def _starting_letter(param, condition): 

484 if condition: 

485 return param[0] 

486 return param 

487 if len(true) != 0 and len(false) == 0: 

488 condition = lambda j: True if any( 

489 i in _starting_letter(j, starting_letter) for i in true 

490 ) else False 

491 elif len(true) == 0 and len(false) != 0: 

492 condition = lambda j: True if any( 

493 i not in _starting_letter(j, starting_letter) for i in false 

494 ) else False 

495 elif len(true) and len(false) != 0: 

496 condition = lambda j: True if any( 

497 i in _starting_letter(j, starting_letter) and all( 

498 k not in _starting_letter(j, starting_letter) for k in false 

499 ) for i in true 

500 ) else False 

501 return condition 

502 

503 def _partition(self, condition, array): 

504 """Filter the list according to a condition 

505 

506 Parameters 

507 ---------- 

508 condition: func 

509 lambda function containing the condition that you want to use to 

510 filter the array 

511 array: list 

512 List of parameters that you would like to filter 

513 """ 

514 return sorted(list(filter(condition, array))) 

515 

516 def generate_webpages(self): 

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

518 """ 

519 if self.add_to_existing: 

520 self.add_existing_data() 

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 

542 

543 def create_blank_html_pages(self, pages, stylesheets=[]): 

544 """Create blank html pages 

545 

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 ) 

554 

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. 

560 

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

589 

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 

613 

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) 

621 

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 

627 

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 

640 

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

663 

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 ) 

679 

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) 

688 

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) 

707 

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

720 

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) 

742 

743 def _make_1d_histogram_pages(self, pages): 

744 """Make the 1d histogram pages 

745 

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

982 

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) 

992 

993 def _make_additional_plots_pages(self, pages): 

994 """Make the additional plots pages 

995 

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

1058 

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) 

1065 

1066 def _make_corner_pages(self, pages): 

1067 """Make the corner pages 

1068 

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

1098 

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) 

1105 

1106 def _make_config_pages(self, pages): 

1107 """Make the config pages 

1108 

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

1161 

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) 

1175 

1176 def _make_comparison_pages(self, pages): 

1177 """Make pages to compare all result files 

1178 

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 

1197 

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

1212 

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) 

1229 

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) 

1247 

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

1288 

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) 

1305 

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

1318 

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

1376 

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) 

1388 

1389 def _make_interactive_pages(self, pages, html_files): 

1390 """Make a page that shows all interactive plots 

1391 

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

1442 

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) 

1449 

1450 def _make_error_page(self, pages): 

1451 """Make a page that is shown when something goes wrong 

1452 

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

1479 

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) 

1486 

1487 def _make_version_page(self, pages): 

1488 """Make a page to display the version information 

1489 

1490 Parameters 

1491 ---------- 

1492 pages: list 

1493 list of pages that you wish to create 

1494 """ 

1495 from pesummary._version_helper import install_path 

1496 

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

1537 

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) 

1544 

1545 def _make_logging_page(self, pages): 

1546 """Make a page to display the logging output from PESummary 

1547 

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

1566 

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

1576 

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) 

1583 

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 

1587 

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

1623 

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) 

1630 

1631 def _make_downloads_page(self, pages, fix_bottom=False): 

1632 """Make a page with links to files which can be downloaded 

1633 

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

1705 

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

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

1708 

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 

1764 

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) 

1771 

1772 def _make_notes_page(self, pages): 

1773 """Make a page to display the custom notes 

1774 

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

1796 

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

1814 

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 

1842 

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 [], [], [] 

1847 

1848 def default_popular_options(self): 

1849 """Return a list of default options 

1850 """ 

1851 return [] 

1852 

1853 def default_comparison_homepage_plots(self): 

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

1855 """ 

1856 return [] 

1857 

1858 def default_corner_params(self): 

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

1860 plotting function 

1861 """ 

1862 return [] 

1863 

1864 def add_existing_data(self): 

1865 """ 

1866 """ 

1867 from pesummary.utils.utils import _add_existing_data 

1868 

1869 self = _add_existing_data(self) 

1870 

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. 

1876 

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 

1898 

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