Loading [MathJax]/extensions/TeX/AMSsymbols.js
LALPulsar 7.1.0.1-02cf16d
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
pulsarhtmlutils.py
Go to the documentation of this file.
1# -*- coding: utf-8 -*-
2#
3# pulsarhtmlutils.py
4#
5# Copyright 2016
6# Matthew Pitkin <matthew.pitkin@ligo.org>
7#
8#
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation; either version 2 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program; if not, write to the Free Software
21# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22# MA 02110-1301, USA.
23
24"""
25Some helper classes and functions for outputing html and LaTeX pages
26"""
27
28from __future__ import print_function
29
30import re
31import numpy as np
32import math
33
34from lalpulsar.pulsarpputils import rad_to_dms, rad_to_hms
35
36# some parameter names for special LaTeX treatment in figures
37paramlatexdict = {
38 "H0": "$h_0$",
39 "COSIOTA": "$\\cos{\\iota}$",
40 "PSI": "$\\psi$ (rad)",
41 "PHI0": "$\\phi_0$ (rad)",
42 "RA": "$\\alpha$",
43 "DEC": "$\\delta$",
44 "RAJ": "$\\alpha$",
45 "DECJ": "$\\delta$",
46 "F0": "$f_0$ (Hz)",
47 "F1": "$\\dot{f}$ (Hz/s)",
48 "F2": "$\\ddot{f}$ (Hz/s$^2$)",
49 "F3": "$f_3$ (Hz/s$^3$)",
50 "F4": "$f_4$ (Hz/s$^4$)",
51 "F5": "$f_5$ (Hz/s$^5$)",
52 "F6": "$f_6$ (Hz/s$^6$)",
53 "F7": "$f_7$ (Hz/s$^7$)",
54 "F8": "$f_8$ (Hz/s$^8$)",
55 "F9": "$f_9$ (Hz/s$^9$)",
56 "F10": "$f_{10}$ (Hz/s$^{10}$)",
57 "LOGL": "$\\log{L}$",
58 "PMRA": "p.m. $\\alpha$ (rad/s)",
59 "PMDEC": "p.m. $\\delta$ (rad/s)",
60 "PMDC": "p.m. $\\delta$ (rad/s)",
61 "PX": "$\\pi$ (rad)",
62 "A1": "$a \\sin{i}$ (lt s)",
63 "A1_2": "$(a \\sin{i})_{2}$ (lt s)",
64 "A1_3": "$(a \\sin{i})_{3}$ (lt s)",
65 "SINI": "$\\sin{i}$",
66 "PB": "$P_b$ (s)",
67 "PB_2": "$(P_b)_2$ (s)",
68 "PB_3": "$(P_b)_3$ (s)",
69 "T0": "$T_0$ (s)",
70 "T0_2": "$(T_0)_2$ (s)",
71 "T0_3": "$(T_0)_3$ (s)",
72 "TASC": "$T_{\\\textrm{asc}}$ (s)",
73 "OM": "$\\omega_0$ (rad)",
74 "OM_2": "$(\\omega_0)_2$ (rad)",
75 "OM_3": "$(\\omega_0)_3$ (rad)",
76 "PBDT": "$\\dot{P}$ (s/s)",
77 "PBDOT": "$\\dot{P}$ (s/s)",
78 "GAMMA": "$\\gamma$",
79 "E": "$e$",
80 "ECC": "$e$",
81 "ECC_2": "$e_2$",
82 "ECC_3": "$e_3$",
83 "FB0": "$(f_b)_0$ (Hz)",
84 "FB1": "$(f_b)_1$ (Hz)",
85 "FB2": "$(f_b)_2$ (Hz)",
86 "FB3": "$(f_b)_3$ (Hz)",
87 "FB4": "$(f_b)_4$ (Hz)",
88 "FB5": "$(f_b)_5$ (Hz)",
89 "FB6": "$(f_b)_6$ (Hz)",
90 "FB7": "$(f_b)_7$ (Hz)",
91 "FB8": "$(f_b)_8$ (Hz)",
92 "FB9": "$(f_b)_9$ (Hz)",
93 "M2": "$m_2$ (kg)",
94 "MTOT": "$M$ (kg)",
95 "ELL": "$\\varepsilon$",
96 "H95": "$h_0^{95\\%}$",
97 "H0UL": "$h_0^{{{}\\%}}$",
98 "Q22": "$Q_{22}$\\,(kg\\,m$^2$)",
99 "SDRAT": "spin-down ratio",
100 "SDRAT95": "$h_0^{95\\%}$/h_0^{\\rm sd}$",
101 "SDLIM": "$h_0^{\\rm sd}$",
102 "F0ROT": "$f_{\\rm rot}$ (Hz)",
103 "F0GW": "$f_{\\rm gw}$ (Hz)",
104 "F1ROT": "$\\dot{f}_{\\rm rot}$ (Hz/s)",
105 "F1GW": "$\\dot{f}_{\\rm gw}$ (Hz/s)",
106 "SDPOWRAT": "power ratio (\\%)",
107 "OMDOT": "$\\dot{\\omega}$",
108 "OMDT": "$\\dot{\\omega}$",
109 "EPS1": "$\\epsilon_1$",
110 "EPS2": "$\\epsilon_2$",
111 "C22": "$C_{22}$",
112 "C21": "$C_{21}$",
113 "C22UL": "$C_{{22}}^{{{}\\%}}$",
114 "C21UL": "$C_{{21}}^{{{}\\%}}$",
115 "PHI22": "$\\phi_{22}$",
116 "PHI21": "$\\phi_{21}$",
117 "I31": "$I_{31}$",
118 "I21": "$I_{21}$",
119 "I31UL": "$I_{{31}}^{{{}\\%}}$",
120 "I21UL": "$I_{{21}}^{{{}\\%}}$",
121 "LAMBDA": "$\\lambda$ (rad)",
122 "COSTHETA": "$\\cos{\\\theta}$",
123 "DIST": "distance (kpc)",
124 "SNR": "$\\rho$",
125 "BSN": "$\\log{}_{10}\\left(B_{\\\textrm{SvN}}\\right)$",
126 "BCI": "$\\log{}_{10}\\left(B_{\\\textrm{CvI}}\\right)$",
127 "BCIN": "$\\log{}_{10}\\left(B_{\\\textrm{CvIN}}\\right)$",
128}
129
130
131# html text to display for different parameter names
132paramhtmldict = {
133 "RAJ": "&alpha;",
134 "DECJ": "&delta;",
135 "RA": "&alpha;",
136 "DEC": "&delta;",
137 "F0": "f<sub>0</sub> (Hz)",
138 "F1": "f<sub>1</sub> (Hz/s)",
139 "F2": "f<sub>2</sub> (Hz/s<sup>2</sup>)",
140 "F3": "f<sub>3</sub> (Hz/s<sup>3</sup>)",
141 "F4": "f<sub>4</sub> (Hz/s<sup>4</sup>)",
142 "F5": "f<sub>5</sub> (Hz/s<sup>5</sup>)",
143 "F6": "f<sub>6</sub> (Hz/s<sup>6</sup>)",
144 "F7": "f<sub>7</sub> (Hz/s<sup>7</sup>)",
145 "F8": "f<sub>8</sub> (Hz/s<sup>8</sup>)",
146 "F9": "f<sub>9</sub> (Hz/s<sup>9</sup>)",
147 "F10": "f<sub>10</sub> (Hz/s<sup>10</sup>)",
148 "F0ROT": "f<sub>rotation</sub> (Hz)",
149 "F1ROT": "Spin-down<sub>rotation</sub> (Hz/s)",
150 "F0GW": "f<sub>GW</sub> (Hz)",
151 "F1GW": "Spin-down<sub>GW</sub> (Hz/s)",
152 "PEPOCH": "epoch (MJD)",
153 "A1": "a sin<it>i</i> (lt s)",
154 "A1_2": "(a sin<it>i</i>)<sub>2</sub> (lt s)",
155 "A1_3": "(a sin<it>i</i>)<sub>3</sub> (lt s)",
156 "SINI": "sin<it>i</it>$",
157 "E": "<it>e</it>",
158 "ECC": "<it>e</it>",
159 "ECC_2": "<it>e</it><sub>2</sub>",
160 "ECC_3": "<it>e</it><sub>3</sub>",
161 "EPS1": "&epsilon;<sub>1</sub>",
162 "EPS2": "&epsilon;<sub>2</sub>",
163 "T0": "T<sub>0</sub> (MJD)",
164 "T0_2": "(T<sub>0</sub>)<sub>2</sub> (MJD)",
165 "T0_3": "(T<sub>0</sub>)<sub>3</sub> (MJD)",
166 "TASC": "T<sub>asc</sub> (MJD)",
167 "OM": "&omega;<sub>0</sub> (deg)",
168 "OM_2": "(&omega;<sub>0</sub>)<sub>2</sub> (deg)",
169 "OM_3": "(&omega;<sub>0</sub>)<sub>3</sub> (deg)",
170 "M2": "<it>m</it><sub>2</sub> (kg)",
171 "MTOT": "<it>M</it> (kg)",
172 "PB": "<it>P</it><sub>b</sub> (days)",
173 "PB_2": "(<it>P</it><sub>b</sub>)<sub>2</sub> (days)",
174 "PB_3": "(<it>P</it><sub>b</sub>)<sub>3</sub> (days)",
175 "FB0": "(<it>f</it><sub>b</sub>)<sub>0</sub> (Hz)",
176 "FB1": "(<it>f</it><sub>b</sub>)<sub>1</sub> (Hz)",
177 "FB2": "(<it>f</it><sub>b</sub>)<sub>2</sub> (Hz)",
178 "FB3": "(<it>f</it><sub>b</sub>)<sub>3</sub> (Hz)",
179 "FB4": "(<it>f</it><sub>b</sub>)<sub>4</sub> (Hz)",
180 "FB5": "(<it>f</it><sub>b</sub>)<sub>5</sub> (Hz)",
181 "FB6": "(<it>f</it><sub>b</sub>)<sub>6</sub> (Hz)",
182 "FB7": "(<it>f</it><sub>b</sub>)<sub>7</sub> (Hz)",
183 "FB8": "(<it>f</it><sub>b</sub>)<sub>8</sub> (Hz)",
184 "FB9": "(<it>f</it><sub>b</sub>)<sub>9</sub> (Hz)",
185 "H0": "h<sub>0</sub>",
186 "C21": "C<sub>21</sub>",
187 "C21UL": "C<sub>21</sub><sup>{}%</sup>",
188 "C22": "C<sub>22</sub>",
189 "C22UL": "C<sub>22</sub><sup>{}%</sup>",
190 "I21": "I<sub>21</sub>",
191 "I21UL": "I<sub>21</sub><sup>{}%</sup>",
192 "I31": "I<sub>31</sub>",
193 "I31UL": "I<sub>31</sub><sup>{}%</sup>",
194 "COSIOTA": "cos&iota;",
195 "PSI": "&psi; (rad)",
196 "PHI0": "&phi;<sub>0</sub> (rad)",
197 "PHI21": "&phi;<sub>21</sub> (rad)",
198 "PHI22": "&phi;<sub>22</sub> (rad)",
199 "PMRA": "p.m. &alpha; (rad/s)",
200 "PMDC": "p.m. &delta; (rad/s)",
201 "PMDEC": "p.m. &delta; (rad/s)",
202 "PX": "&pi; (rad)",
203 "DIST": "Distance (kpc)",
204 "SDLIM": "Spin-down limit",
205 "ELL": "&#949;",
206 "SDRAT": "ratio",
207 "H95": "h<sub>0</sub><sup>95%</sup>",
208 "H0UL": "h<sub>0</sub><sup>{}%</sup>",
209 "H0PRIOR": "h<sub>0</sub><sup>95%</sup> prior",
210 "SDPOWRAT": "power ratio (%)",
211 "Q22": "Q<sub>22</sub> (kg m<sup>2</sup>)",
212 "BSN": "log<sub>10</sub>(B<sub>SvN</sub>)",
213 "BCI": "log<sub>10</sub>(B<sub>CvI</sub>)",
214 "BCIN": "log<sub>10</sub>(B<sub>CvIN</sub>)",
215 "MAXL": "log<sub>10</sub>(max. L)",
216 "SNR": "&rho;",
217}
218
219
220# function to return a float number to a given number of significant figures
221def sigfig(x, sf):
222 return round(x, -int(math.floor(math.log10(abs(x))) - (sf - 1)))
223
224
225# function will return a string with the number (input as a string) to two decimal
226# places if it is greater than |0.01|, or the number in exponent for to one decimal
227# place it it is smaller
228def dec_or_exp(f, dp=2, horl="html"):
229 fv = float(f)
230 if np.abs(fv) > 0.01 and np.abs(fv) < 1000.0:
231 if horl == "html":
232 return repr(round(fv, dp))
233 else:
234 return "$%s$" % repr(round(fv, dp))
235 else:
236 return exp_str(fv, dp, otype=horl)
237
238
239# a class containing functions to output html parameter values in the appropriate format
241 def RAJ(f, stype="hms"): # default to output in hh:mm:ss.s format
242 if stype == "hms":
243 return ra_str(f)
244 else: # output in radians
245 return dec_or_exp(f)
246
247 def RA(f, stype="hms"): # default to output in hh:mm:ss.s format
248 if stype == "hms":
249 return ra_str(f)
250 else: # output in radians
251 return dec_or_exp(f)
252
253 def DECJ(f, stype="dms"): # default to output in dd:mm:ss.s format
254 if stype == "dms":
255 return dec_str(f)
256 else: # output in radians
257 return dec_or_exp(f)
258
259 def DEC(f, stype="dms"): # default to output in dd:mm:ss.s format
260 if stype == "dms":
261 return dec_str(f)
262 else: # output in radians
263 return dec_or_exp(f)
264
265 def PMRA(f):
266 return dec_or_exp(f)
267
268 def PMDEC(f):
269 return dec_or_exp(f)
270
271 def PMDC(f):
272 return dec_or_exp(f)
273
274 def F0(f, dp=5): # default to returning with 5
275 return dec_or_exp(f, dp=dp)
276
277 def F1(f):
278 return exp_str(float(f), 2)
279
280 def F2(f):
281 return exp_str(float(f), 2)
282
283 def F3(f):
284 return exp_str(float(f), 2)
285
286 def F4(f):
287 return exp_str(float(f), 2)
288
289 def F5(f):
290 return exp_str(float(f), 2)
291
292 def F6(f):
293 return exp_str(float(f), 2)
294
295 def F7(f):
296 return exp_str(float(f), 2)
297
298 def F8(f):
299 return exp_str(float(f), 2)
300
301 def F9(f):
302 return exp_str(float(f), 2)
303
304 def F10(f):
305 return exp_str(float(f), 2)
306
307 def PEPOCH(f):
308 return "%.1f" % float(
309 repr(44244.0 + (float(f) + 51.184) / 86400.0)
310 ) # return epoch as an float (converted from GPS to MJD)
311
312 def A1(f):
313 return dec_or_exp(f)
314
315 def E(f):
316 return dec_or_exp(f)
317
318 def EPS1(f):
319 return dec_or_exp(f)
320
321 def EPS2(f):
322 return dec_or_exp(f)
323
324 def M2(f):
325 return dec_or_exp(f)
326
327 def MTOT(f):
328 return dec_or_exp(f)
329
330 def SINI(f):
331 return dec_or_exp(f)
332
333 def T0(f, stype=None):
334 if stype == "diff":
335 return dec_or_exp(repr((float(f) + 51.184) / 86400.0), dp=2)
336 else:
337 return "%.2f" % float(
338 repr(44244.0 + ((float(f) + 51.184) / 86400.0))
339 ) # convert from GPS to MJD for display
340
341 def TASC(f, stype=None):
342 if stype == "diff":
343 return dec_or_exp(repr((float(f) + 51.184) / 86400.0), dp=2)
344 else:
345 return "%.2f" % float(
346 repr(44244.0 + ((float(f) + 51.184) / 86400.0))
347 ) # convert from GPS to MJD for display
348
349 def OM(f):
350 return dec_or_exp(
351 repr(float(f) * 180.0 / math.pi), dp=1
352 ) # convert from rads to deg
353
354 def PB(f):
355 return dec_or_exp(repr(float(f) / 86400.0)) # convert from seconds to days
356
357 def H0(f):
358 return exp_str(float(f), 1)
359
360 def H0UL(f):
361 return exp_str(float(f), 1)
362
363 def C21(f):
364 return exp_str(float(f), 1)
365
366 def C21UL(f):
367 return exp_str(float(f), 1)
368
369 def C22(f):
370 return exp_str(float(f), 1)
371
372 def C22UL(f):
373 return exp_str(float(f), 1)
374
375 def I21(f):
376 return exp_str(float(f), 1)
377
378 def I21UL(f):
379 return exp_str(float(f), 1)
380
381 def I31(f):
382 return exp_str(float(f), 1)
383
384 def I31UL(f):
385 return exp_str(float(f), 1)
386
387 def COSIOTA(f):
388 return dec_or_exp(f)
389
390 def PHI0(f):
391 return dec_or_exp(f)
392
393 def PHI22(f):
394 return dec_or_exp(f)
395
396 def PHI21(f):
397 return dec_or_exp(f)
398
399 def PSI(f):
400 return dec_or_exp(f)
401
402 def ELL(f):
403 return exp_str(float(f), 1)
404
405 def SDLIM(f):
406 return exp_str(float(f), 1)
407
408 def SDRAT(f):
409 fsf = sigfig(float(f), 2) # get value rounded to 2 significant figure
410 if fsf < 1.0: # if spin-down ratio is less than 1
411 return "%.2f" % fsf
412 elif fsf < 10.0: # if spin-down ratio is less than 10
413 return "%.1f" % fsf
414 else: # otherwise round to the nearest integer
415 return "%d" % round(fsf)
416
417 def DIST(f):
418 return "%.1f" % float(f)
419
420 def SDPOWRAT(f):
421 return "%d" % round(float(f))
422
423 def Q22(f):
424 return dec_or_exp(f, dp=1) # quadrupole moment
425
426 def F0ROT(f):
427 return dec_or_exp(f)
428
429 def F0GW(f):
430 return dec_or_exp(f)
431
432 def F1ROT(f):
433 return exp_str(float(f), 1)
434
435 def F1GW(f):
436 return exp_str(float(f), 1)
437
438 def PMRA(f):
439 return dec_or_exp(f)
440
441 def PMDC(f):
442 return dec_or_exp(f)
443
444 def BSN(f):
445 return dec_or_exp(f)
446
447 def BCI(f):
448 return dec_or_exp(f)
449
450 def BCIN(f):
451 return dec_or_exp(f)
452
454 return f
455
456
457# a class for outputting parameter values to the table
459 def ELL(f):
460 return exp_str(float(f), 1, "latex")
461
462 def H95(f):
463 return exp_str(float(f), 1, "latex")
464
465 def H0(f):
466 return exp_str(float(f), 1, "latex")
467
468 def H0UL(f):
469 return exp_str(float(f), 1, "latex")
470
471 def C21(f):
472 return exp_str(float(f), 1, "latex")
473
474 def C21UL(f):
475 return exp_str(float(f), 1, "latex")
476
477 def C22(f):
478 return exp_str(float(f), 1, "latex")
479
480 def C22UL(f):
481 return exp_str(float(f), 1, "latex")
482
483 def I21(f):
484 return exp_str(float(f), 1, "latex")
485
486 def I21UL(f):
487 return exp_str(float(f), 1, "latex")
488
489 def I31(f):
490 return exp_str(float(f), 1, "latex")
491
492 def I31UL(f):
493 return exp_str(float(f), 1, "latex")
494
495 def H0PRIOR(f):
496 return exp_str(float(f), 1, "latex")
497
498 def SDLIM(f):
499 return exp_str(float(f), 1, "latex")
500
501 def SDRAT(f):
502 fsf = sigfig(float(f), 2) # get value rounded to 2 significant figure
503 if fsf < 1.0: # if spin-down ratio is less than 1
504 return "%.2f" % fsf
505 elif fsf < 10.0: # if spin-down ratio is less than 10
506 return "%.1f" % fsf
507 else: # otherwise round to the nearest integer
508 return "%d" % fsf
509
510 def RAJ(f):
511 return ra_str(f, "latex") # RA in string format
512
513 def DECJ(f):
514 return dec_str(f, "latex") # dec in string format
515
516 def RA(f):
517 return ra_str(f, "latex") # RA in string format
518
519 def DEC(f):
520 return dec_str(f, "latex") # dec in string format
521
522 def PMRA(f):
523 return dec_or_exp(f, horl="latex")
524
525 def PMDEC(f):
526 return dec_or_exp(f, horl="latex")
527
528 def PMDC(f):
529 return dec_or_exp(f, horl="latex")
530
531 def M2(f):
532 return dec_or_exp(f, horl="latex")
533
534 def MTOT(f):
535 return dec_or_exp(f, horl="latex")
536
537 def DIST(f):
538 return "%.1f" % float(f)
539
540 def SDPOWRAT(f):
541 return "%d" % int(f)
542
543 def Q22(f):
544 return exp_str(float(f), 1, "latex") # quadrupole moment
545
546 def F0(f):
547 return "%.2f" % float(f)
548
549 def F0ROT(f):
550 return "%.2f" % float(f)
551
552 def F0GW(f):
553 return "%.2f" % float(f)
554
555 def F1(f):
556 return exp_str(float(f), 1, "latex")
557
558 def F2(f):
559 return exp_str(float(f), 1, "latex")
560
561 def F3(f):
562 return exp_str(float(f), 1, "latex")
563
564 def F4(f):
565 return exp_str(float(f), 1, "latex")
566
567 def F5(f):
568 return exp_str(float(f), 1, "latex")
569
570 def F6(f):
571 return exp_str(float(f), 1, "latex")
572
573 def F7(f):
574 return exp_str(float(f), 1, "latex")
575
576 def F8(f):
577 return exp_str(float(f), 1, "latex")
578
579 def F9(f):
580 return exp_str(float(f), 1, "latex")
581
582 def F10(f):
583 return exp_str(float(f), 1, "latex")
584
585 def F1ROT(f):
586 return exp_str(float(f), 1, "latex")
587
588 def F1GW(f):
589 return exp_str(float(f), 1, "latex")
590
591 def BSN(f):
592 return dec_or_exp(f, horl="latex")
593
594 def BCI(f):
595 return dec_or_exp(f, horl="latex")
596
597 def BCIN(f):
598 return dec_or_exp(f, horl="latex")
599
601 return f
602
603
604class htmltag:
605 """
606 A class to create a html tag
607 """
608
610 self, tag, tagtext="", tagclass="", tagid="", tagstyle="", newline=False
611 ):
612 self._taginfo = {}
613 self.set_tag(tag) # the name of the tag
614 self.set_tagtext(tagtext) # the text to go into the tag
615 self.set_tagclass(tagclass) # the tag class
616 self.set_tagid(tagid) # the tag id
617 self.set_tagstyle(tagstyle) # the tag style
618 self.set_tagextra("") # any additional formatting
619
620 if newline:
621 self._newline = "\n" # whether to add a new line after the tag
622 else:
623 self._newline = ""
624
625 # set the tag format
626 self._tagdata = (
627 '<{tag} class="{class}" id="{id}" style="{style}"{extra}>{text}</{tag}>'
628 + self._newline
629 )
630
631 def __iadd__(self, ttext):
632 """
633 Overload the += operator to append text to tagtext
634 """
635 if not isinstance(ttext, str) and not isinstance(ttext, unicode):
636 raise ValueError("Error... appended text must be a string.")
637 else:
638 self.set_tagtext(self._taginfo["text"] + ttext)
639 return self
640
641 @property
642 def tag(self):
643 return self._taginfo["tag"]
644
645 def set_tag(self, t):
646 if not isinstance(t, str) and not isinstance(t, unicode):
647 raise ValueError("Error... 'tag' must be a string.")
648 else:
649 self._taginfo["tag"] = t
650
651 @property
652 def tagclass(self):
653 return self._taginfo["class"]
654
655 def set_tagclass(self, tclass):
656 if not isinstance(tclass, str) and not isinstance(tclass, unicode):
657 raise ValueError("Error... 'class' text must be a string.")
658 else:
659 self._taginfo["class"] = tclass
660
661 @property
662 def tagid(self):
663 return self._taginfo["id"]
664
665 def set_tagid(self, tid):
666 if not isinstance(tid, str) and not isinstance(tid, unicode):
667 raise ValueError("Error... 'id' text must be a string.")
668 else:
669 self._taginfo["id"] = tid
670
671 @property
672 def tagstyle(self):
673 return self._taginfo["style"]
674
675 def set_tagstyle(self, tstyle):
676 if not isinstance(tstyle, str) and not isinstance(tstyle, unicode):
677 raise ValueError("Error... 'style' text must be a string.")
678 else:
679 self._taginfo["style"] = tstyle
680
681 @property
682 def tagtext(self):
683 return self._taginfo["text"]
684
685 def set_tagtext(self, ttext):
686 if not isinstance(ttext, str) and not isinstance(ttext, unicode):
687 raise ValueError("Error... tag text must be a string.")
688 else:
689 self._taginfo["text"] = ttext
690
691 @property
692 def tagextra(self):
693 return self._taginfo["extra"]
694
695 def set_tagextra(self, textra):
696 if not isinstance(textra, str) and not isinstance(textra, unicode):
697 raise ValueError("Error... 'extra' tag text must be a string.")
698 else:
699 space = "" # add no space
700 if len(textra) > 0:
701 space = " " # add a space
702 self._taginfo["extra"] = space + textra
703
704 @property
705 def taginfo(self):
706 return self._taginfo
707
708 @property
709 def text(self):
710 # return the full tag
711 return self._tagdata.format(**self.taginfo)
712
713 def __str__(self):
714 return self.text
715
716
717class atag(htmltag):
718 """
719 Class for a link tag
720 """
721
722 def __init__(self, link, linktext="", linkclass="", linkid="", linkstyle=""):
723 """
724 Input the link and the text that the link surrounds
725 """
726 if linktext == "": # if no link text is given then just use the link itself
727 linktext = link
728
729 htmltag.__init__(self, "a", linktext, linkclass, linkid, linkstyle)
730 self.set_tagextra('href="{}"'.format(link)) # add href
731
732
733class htmltable(htmltag):
734 """
735 Class to make and return a html table
736 """
737
738 def __init__(self, tag="table", tableclass="", tableid="", tablestyle=""):
739 htmltag.__init__(
740 self, "table", tagclass=tableclass, tagid=tableid, tagstyle=tablestyle
741 )
742
743 self._rows = []
744 self._nrows = 0 # number of rows
745 self._thisrow = -1 # the index of the current row given row additions
746
747 @property
748 def tabletext(self):
749 innertable = ""
750 for row in self._rows:
751 rowtxt = ""
752 for data in row["data"]:
753 td = "td"
754 if data["header"]:
755 td = "th" # use header <th> tags for this value
756 datatag = htmltag(
757 td, data["text"], data["class"], data["id"], data["style"]
758 )
759 datatag.set_tagextra(
760 'rowspan="{rowspan}" colspan="{colspan}"'.format(**data)
761 )
762 rowtxt += datatag.text + " " # add space between <td> elements
763 rowtag = htmltag(
764 "tr", rowtxt, row["class"], row["id"], row["style"], newline=True
765 )
766 innertable += rowtag.text
767 self.set_tagtext(innertable)
768 return self.text
769
770 def addrow(self, rowclass="", rowid="", rowstyle=""):
771 """
772 Add a new empty row dictionary to the list and increment the current row index
773 """
774 row = {"data": [], "class": rowclass, "id": rowid, "style": rowstyle}
775 self._rows.append(row)
776 self._nrows += 1 # number of rows
777 self._thisrow += 1 # the index of the row that has just been added
778
779 def deleterow(self, rowidx):
780 """
781 Delete a row
782 """
783 if rowidx > self._nrows - 1:
784 print(
785 "Warning... cannot delete row '%d'. Only %d row in table."
786 % (rowdix, self._nrows)
787 )
788 else:
789 self._rows.pop(rowidx) # remove row
790 self._nrows -= 1
791 self._thisrow -= 1
792
793 def adddata(
794 self,
795 datatext,
796 dataclass="",
797 dataid="",
798 datastyle="",
799 header=False,
800 rowspan=0,
801 colspan=0,
802 rowidx=None,
803 ):
804 """
805 Add table data <td> (or <th> is header is True) tags to a given row
806 """
807 if rowidx is None:
808 rowidx = self._thisrow
809
810 if rowidx > len(self._rows) - 1:
811 raise ValueError("Warning... row index is out of range.")
812 else:
813 td = {
814 "text": datatext,
815 "class": dataclass,
816 "id": dataid,
817 "style": datastyle,
818 "header": header,
819 "rowspan": "",
820 "colspan": "",
821 }
822 if rowspan > 0:
823 td["rowspan"] = str(int(rowspan))
824 if colspan > 0:
825 td["colspan"] = str(int(colspan))
826
827 self._rows[rowidx]["data"].append(td)
828
829 def __str__(self):
830 return self.tabletxt
831
832
833class latextable:
834 """
835 Class to make a return a LaTeX table
836 """
837
838 def __init__(
839 self,
840 ncolumns=1,
841 columnalign="c",
842 caption="",
843 label="",
844 floatval="h",
845 preamble="",
846 postamble="",
847 ):
848 """
849 Create a table environment with `ncolumns` columns positioned with `columnpos`
850 """
851 self._tableinfo = {} # dictionary containing the table data
852
853 self.set_ncolumns(ncolumns) # set number of columns
854 self.set_columnalign(columnalign) # set column text alignment
855 self.set_caption(caption) # set table caption
856 self.set_label(label) # set table label
857 self.set_floatval(floatval) # set floating environment position
858 self.set_preamble(preamble) # set any preamble before the tabular environment
859 self.set_postamble(
860 postamble
861 ) # set any text to go after the tabular environment
862
863 self._rows = [] # a list of row data
864 self._nrows = 0 # number of rows
865 self._thisrow = -1 # the index of the current row given row additions
866
867 # set the table format
868 self._tableformat = "\\begin{{table}}{{{floatval}}}\n{preamble}\\caption{{{caption}\\label{{{label}}}}}\n\\begin{{tabular}}{{{columnalign}}}\n{table}\n\\end{{tabular}}\n{postamble}\n\\end{{table}}"
869 self._tableinfo["data"] = ""
870
871 def set_ncolumns(self, ncolumns):
872 # set number of columns in table
873 self._ncolumns = ncolumns
874
875 def set_columnalign(self, columnalign):
876 # set the alignment of data within each column (if a list then this should be equal in length to ncolumns)
877 if isinstance(columnalign, list):
878 if len(columnalign) != self._ncolumns:
879 raise ValueError(
880 "Error... number of column alignments is not equal to the number of columns."
881 )
882 else:
883 for ca in columnalign:
884 if not isinstance(ca, str) and not isinstance(ca, unicode):
885 raise TypeError(
886 "Error... columnalign must be a list of strings."
887 )
888
889 self._columnalign = columnalign
890 else:
891 if isinstance(columnalign, str) or isinstance(columnalign, unicode):
892 if len(columnalign) == 1:
893 self._columnalign = [columnalign for _ in range(self._ncolumns)]
894 else:
895 self._columnalign = [columnalign]
896 else:
897 raise TypeError("Error... columnalign must be a list or a string.")
898
899 self._tableinfo["columnalign"] = " ".join(self._columnalign)
900
901 def set_label(self, label):
902 # set the label
903 self._tableinfo["label"] = label
904
905 @property
906 def label(self):
907 return self._tableinfo["label"]
908
909 def set_caption(self, caption):
910 # set the table caption
911 self._tableinfo["caption"] = caption
912
913 @property
914 def caption(self):
915 return self._tableinfo["caption"]
916
917 def set_floatval(self, floatval):
918 # set the floating environment position
919 self._tableinfo["floatval"] = floatval
920
921 def set_preamble(self, preamble):
922 # set any preamble before the tabular environment
923 self._tableinfo["preamble"] = preamble
924
925 @property
926 def preamble(self):
927 return self._tableinfo["preamble"]
928
929 def set_postamble(self, postamble):
930 # set any text to go after the tabular environment
931 self._tableinfo["postamble"] = postamble
932
933 @property
934 def postamble(self):
935 return self._tableinfo["postamble"]
936
937 def addrow(self, underline=False):
938 # add an empty row (underline will add a horizontal rule below the row)
939 row = {"data": [], "underline": underline}
940 self._rows.append(row)
941 self._nrows += 1 # number of rows
942 self._thisrow += 1 # the index of the row that has just been added
943
944 def addhrule(self, rowidx=None):
945 # add horizontal rule
946 if rowidx == None: # add horizontal rule as new row
947 self.addrow(underline=True)
948 else:
949 self._rows[rowidx]["underline"] = True
950
951 def adddata(self, datatxt, multicolumn=0, mcalign="c", rowidx=None):
952 # add data to a row
953 if rowidx is None:
954 rowidx = self._thisrow
955
956 if rowidx > len(self._rows) - 1:
957 raise ValueError("Warning... row index is out of range.")
958 else:
959 rowdata = {"text": datatxt}
960 if multicolumn != 0:
961 rowdata["multicolumn"] = multicolumn
962 rowdata["mcalign"] = mcalign
963
964 self._rows[rowidx]["data"].append(rowdata)
965
966 @property
967 def tabletext(self):
968 # output the full table
969 self._tableinfo["table"] = ""
970 for i, row in enumerate(self._rows):
971 rowtxt = []
972 ncols = 0
973 for data in row["data"]:
974 val = data["text"]
975 if isinstance(val, float) or isinstance(
976 val, int
977 ): # if a number convert into a string
978 val = repr(val)
979 if "multicolumn" in data:
980 ncols += data["multicolumn"]
981 rowtxt.append(
982 "\\multicolumn{%d}{%s}{%s} "
983 % (data["multicolumn"], data["mcalign"], val)
984 )
985 else:
986 ncols += 1
987 rowtxt.append(val + " ")
988 if ncols != self._ncolumns and (
989 len(rowtxt) != 0 and row["underline"] == False
990 ):
991 raise ValueError("Error... too many or too few inputs in row '%d'." % i)
992 if len(rowtxt) != 0:
993 self._tableinfo["table"] += "&".join(rowtxt) + "\\\n"
994 if row["underline"]: # add horizontal rule below row
995 self._tableinfo["table"] += "\\hline\n"
996
997 self._tabletext = self._tableformat.format(**self._tableinfo)
998 return self._tabletext
999
1000
1001# convert a floating point number into a string in X.X x 10^Z format
1002def exp_str(f, p=1, otype="html"):
1003 if p > 16:
1004 print("Precision must be less than 16 d.p.", file=sys.stderr)
1005 p = 16
1006
1007 s = "%.16e" % f
1008 ssplit = s.split("e")
1009 if otype.lower() == "html": # output html format
1010 return "%.*f&times;10<sup>%d</sup>" % (p, float(ssplit[0]), int(ssplit[1]))
1011 elif otype.lower() == "latex": # output LaTeX format
1012 return "\\ensuremath{%.*f\\!\\times\\!10^{%d}}" % (
1013 p,
1014 float(ssplit[0]),
1015 int(ssplit[1]),
1016 )
1017 else:
1018 raise ValueError("Error... 'otype' must be 'html' or 'latex'.")
1019
1020
1021# convert a right ascension string in format 'hh:mm:ss.s' to a html/LaTeX string like H^h M^m S^s.ss
1022def ra_str(ra, otype="html"):
1023 if isinstance(ra, str):
1024 hms = ra.split(":")
1025 elif isinstance(ra, float):
1026 hms = [str(v) for v in rad_to_hms(ra)]
1027 else:
1028 raise ValueError("Error... ra must be a string or a float.")
1029
1030 if len(hms) == 1:
1031 hms.append("0")
1032 hms.append("0")
1033 elif len(hms) == 2:
1034 hms.append("0")
1035
1036 ss = ("%.2f" % float(hms[2])).split(".")
1037
1038 if otype.lower() == "html": # return html string
1039 return "%s<sup>h</sup>%s<sup>m</sup>%s<sup>s</sup>.%s" % (
1040 hms[0].zfill(2),
1041 hms[1].zfill(2),
1042 ss[0].zfill(2),
1043 ss[1].zfill(2),
1044 )
1045 elif otype.lower() == "latex": # return LaTeX string
1046 return "$%s^{\\rm h}%s^{\\rm m}%s^{\\rm s}\\!.%s$" % (
1047 hms[0].zfill(2),
1048 hms[1].zfill(2),
1049 ss[0].zfill(2),
1050 ss[1].zfill(2),
1051 )
1052 else:
1053 raise ValueError("Error... 'otype' input must be 'html' or 'latex'")
1054
1055
1056# convert a declination string in format 'dd:mm:ss.s' to a html/LaTeX string like dd^o mm' ss''.ss
1057def dec_str(dec, otype="html"):
1058 if isinstance(dec, str):
1059 dms = dec.split(":")
1060 elif isinstance(dec, float):
1061 dms = [str(v) for v in rad_to_dms(dec)]
1062 else:
1063 raise ValueError("Error... dec must be a string or a float.")
1064
1065 if len(dms) == 1:
1066 dms.append("0")
1067 dms.append("0")
1068 elif len(dms) == 2:
1069 dms.append("0")
1070
1071 ss = ("%.2f" % float(dms[2])).split(".")
1072
1073 if otype.lower() == "html": # html output
1074 return "%s&deg;%s'%s\".%s" % (
1075 (re.sub(r"\+", "", dms[0])).zfill(2),
1076 dms[1].zfill(2),
1077 ss[0].zfill(2),
1078 ss[1].zfill(2),
1079 )
1080 elif otype.lower() == "latex": # LaTeX output
1081 return "$%s^{\\circ}%s'%s''\\!.%s$" % (
1082 (re.sub(r"\+", "", dms[0])).zfill(2),
1083 dms[1].zfill(2),
1084 ss[0].zfill(2),
1085 ss[1].zfill(2),
1086 )
1087 else:
1088 raise ValueError("Error... 'otype' must be 'html' or 'latex'.")
1089
1090
1091"""
1092CSS files for results pages
1093"""
1094
1095# css file for the standard individual pulsar result page
1096result_page_css = """
1097/* create body style */
1098body {
1099 font-family: "Avant Garde", Avantegarde, Verdana, Geneva, "Trebuchet MS", sans-serif;
1100}
1101
1102/* create header name style */
1103h1 {
1104 margin: 0px 0px 0px 0px;
1105 padding: 4px 4px 8px 4px;
1106 font-size: 20px;
1107 font-weight: bold;
1108 letter-spacing: 0px;
1109 font-family: "Avant Garde", Avantegarde, Verdana, Geneva, "Trebuchet MS", Sans-Serif;
1110 background-color: darkolivegreen;
1111}
1112
1113h1 > a:link {
1114 color: white;
1115 text-shadow: 2px 2px 2px #1c2310;
1116 text-decoration: none;
1117}
1118
1119h1 > a:visited {
1120 color: white;
1121 text-shadow: 2px 2px 2px #1c2310;
1122 text-decoration: none;
1123}
1124
1125h1 > a:hover {
1126 color: white;
1127 text-shadow: 2px 2px 2px #7fa046;
1128 text-decoration: none;
1129}
1130
1131h2 {
1132 margin: 0 0 8px 0;
1133 padding: 4px 4px 8px 4px;
1134 font-size: 16px;
1135 font-weight: bold;
1136 font-family: "Avant Garde", Avantegarde, Verdana, Geneva, "Trebuchet MS", Sans-Serif;
1137 text-shadow: 1px 1px 1px #333300;
1138 background-color: #666600;
1139 color: white
1140}
1141
1142/* create footer style */
1143#footer {
1144 border-top: 1px solid #999;
1145 padding: 15px;
1146 font-family: monospace;
1147 text-align: left;
1148}
1149
1150/* create a class for a posterior plot image */
1151.posplot{
1152 height: 400px;
1153 border: 0px solid #999;
1154}
1155
1156/* create a class for a full joint posterior plot image */
1157.jointplot{
1158 height: 600px;
1159 border: 0px solid #999;
1160}
1161
1162/* create a class for a background distribution plot image */
1163.backgroundplot{
1164 height: 400px;
1165 border: 0px solid #999;
1166}
1167
1168/* create a class for a Bk data plot */
1169.dataplot{
1170 height: 275px;
1171}
1172
1173/* create class for an amplitude spectral density plot */
1174.asdplot{
1175 height: 275px;
1176}
1177
1178/* create class for an MCMC chain plot */
1179.chainplot{
1180 height: 275px;
1181}
1182
1183/* style for links list */
1184.pagelinks {
1185 background-color: darkolivegreen;
1186 font-family: "Avant Garde", Avantegarde, Verdana, Geneva, "Trebuchet MS", Sans-Serif;
1187 overflow: hidden;
1188 color: white;
1189 font-size: 16px;
1190 padding: 0px 0px 3px 3px;
1191 margin: 0px 0px 8px 0px;
1192 text-shadow: 2px 2px 2px #1c2310;
1193}
1194
1195div.pagelinks a:link {
1196 color: white;
1197 text-shadow: 2px 2px 2px #1c2310;
1198 text-decoration: none;
1199}
1200
1201div.pagelinks a:visited {
1202 color: white;
1203 text-shadow: 2px 2px 2px #1c2310;
1204 text-decoration: none;
1205}
1206
1207div.pagelinks a:hover {
1208 color: white;
1209 text-shadow: 2px 2px 2px #7fa046;
1210 text-decoration: none;
1211}
1212
1213/* pulsar parameter table class */
1214.pulsartable {
1215 background-color: floralwhite;
1216 border: 0px solid;
1217 border-radius: 4px;
1218 box-shadow: 2px 2px 2px 2px #d8d8d8;
1219 -webkit-box-shadow: 2px 2px 2px 2px #d8d8d8;
1220 -moz-box-shadow: 2px 2px 2px 2px #d8d8d8;
1221 padding: 4px 4px 4px 4px;
1222}
1223
1224/* upper limits table class */
1225.limitstable {
1226 background-color: floralwhite;
1227 border: 0px solid;
1228 border-radius: 4px;
1229 box-shadow: 2px 2px 2px 2px #d8d8d8;
1230 -webkit-box-shadow: 2px 2px 2px 2px #d8d8d8;
1231 -moz-box-shadow: 2px 2px 2px 2px #d8d8d8;
1232 padding: 4px 4px 4px 4px;
1233}
1234
1235/* background evidence table class */
1236.evidencetable {
1237 background-color: floralwhite;
1238 border: 0px solid;
1239 border-radius: 4px;
1240 box-shadow: 2px 2px 2px 2px #d8d8d8;
1241 -webkit-box-shadow: 2px 2px 2px 2px #d8d8d8;
1242 -moz-box-shadow: 2px 2px 2px 2px #d8d8d8;
1243 padding: 4px 4px 4px 4px;
1244}
1245
1246/* set defaults for table data and table headers */
1247table{
1248 border: 0px;
1249 border-collapse: collapse;
1250}
1251
1252td{
1253 padding: 0px 8px 0px 8px;
1254 border: 0px;
1255}
1256
1257th{
1258 padding: 0px 8px 0px 8px;
1259 border: 0px;
1260}
1261
1262.leftborder{
1263 border-left: 1px solid #000;
1264}
1265
1266.rightborder{
1267 border-right: 1px solid #000;
1268}
1269
1270.topborder{
1271 border-top: 1px solid #000;
1272}
1273
1274.bottomborder{
1275 border-bottom: 1px solid #000;
1276}
1277
1278/* set text colour classes for detectors */
1279.H1{
1280 color: red;
1281}
1282
1283.H2{
1284 color: cyan;
1285}
1286
1287.L1{
1288 color: green;
1289}
1290
1291.V1{
1292 color: blue;
1293}
1294
1295.G1{
1296 color: magenta;
1297}
1298
1299.Joint{
1300 color: black;
1301 font-weight: bold;
1302}
1303"""
1304
1305
1306# create css file text for the tables of all results
1307results_table_css = """
1308/* create body style */
1309body {
1310 font-family: Verdana, Geneva, "Trebuchet MS", sans-serif;
1311}
1312
1313/* create footer style */
1314#footer {
1315 border-top: 1px solid #999;
1316 padding: 15px;
1317 font-family: monospace;
1318 text-align: left;
1319}
1320
1321/* create link style */
1322a:link{
1323 color: #000000;
1324 text-decoration: none;
1325}
1326
1327a:visited{
1328 color: #000000;
1329 text-decoration: none;
1330}
1331
1332a:hover{
1333 color: #000000;
1334 text-decoration: none;
1335 text-shadow: 2px 2px 2px #ccc;
1336}
1337
1338/* set defaults for table data and table headers */
1339table{
1340 border: 0px;
1341 border-collapse: collapse;
1342}
1343
1344td{
1345 padding: 0px 8px 0px 8px;
1346 border: 0px;
1347}
1348
1349th{
1350 padding: 0px 8px 0px 8px;
1351 border: 0px;
1352}
1353
1354.leftborder{
1355 border-left: 1px solid #000;
1356}
1357
1358.rightborder{
1359 border-right: 1px solid #000;
1360}
1361
1362.topborder{
1363 border-top: 1px solid #000;
1364}
1365
1366.bottomborder{
1367 border-bottom: 1px solid #000;
1368}
1369
1370/* set text colour classes for detectors */
1371.H1{
1372 color: red;
1373}
1374
1375.H2{
1376 color: cyan;
1377}
1378
1379.L1{
1380 color: green;
1381}
1382
1383.V1{
1384 color: blue;
1385}
1386
1387.G1{
1388 color: magenta;
1389}
1390
1391.Joint{
1392 color: black;
1393 font-weight: bold;
1394}
1395"""
def __init__(self, link, linktext="", linkclass="", linkid="", linkstyle="")
Input the link and the text that the link surrounds.
Class to make and return a html table.
def addrow(self, rowclass="", rowid="", rowstyle="")
Add a new empty row dictionary to the list and increment the current row index.
def __init__(self, tag="table", tableclass="", tableid="", tablestyle="")
def deleterow(self, rowidx)
Delete a row.
def adddata(self, datatext, dataclass="", dataid="", datastyle="", header=False, rowspan=0, colspan=0, rowidx=None)
Add table data (or is header is True) tags to a given row.
A class to create a html tag.
def __init__(self, tag, tagtext="", tagclass="", tagid="", tagstyle="", newline=False)
def __iadd__(self, ttext)
Overload the += operator to append text to tagtext.
Class to make a return a LaTeX table.
def adddata(self, datatxt, multicolumn=0, mcalign="c", rowidx=None)
def addrow(self, underline=False)
def __init__(self, ncolumns=1, columnalign="c", caption="", label="", floatval="h", preamble="", postamble="")
Create a table environment with ncolumns columns positioned with columnpos
def set_columnalign(self, columnalign)
static const INT4 a
float data[BLOCKSIZE]
Definition: hwinject.c:360
def dec_str(dec, otype="html")
def dec_or_exp(f, dp=2, horl="html")
def ra_str(ra, otype="html")
def exp_str(f, p=1, otype="html")
def rad_to_hms(rad)
rad_to_hms(rad): Convert radians to hours, minutes, and seconds of arc.
def rad_to_dms(rad)
rad_to_dms(rad): Convert radians to degrees, minutes, and seconds of arc.