Coverage for /home/andrew/Documents/Research/gwent/gwent/snrplot.py: 85%

# Coverage for /home/andrew/Documents/Research/gwent/gwent/snrplot.py : 85%

## 326 statements 278 run 48 missing 0 excluded

Hot-keys on this page

r m x p toggle line displays

j k next/prev highlighted chunk

0 (zero) top of page

1 (one) first highlighted chunk

1 import numpy as np

2 import matplotlib as mpl

3 import matplotlib.pyplot as plt

4 import matplotlib.colors as colors

5 from scipy.constants import golden_ratio

6

7 import astropy.units as u

8 from astropy.cosmology import z_at_value

9 from astropy.cosmology import WMAP9 as cosmo

10

11

12 def Plot_SNR(

13 var_x,

14 sample_x,

15 var_y,

16 sample_y,

17 SNRMatrix,

18 fig=None,

19 ax=None,

20 display=True,

21 return_plt=False,

22 dl_axis=False,

23 lb_axis=False,

24 smooth_contours=False,

25 cfill=True,

26 display_cbar=True,

27 x_axis_label=True,

28 y_axis_label=True,

29 x_axis_line=None,

30 y_axis_line=None,

31 logLevels_min=-1.0,

32 logLevels_max=0.0,

33 hspace=0.15,

34 wspace=0.1,

35 contour_kwargs={},

36 contourf_kwargs={},

37 xticklabels_kwargs={},

38 xlabels_kwargs={},

39 xline_kwargs={},

40 yticklabels_kwargs={},

41 ylabels_kwargs={},

42 yline_kwargs={},

43):

44 """Plots the SNR contours from calcSNR

45

46 Parameters

47 ----------

48 var_x : str

49 x-axis variable

50 sample_x : array

51 samples at which SNRMatrix was calculated corresponding to the x-axis variable

52 var_y : str

53 y-axis variable

54 sample_y : array

55 samples at which SNRMatrix was calculated corresponding to the y-axis variable

56 SNRMatrix : array-like

57 the matrix at which the SNR was calculated corresponding to the particular x and y-axis variable choices

58

59 fig : object, optional

60 matplotlib figure object on which to collate the individual plots

61 ax : object, optional

62 matplotlib axes object on which to plot the individual plot

63 display : bool, optional

64 Option to turn off display if saving multiple plots to a file

65 return_plt : bool, optional

66 Option to return fig and ax

67 dl_axis : bool, optional

68 Option to turn on the right hand side labels of luminosity distance

69 lb_axis : bool, optional

70 Option to turn on the right hand side labels of lookback time

71 smooth_contours : bool, optional

72 Option to have contours appear smooth instead of tiered (depending on sample size the edges appear boxey).

73 cfill : bool, optional

74 Option to use filled contours or not, default is True

75 display_cbar : bool, optional

76 Option to display the colorbar on the axes object

77 x_axis_label : bool, optional

78 Option to display the x axis label

79 y_axis_label : bool, optional

80 Option to display the y axis label

81 x_axis_line : int,float, optional

82 Option to display a line on the x axis if not None

83 y_axis_line : int,float, optional

84 Option to display a line on the y axis if not None

85 logLevels_min : float, optional

86 Sets the minimum log level of the colorbar, default is -1.0 which set the minimum to the log minimum of the given SNRMatrix

87 logLevels_max : float, optional

88 Sets the maximum log level of the colorbar, default is 0.0, which sets the maximum to the log maximum value of the given SNRMatrix

89 hspace : float, optional

90 Sets the vertical space between axes objects, default is 0.15

91 wspace : float, optional

92 Sets the horizontal space between axes objects, default is 0.1

93 contour_kwargs : dict, optional

94 Sets additional kwargs taken by contour in matplotlib

95 contourf_kwargs : dict, optional

96 Sets additional kwargs taken by contourf in matplotlib

97 xticklabels_kwargs : dict, optional

98 Sets additional kwargs taken by xticklabel in matplotlib

99 xlabels_kwargs= : dict, optional

100 Sets additional kwargs taken by xlabel in matplotlib

101 xline_kwargs : dict, optional

102 Sets additional kwargs taken by ax.axvline in matplotlib

103 yticklabels_kwargs : dict, optional

104 Sets additional kwargs taken by yticklabel in matplotlib

105 ylabels_kwargs : dict, optional

106 Sets additional kwargs taken by ylabel in matplotlib

107 yline_kwargs : dict, optional

108 Sets additional kwargs taken by ax.axhline in matplotlib

109

110 """

111 if fig is not None:

112 if ax is not None:

113 pass

114 else:

115 fig, ax = plt.subplots()

116 else:

117 fig, ax = plt.subplots()

118

119 if "colors" not in contour_kwargs.keys() and "cmap" not in contour_kwargs.keys():

120 contour_kwargs["colors"] = "k"

121 if "linewidths" not in contour_kwargs.keys():

122 contour_kwargs["linewidths"] = 2.0

123

124 if "cmap" not in contourf_kwargs.keys():

125 contourf_kwargs["cmap"] = "viridis"

126

127 logSNR = np.log10(SNRMatrix)

128 if logLevels_min == -1.0:

129 logLevels_min = np.log10(np.array([1.0]))

130 if logLevels_max == 0.0:

131 logLevels_max = np.ceil(np.amax(logSNR))

132 if logLevels_max < logLevels_min:

133 raise ValueError("All SNRs are lower than 5.")

134

135 logLevels_add = np.log10(np.array([3.0, 10.0, 31.0]))

136 print_logLevels = np.concatenate(

137 (logLevels_min, logLevels_add, np.arange(2.0, logLevels_max + 1.0))

138 )

139

140 logLevels = print_logLevels

141

142 ylabel_min = min(sample_y)

143 ylabel_max = max(sample_y)

144 xlabel_min = min(sample_x)

145 xlabel_max = max(sample_x)

146

147 # Set whether log or linearly spaced axes

148 if xlabel_max < 0.0 or xlabel_min < 0.0 or var_x in ["n_p", "T_obs"]:

149 xaxis_type = "lin"

150 step_size = int(xlabel_max - xlabel_min + 1)

151 x_labels = np.linspace(xlabel_min, xlabel_max, step_size)

152 else:

153 x_log_range = np.log10(xlabel_max) - np.log10(xlabel_min)

154 if x_log_range >= 2.0:

155 xaxis_type = "log"

156 step_size = int(np.log10(xlabel_max) - np.log10(xlabel_min) + 1)

157 x_labels = np.logspace(

158 np.log10(xlabel_min), np.log10(xlabel_max), step_size

159 )

160 else:

161 xaxis_type = "lin"

162 x_scale = 10 ** round(np.log10(xlabel_min))

163 x_labels = (

164 np.arange(

165 round(xlabel_min / x_scale), round(xlabel_max / x_scale) + 1, 1

166 )

167 * x_scale

168 )

169 if x_labels[0] < xlabel_min:

170 x_labels[0] = xlabel_min

171 if x_labels[-1] > xlabel_max:

172 x_labels[-1] = xlabel_max

173

174 if ylabel_max < 0.0 or ylabel_min < 0.0 or var_y in ["n_p", "T_obs"]:

175 yaxis_type = "lin"

176 step_size = int(ylabel_max - ylabel_min + 1)

177 y_labels = np.linspace(ylabel_min, ylabel_max, step_size)

178 else:

179 y_log_range = np.log10(ylabel_max) - np.log10(ylabel_min)

180 if y_log_range >= 2.0:

181 yaxis_type = "log"

182 step_size = int(np.log10(ylabel_max) - np.log10(ylabel_min) + 1)

183 y_labels = np.logspace(

184 np.log10(ylabel_min), np.log10(ylabel_max), step_size

185 )

186 else:

187 yaxis_type = "lin"

188 y_scale = 10 ** round(np.log10(ylabel_min))

189 y_labels = (

190 np.arange(

191 round(ylabel_min / y_scale), round(ylabel_max / y_scale) + 1, 1

192 )

193 * y_scale

194 )

195 if y_labels[0] < ylabel_min:

196 y_labels[0] = ylabel_min

197 if y_labels[-1] > ylabel_max:

198 y_labels[-1] = ylabel_max

199

200 # Set axis scales based on what data sampling we used

201 if yaxis_type == "lin" and xaxis_type == "log":

202 if cfill == False:

203 CS1 = ax.contour(

204 np.log10(sample_x), sample_y, logSNR, print_logLevels, **contour_kwargs

205 )

206 else:

207 if smooth_contours:

208 cmap = mpl.cm.get_cmap(name=contourf_kwargs["cmap"])

209 cmap.set_under(color="white")

210 CS1 = ax.imshow(

211 logSNR,

212 extent=[

213 np.log10(xlabel_min),

214 np.log10(xlabel_max),

215 ylabel_min,

216 ylabel_max,

217 ],

218 vmin=logLevels_min,

219 vmax=logLevels_max,

220 origin="lower",

221 aspect="auto",

222 cmap=cmap,

223 )

224 else:

225 CS1 = ax.contourf(

226 np.log10(sample_x), sample_y, logSNR, logLevels, **contourf_kwargs

227 )

228 ax.contour(

229 np.log10(sample_x), sample_y, logSNR, print_logLevels, **contour_kwargs

230 )

231 ax.set_xlim(np.log10(xlabel_min), np.log10(xlabel_max))

232 ax.set_ylim(ylabel_min, ylabel_max)

233

234 elif yaxis_type == "log" and xaxis_type == "lin":

235 if cfill == False:

236 CS1 = ax.contour(

237 sample_x, np.log10(sample_y), logSNR, print_logLevels, **contour_kwargs

238 )

239 else:

240 if smooth_contours:

241 cmap = mpl.cm.get_cmap(name=contourf_kwargs["cmap"])

242 cmap.set_under(color="white")

243 CS1 = ax.imshow(

244 logSNR,

245 extent=[

246 xlabel_min,

247 xlabel_max,

248 np.log10(ylabel_min),

249 np.log10(ylabel_max),

250 ],

251 vmin=logLevels_min,

252 vmax=logLevels_max,

253 origin="lower",

254 aspect="auto",

255 cmap=cmap,

256 )

257 else:

258 CS1 = ax.contourf(

259 sample_x, np.log10(sample_y), logSNR, logLevels, **contourf_kwargs

260 )

261 ax.contour(

262 sample_x, np.log10(sample_y), logSNR, print_logLevels, **contour_kwargs

263 )

264 ax.set_xlim(xlabel_min, xlabel_max)

265 ax.set_ylim(np.log10(ylabel_min), np.log10(ylabel_max))

266 elif yaxis_type == "lin" and xaxis_type == "lin":

267 if cfill == False:

268 CS1 = ax.contour(

269 sample_x, sample_y, logSNR, print_logLevels, **contour_kwargs

270 )

271 else:

272 if smooth_contours:

273 cmap = mpl.cm.get_cmap(name=contourf_kwargs["cmap"])

274 cmap.set_under(color="white")

275 CS1 = ax.imshow(

276 logSNR,

277 extent=[xlabel_min, xlabel_max, ylabel_min, ylabel_max],

278 vmin=logLevels_min,

279 vmax=logLevels_max,

280 origin="lower",

281 aspect="auto",

282 cmap=cmap,

283 )

284 else:

285 CS1 = ax.contourf(

286 sample_x, sample_y, logSNR, logLevels, **contourf_kwargs

287 )

288 ax.contour(sample_x, sample_y, logSNR, print_logLevels, **contour_kwargs)

289 ax.set_xlim(xlabel_min, xlabel_max)

290 ax.set_ylim(ylabel_min, ylabel_max)

291 else:

292 if cfill == False:

293 CS1 = ax.contour(

294 np.log10(sample_x),

295 np.log10(sample_y),

296 logSNR,

297 print_logLevels,

298 **contour_kwargs

299 )

300 else:

301 if smooth_contours:

302 cmap = mpl.cm.get_cmap(name=contourf_kwargs["cmap"])

303 cmap.set_under(color="white")

304 CS1 = ax.imshow(

305 logSNR,

306 extent=[

307 np.log10(xlabel_min),

308 np.log10(xlabel_max),

309 np.log10(ylabel_min),

310 np.log10(ylabel_max),

311 ],

312 vmin=logLevels_min,

313 vmax=logLevels_max,

314 origin="lower",

315 aspect="auto",

316 cmap=cmap,

317 interpolation="None",

318 )

319 else:

320 CS1 = ax.contourf(

321 np.log10(sample_x),

322 np.log10(sample_y),

323 logSNR,

324 logLevels,

325 **contourf_kwargs

326 )

327 ax.contour(

328 np.log10(sample_x),

329 np.log10(sample_y),

330 logSNR,

331 print_logLevels,

332 **contour_kwargs

333 )

334 ax.set_xlim(np.log10(xlabel_min), np.log10(xlabel_max))

335 ax.set_ylim(np.log10(ylabel_min), np.log10(ylabel_max))

336

337 Get_Axes_Labels(

338 ax,

339 "x",

340 var_x,

341 xaxis_type,

342 x_labels,

343 x_axis_line,

344 xlabels_kwargs,

345 xticklabels_kwargs,

346 xline_kwargs,

347 )

348 Get_Axes_Labels(

349 ax,

350 "y",

351 var_y,

352 yaxis_type,

353 y_labels,

354 y_axis_line,

355 ylabels_kwargs,

356 yticklabels_kwargs,

357 yline_kwargs,

358 )

359

360 if not x_axis_label:

361 ax.set_xticklabels("")

362 ax.set_xlabel("")

363 if not y_axis_label:

364 ax.set_yticklabels("")

365 ax.set_ylabel("")

366

367 # If true, display luminosity distance on right side of plot

368 if dl_axis:

369 if var_y != "z":

370 raise ValueError(

371 "Sorry, we can only plot luminosity distance when redshift is on the y axis."

372 )

373

374 # Set other side y-axis for luminosity distance scalings

375 ax2 = ax.twinx()

376 # Set axis scales based on what data sampling we used

377 if yaxis_type == "lin" and xaxis_type == "log":

378 ax2.contour(

379 np.log10(sample_x), sample_y, logSNR, print_logLevels, **contour_kwargs

380 )

381 elif yaxis_type == "log" and xaxis_type == "lin":

382 ax2.contour(

383 sample_x, np.log10(sample_y), logSNR, print_logLevels, **contour_kwargs

384 )

385 else:

386 ax2.contour(

387 np.log10(sample_x),

388 np.log10(sample_y),

389 logSNR,

390 print_logLevels,

391 **contour_kwargs

392 )

393

394 dists_min = cosmo.luminosity_distance(ylabel_min).to("Gpc")

395 dists_min = np.ceil(np.log10(dists_min.value))

396 dists_max = cosmo.luminosity_distance(ylabel_max).to("Gpc")

397 dists_max = np.ceil(np.log10(dists_max.value))

398 dists = np.arange(dists_min, dists_max)

399 dists = 10 ** dists * u.Gpc

400

401 distticks = [z_at_value(cosmo.luminosity_distance, dist) for dist in dists]

402 # Set other side y-axis for lookback time scalings

403 ax2.set_yticks(np.log10(distticks))

404 # ax2.set_yticklabels(['%f' %dist for dist in distticks],fontsize = axissize)

405 ax2.set_yticklabels(

406 [

407 r"$10^{%i}$" % np.log10(dist)

408 if np.abs(int(np.log10(dist))) > 1

409 else "{:g}".format(dist)

410 for dist in dists.value

411 ]

412 )

413 ax2.set_ylabel(r"$D_{L}$ [Gpc]")

414

415 # cbar = fig.colorbar(CS1,cax=cbar_ax,ax=(ax,ax2),pad=0.01,ticks=print_logLevels)

416 elif lb_axis:

417 if var_y != "z":

418 raise ValueError(

419 "Sorry, we can only plot lookback time when redshift is on the y axis."

420 )

421 # Set other side y-axis for lookback time scalings

422 ax2 = ax.twinx()

423 # Set axis scales based on what data sampling we used

424 if yaxis_type == "lin" and xaxis_type == "log":

425 ax2.contour(

426 np.log10(sample_x), sample_y, logSNR, print_logLevels, **contour_kwargs

427 )

428 elif yaxis_type == "log" and xaxis_type == "lin":

429 ax2.contour(

430 sample_x, np.log10(sample_y), logSNR, print_logLevels, **contour_kwargs

431 )

432 else:

433 ax2.contour(

434 np.log10(sample_x),

435 np.log10(sample_y),

436 logSNR,

437 print_logLevels,

438 **contour_kwargs

439 )

440

441 ages1 = np.array([13.5, 13, 10, 5, 1]) * u.Gyr

442 ages2 = np.array([500, 100, 10, 1]) * u.Myr

443 ages2 = ages2.to("Gyr")

444 ages = np.hstack((ages1.value, ages2.value))

445 ages = ages * u.Gyr

446 ageticks = [z_at_value(cosmo.age, age) for age in ages]

447

448 # Set axes limits

449 ax2.set_yticks(np.log10(ageticks))

450 ax2.set_yticklabels(["{:g}".format(age) for age in ages.value])

451 ax2.set_ylabel(r"$t_{\rm cosmic}$ [Gyr]")

452 ax2.yaxis.set_label_coords(1.2, 0.5)

453

454 if display_cbar:

455 if lb_axis or dl_axis:

456 fig.subplots_adjust(right=0.8)

457 cbar_ax = fig.add_axes([0.9, 0.15, 0.025, 0.7])

458 # Make colorbar

459 if cfill == False:

460 # Make colorbar

461 norm = colors.Normalize(vmin=logLevels_min, vmax=logLevels_max)

462 tick_levels = np.linspace(

463 float(logLevels_min), logLevels_max, len(print_logLevels)

464 )

465 cbar = mpl.colorbar.ColorbarBase(

466 cbar_ax,

467 ax=(ax, ax2),

468 pad=0.01,

469 cmap=CS1.cmap,

470 norm=norm,

471 boundaries=tick_levels,

472 ticks=tick_levels,

473 spacing="proportional",

474 )

475 else:

476 cbar = fig.colorbar(CS1, cax=cbar_ax, ax=(ax, ax2), pad=0.01)

477 else:

478 fig.subplots_adjust(right=0.8)

479 cbar_ax = fig.add_axes([0.82, 0.15, 0.025, 0.7])

480 if cfill == False:

481 # Make colorbar

482 norm = colors.Normalize(vmin=logLevels_min, vmax=logLevels_max)

483 tick_levels = np.linspace(

484 float(logLevels_min), logLevels_max, len(print_logLevels)

485 )

486 cbar = mpl.colorbar.ColorbarBase(

487 cbar_ax,

488 cmap=CS1.cmap,

489 norm=norm,

490 boundaries=tick_levels,

491 ticks=tick_levels,

492 spacing="proportional",

493 )

494 else:

495 # Make colorbar

496 cbar = fig.colorbar(CS1, cax=cbar_ax, ticks=print_logLevels)

497

498 cbar.set_label(r"SNR")

499 cbar.ax.set_yticklabels(

500 [

501 r"$10^{%i}$" % x if int(x) > 1 else r"$%i$" % (10 ** x)

502 for x in print_logLevels

503 ],

504 **yticklabels_kwargs

505 )

506

507 if display:

508 # fig.tight_layout()

509 fig.subplots_adjust(hspace=hspace, wspace=wspace)

510 plt.show()

511

512 if return_plt:

513 return fig, ax

514

515

516 def Get_Axes_Labels(

517 ax,

518 var_axis,

519 var,

520 var_scale,

521 orig_labels,

522 line_val,

523 label_kwargs,

524 tick_label_kwargs,

525 line_kwargs,

526):

527 """Gives paper plot labels for given axis

528

529 Parameters

530 ----------

531 ax: object

532 The current axes object

533 var_axis: str

534 The axis to change labels and ticks, can either be 'y' or 'x'

535 var: str

536 The variable to label

537 orig_labels: list,np.ndarray

538 The original labels for the particular axis, may be updated depending on parameter

539 line_val: int,float

540 Value of line plotted on var_axis if not None. Assumed to be non-log10 value

541 label_kwargs: dict

542 The dictionary adjusting the particular axis' label kwargs

543 tick_label_kwargs: dict

544 The dictionary adjusting the particular axis' tick label kwargs

545 line_kwargs: dict

546 The dictionary associated with the line displayed on var_axis

547

548 """

549

550 # Set axes labels and whether log or linearly spaced

551 if var_axis not in ["y", "x"]:

552 raise ValueError("var_axis can only by x or y")

553

554 ax_dict = {}

555

556 if var == "M":

557 ax_dict[var_axis + "ticks"] = np.log10(orig_labels)

558 ax_dict[var_axis + "label"] = r"$M_{\mathrm{tot}}~[M_{\odot}]$"

559 ax_dict[var_axis + "ticklabels"] = [

560 r"$10^{%i}$" % x if int(x) > 1 else r"$%i$" % (10 ** x)

561 for x in np.log10(orig_labels)

562 ]

563 elif var == "q":

564 new_labels = orig_labels[::2]

565 ax_dict[var_axis + "ticks"] = new_labels

566 ax_dict[var_axis + "label"] = r"$\mathrm{Mass~Ratio}~q$"

567 ax_dict[var_axis + "ticklabels"] = [r"$%i$" % int(x) for x in new_labels]

568 elif var == "z":

569 ax_dict[var_axis + "ticks"] = np.log10(orig_labels)

570 ax_dict[var_axis + "label"] = r"$\mathrm{Redshift}~z$"

571 ax_dict[var_axis + "ticklabels"] = [

572 x if int(x) < 1 else int(x) for x in orig_labels

573 ]

574 elif var in ["chi1", "chi2"]:

575 new_labels = (

576 np.arange(round(min(orig_labels) * 10), round(max(orig_labels) * 10) + 1, 1)

577 / 10

578 )

579 new_labels = new_labels[::2]

580 ax_dict[var_axis + "ticks"] = new_labels

581 ax_dict[var_axis + "label"] = r"$\mathrm{Spin}~\chi_{i}$"

582 ax_dict[var_axis + "ticklabels"] = [r"$%.1f$" % x for x in new_labels]

583 elif var == "L":

584 # Proposed Value = 2.5Gm: L3 LISA

585 ax_dict[var_axis + "ticks"] = np.log10(orig_labels)

586 ax_dict[var_axis + "label"] = r"Arm Length [m]"

587 ax_dict[var_axis + "ticklabels"] = [

588 r"$10^{%i}$" % x if int(x) > 1 else r"$%i$" % (10 ** x)

589 for x in np.log10(orig_labels)

590 ]

591 elif var == "A_acc":

592 # Proposed Value = 3x10^{-15}: L3 LISA

593 ax_dict[var_axis + "ticks"] = np.log10(orig_labels)

594 ax_dict[var_axis + "label"] = r"$A_{\mathrm{acc}} [\mathrm{m~s^{-2}}]$"

595 ax_dict[var_axis + "ticklabels"] = [

596 r"$10^{%.0f}$" % x for x in np.log10(orig_labels)

597 ]

598 elif var == "A_IFO":

599 # Proposed Value = 10^{-12}: L3 LISA

600 ax_dict[var_axis + "ticks"] = np.log10(orig_labels)

601 ax_dict[var_axis + "label"] = r"$A_{\mathrm{IFO}}$ [m]"

602 ax_dict[var_axis + "ticklabels"] = [

603 r"$10^{%.0f}$" % x for x in np.log10(orig_labels)

604 ]

605 elif var == "f_acc_break_low":

606 # Proposed Value = 0.4mHz: L3 LISA

607 scale = 10 ** round(np.log10(min(orig_labels)))

608 new_labels = (

609 np.arange(

610 round(min(orig_labels) / scale), round(max(orig_labels) / scale) + 1, 1

611 )

612 * scale

613 )

614 ax_dict[var_axis + "ticks"] = new_labels

615 ax_dict[var_axis + "label"] = r"$f_{\mathrm{acc,low}}$ [mHz]"

616 ax_dict[var_axis + "ticklabels"] = [r"$%.1f$" % x for x in new_labels * 1e3]

617 elif var == "f_acc_break_high":

618 # Proposed Value = 8mHz: L3 LISA

619 scale = 10 ** round(np.log10(min(orig_labels)))

620 new_labels = (

621 np.arange(

622 round(min(orig_labels) / scale), round(max(orig_labels) / scale) + 1, 1

623 )

624 * scale

625 )

626 ax_dict[var_axis + "ticks"] = new_labels

627 ax_dict[var_axis + "label"] = r"$f_{\mathrm{acc,high}}$ [mHz]"

628 ax_dict[var_axis + "ticklabels"] = [r"$%.1f$" % x for x in new_labels * 1e3]

629 elif var == "f_IFO_break":

630 # Proposed Value = 2mHz: L3 LISA

631 scale = 10 ** round(np.log10(min(orig_labels)))

632 new_labels = (

633 np.arange(

634 round(min(orig_labels) / scale), round(max(orig_labels) / scale) + 1, 1

635 )

636 * scale

637 )

638 ax_dict[var_axis + "ticks"] = new_labels

639 ax_dict[var_axis + "label"] = r"$f_{\mathrm{IFO,break}}$ [mHz]"

640 ax_dict[var_axis + "ticklabels"] = [r"$%.1f$" % x for x in new_labels * 1e3]

641 elif var == "n_p":

642 sample_range = max(orig_labels) - min(orig_labels)

643 sample_rate = max(2, int(sample_range / 10))

644 new_labels = orig_labels[::sample_rate]

645 ax_dict[var_axis + "ticks"] = new_labels

646 ax_dict[var_axis + "label"] = r"$\mathrm{Number~of~Pulsars}$"

647 ax_dict[var_axis + "ticklabels"] = [r"$%i$" % int(x) for x in new_labels]

648 elif var == "cadence":

649 new_labels = np.arange(round(min(orig_labels)), round(max(orig_labels)) + 1, 5)

650 ax_dict[var_axis + "ticks"] = new_labels

651 ax_dict[

652 var_axis + "label"

653 ] = r"$\mathrm{Observation~Cadence}$ $[\mathrm{yr}^{-1}]$"

654 ax_dict[var_axis + "ticklabels"] = [r"$%i$" % int(x) for x in new_labels]

655 elif var == "sigma":

656 scale = 10 ** round(np.log10(min(orig_labels)))

657 new_labels = (

658 np.arange(

659 round(min(orig_labels) / scale), round(max(orig_labels) / scale) + 1, 1

660 )

661 * scale

662 )

663 ax_dict[var_axis + "ticks"] = new_labels

664 ax_dict[var_axis + "label"] = r"TOA Error RMS [ns]"

665 ax_dict[var_axis + "ticklabels"] = [r"$%.0f$" % x for x in new_labels * 1e9]

666 elif var == "T_obs":

667 new_labels = orig_labels[::2]

668 ax_dict[var_axis + "ticks"] = new_labels

669 ax_dict[var_axis + "label"] = r"${\rm T_{obs}}$ [yr]"

670 ax_dict[var_axis + "ticklabels"] = [r"$%i$" % int(x) for x in new_labels]

671 elif var == "Infrastructure Length":

672 # Proposed Value = 3995: aLIGO, Voyager

673 # Proposed Value = 40000: CE1

674 if var_scale == "log":

675 ax_dict[var_axis + "ticks"] = np.log10(orig_labels)

676 ax_dict[var_axis + "label"] = r"Infrastructure Length [m]"

677 ax_dict[var_axis + "ticklabels"] = [

678 r"$10^{%.0f}$" % y if abs(int(y)) > 1 else r"$%.1f$" % (10 ** y)

679 for y in np.log10(orig_labels)

680 ]

681 elif var_scale == "lin":

682 ax_dict[var_axis + "ticks"] = orig_labels

683 ax_dict[var_axis + "label"] = r"Infrastructure Length [km]"

684 ax_dict[var_axis + "ticklabels"] = [

685 r"$%.1f$" % (x / 1e3) for x in orig_labels

686 ]

687 elif var == "Laser Power":

688 # Proposed Value = 125: aLIGO

689 # Proposed Value = 145: Voyager

690 # Proposed Value = 150: CE1

691 if var_scale == "log":

692 ax_dict[var_axis + "ticks"] = np.log10(orig_labels)

693 ax_dict[var_axis + "label"] = r"Laser Power [W]"

694 ax_dict[var_axis + "ticklabels"] = [

695 r"$10^{%.0f}$" % x if abs(int(x)) > 1 else r"$%.1f$" % (10 ** x)

696 for x in np.log10(orig_labels)

697 ]

698 elif var_scale == "lin":

699 ax_dict[var_axis + "ticks"] = orig_labels

700 ax_dict[var_axis + "label"] = r"Laser Power [W]"

701 ax_dict[var_axis + "ticklabels"] = [r"$%.1f$" % x for x in orig_labels]

702 elif var == "Seismic Gamma":

703 # Proposed Value = 0.8: aLIGO, Voyager, CE1

704 if var_scale == "log":

705 ax_dict[var_axis + "ticks"] = np.log10(orig_labels)

706 ax_dict[var_axis + "label"] = r"Seismic Gamma"

707 ax_dict[var_axis + "ticklabels"] = [

708 r"$10^{%.0f}$" % y if abs(int(y)) > 1 else r"$%.1f$" % (10 ** y)

709 for y in np.log10(orig_labels)

710 ]

711 elif var_scale == "lin":

712 ax_dict[var_axis + "ticks"] = orig_labels

713 ax_dict[var_axis + "label"] = r"Seismic Gamma"

714 ax_dict[var_axis + "ticklabels"] = [r"$%.1f$" % y for y in orig_labels]

715 elif var == "Materials Substrate Temp":

716 # Proposed Value = 295: aLIGO, CE1

717 # Proposed Value = 123: Voyager

718 if var_scale == "lin":

719 ax_dict[var_axis + "ticks"] = orig_labels

720 ax_dict[var_axis + "label"] = r"Mirror Substrate Temp [K]"

721 ax_dict[var_axis + "ticklabels"] = [

722 r"$%.1f \times 10^{%i}$" % (x / 10 ** int(np.log10(x)), np.log10(x))

723 if np.abs(int(np.log10(x))) > 1

724 else "{:g}".format(x)

725 for x in orig_labels

726 ]

727 elif var_scale == "log":

728 ax_dict[var_axis + "ticks"] = np.log10(orig_labels)

729 ax_dict[var_axis + "label"] = r"Mirror Substrate Temp [K]"

730 ax_dict[var_axis + "ticklabels"] = [

731 r"$10^{%.0f}$" % y if abs(int(y)) > 1 else r"$%.1f$" % (10 ** y)

732 for y in np.log10(orig_labels)

733 ]

734 else:

735 if var_scale == "lin":

736 ax_dict[var_axis + "ticks"] = orig_labels

737 ax_dict[var_axis + "label"] = str(var)

738 ax_dict[var_axis + "ticklabels"] = [

739 r"$%.1f \times 10^{%i}$" % (x / 10 ** int(np.log10(x)), np.log10(x))

740 if np.abs(int(np.log10(x))) > 1

741 else "{:g}".format(x)

742 for x in orig_labels

743 ]

744 elif var_scale == "log":

745 ax_dict[var_axis + "ticks"] = np.log10(orig_labels)

746 ax_dict[var_axis + "label"] = str(var)

747 ax_dict[var_axis + "ticklabels"] = [

748 r"$10^{%.0f}$" % y if abs(int(y)) > 1 else r"$%.1f$" % (10 ** y)

749 for y in np.log10(orig_labels)

750 ]

751 if line_val is not None:

752 if "linestyle" not in line_kwargs.keys():

753 line_kwargs["linestyle"] = "--"

754 if "color" not in line_kwargs.keys():

755 line_kwargs["color"] = "k"

756 if "label" not in line_kwargs.keys():

757 line_kwargs["label"] = "Proposed Value"

758

759 if var_scale == "log":

760 if var_axis == "y":

761 ax.axhline(y=np.log10(line_val), **line_kwargs)

762 elif var_axis == "x":

763 ax.axvline(x=np.log10(line_val), **line_kwargs)

764 elif var_scale == "lin":

765 if var_axis == "y":

766 ax.axhline(y=line_val, **line_kwargs)

767 elif var_axis == "x":

768 ax.axvline(x=line_val, **line_kwargs)

769

770 ax.update(ax_dict)

771 if label_kwargs:

772 if var_axis == "y":

773 ax.set_ylabel(ax.get_ylabel(), **label_kwargs)

774 elif var_axis == "x":

775 ax.set_xlabel(ax.get_xlabel(), **label_kwargs)

776

777 if tick_label_kwargs:

778 if var_axis == "y":

779 ax.set_yticklabels(ax.get_yticklabels(), **tick_label_kwargs)

780 elif var_axis == "x":

781 ax.set_xticklabels(ax.get_xticklabels(), **tick_label_kwargs)