-
Notifications
You must be signed in to change notification settings - Fork 20
/
_spectrum.py
843 lines (680 loc) · 31.7 KB
/
_spectrum.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
from __future__ import division
from ._global_imports import *
try:
import fgivenx
except ImportError:
_warning('Cannot import fgivenx for conditional posterior contours.')
fgivenx = None
from ..tools.phase_integrator import phase_integrator
from ..tools.energy_interpolator import energy_interpolator
from ..tools.phase_interpolator import phase_interpolator as interp
from ._signalplot import SignalPlot
class SpectrumPlot(SignalPlot):
""" Plot posterior-averaged channel count-rate spectra.
The figure contains three panels which share phase as an x-axis:
* the top panel displays the specific photon flux signal
from the source, resolved as a function of energy, optionally showing
both unattenuated and attenuated incident spectra and optionally
using :mod:`fgivenx`;
* the center panel displays the posterior expectation of the count-rate
signal as a function of channel and phase, optionally including an
expected background signal;
* the bottom panel displays the phase-integrated (averaged) count-rate
spectum as a function of channel number, optionally including an
expected background signal and optionally using :mod:`fgivenx`.
The top and bottom panels aim to render the conditional posterior
distribution of the associated signal as a function an energy (proxy)
variable, ideally with contours to map out the conditional posterior mass.
These panels have space to optionally display other elements such as:
the posterior-expected total signal; the posterior-expected component
signals; the true total and component signals if the ground truth (the
injected signal correpsonding to some model parameter vector) is known;
attenuated incident spectra; and the summation of posterior-expected
total (component-summed) source count-rate signals with posterior-expected
background count-rate signals.
The following example is (improved) from :ref:`R19`:
.. image:: _static/_spectrumplot.png
:param float rel_num_energies:
The number of energies desired for interpolation as a fraction of the
number of energies implemented for the original incident signal
integration. The energy set will be appropriately spaced and bounded.
:param int num_phases:
The number of phases to interpolate the pulse-profile signals at for
the center panel.
:param str registered_cmap:
Colormap name from :mod:`matplotlib` to use for the posterior-expected
registered signal as a function of channel and phase (center panel).
:param bool show_components:
If the :class:`~.Signal.Signal` instance has multiple components (hot
region signals), display the posterior expectations of those components
as a function of energy (top panel) and channel (bottom panel).
:param bool show_attenuated:
If the source signal is attenuated by the interstellar absorption
processes, display the posterior-expected attenuated incident specific
photon flux spectra? This switch also instructs :mod:`fgivenx`, if
enabled, to generate conditional posterior contours for the attenuated
spectrum instead of the unattenuated spectrum (top panel). If
:mod:`fgivenx` is not invoked, this switch instructs the plotting
of sample-by-sample attenuated total (component-summed) spectra to
delineate the distribution of conditional posterior mass (top panel).
:param dict expectation_line_kwargs:
Keyword arguments for plotting the posterior-expected signal lines (in
the top and bottom panels).
:param bool add_background:
Add an posterior-expected background count-rate signal to the total
(component-summed) expected source count-rate signals in the center
and bottom panels?
:param dict background_line_kwargs:
Keyword arguments for plotting the posterior-expected spectrum in the
bottom panel that includes the background signal.
:param bool use_fgivenx:
Use :mod:`fgivenx` to plot conditional posterior contours in the
top and bottom panels?
:param dict incident_contour_kwargs:
Keyword arguments for :mod:`fgivenx` incident signal contours (top
panel) that will take precedence over the corresponding class
attributes. (See the :class:`~.SignalPlot` class if you choose
not to modify these attributes on this present subclass.)
:param dict registered_contour_kwargs:
Keyword arguments for :mod:`fgivenx` registered signal contours (bottom
panel) that will take precedence over the corresponding class
attributes. (See the :class:`~.SignalPlot` class if you choose
not to modify these attributes on this present subclass.)
:param plot_truth:
Plot the ground truth (injected) signal, if known and available, in
the top and bottom panels.
:param truth_line_kwargs:
Keyword arguments for plotting the ground truth signal lines (top and
bottom panels).
:param comp_truth_line_kwargs:
Keyword arguments for plotting the component ground truth signal lines
(top and bottom panels).
"""
__figtype__ = 'signalplot_spectrum'
# do not change at runtime (see base class comments):
__caching_targets__ = ['shifts',
'signals', # count-rate signals
# incident specific flux signals
'incident_specific_flux_signals']
__rows__ = 3
__columns__ = 1
__ax_rows__ = 2
__ax_columns__ = 1
__height_ratios__ = [1,2]
__width_ratios__ = [1]
__wspace__ = 0.025
__hspace__ = 0.175
@make_verbose('Instantiating a spectrum plotter for posterior checking',
'Spectrum plotter instantiated')
def __init__(self,
rel_num_energies=10.0,
num_phases=1000,
registered_cmap='inferno',
show_components=False,
show_attenuated=True,
expectation_line_kwargs=None,
comp_expectation_line_kwargs=None,
add_background=False,
background_line_kwargs=None,
sample_line_kwargs=None,
use_fgivenx=False,
incident_contour_kwargs=None,
registered_contour_kwargs=None,
plot_truth=False,
truth_line_kwargs=None,
comp_truth_line_kwargs=None,
**kwargs):
try:
_shadow = not self._logspace_y
except AttributeError:
_shadow = True
if _shadow: # shadow class attribute
kwargs.setdefault('logspace_y', True)
if not kwargs.get('logspace_y'):
yield ('Spectrum plots may have conditional-probability '
'contour artefacts if logspace_y is not True.')
super(SpectrumPlot, self).__init__(**kwargs)
self._rel_num_energies = rel_num_energies
self._phases = _np.linspace(0.0, 2.0, int(num_phases))
self._show_attenuated = show_attenuated
self._add_background = add_background
if add_background: # count-rate spectrum
self.__caching_targets__.append('background_signal')
if use_fgivenx and fgivenx is None:
raise ImportError('Install fgivenx to plot contours.')
self._use_fgivenx = use_fgivenx
if self._use_fgivenx:
self._incident_contour_kwargs =\
incident_contour_kwargs if incident_contour_kwargs else {}
self._registered_contour_kwargs =\
registered_contour_kwargs if registered_contour_kwargs else {}
self._get_figure()
fig = self._fig
gs = self._gs
cls = type(self)
# for the incident specific flux signal incident on an instrument
gs_top = gridspec.GridSpecFromSubplotSpec(1, 2,
subplot_spec=gs[0,0],
wspace=cls.__wspace__,
width_ratios=[50,1])
self._ax_incident = fig.add_subplot(gs_top[0,0])
# for the count-rate signal registered by an an instrument
gs_bottom = gridspec.GridSpecFromSubplotSpec(2, 2,
subplot_spec=gs[1,0],
wspace=cls.__wspace__,
hspace=0.125*self._fscale,
height_ratios=[1,1],
width_ratios=[50,1])
self._ax_registered = fig.add_subplot(gs_bottom[0,0])
self._ax_registered_1d = fig.add_subplot(gs_bottom[1,0])
self._axes = [self._ax_incident,
self._ax_registered,
self._ax_registered_1d]
# incident axis properties
self._ax_incident.set_xlabel(r'$E$ [keV]')
self._ax_incident.set_xscale('log')
self._ax_incident.set_ylabel(r'photons/keV/cm$^{2}$/s')
self._ax_incident.set_yscale('log')
# registered axis properties
for ax in self._axes[1:]:
ax.set_xscale('log')
self._ax_registered.tick_params(axis='x', which='both',
labelbottom=False)
self._ax_registered_1d.set_xlabel('channel')
self._ax_registered.set_ylabel(r'$\phi$ [cycles]')
self._ax_registered.yaxis.set_major_locator(MultipleLocator(0.5))
self._ax_registered.yaxis.set_minor_locator(MultipleLocator(0.1))
self._ax_registered.set_ylim([0.0,2.0])
self._ax_registered_1d.set_ylabel('counts/s')
self._ax_registered_1d.set_yscale('log')
# colorbars
if use_fgivenx:
self._ax_incident_cb = fig.add_subplot(gs_top[0,1])
self._axes.append(self._ax_incident_cb)
self._ax_registered_1d_cb = fig.add_subplot(gs_bottom[1,1])
self._axes.append(self._ax_registered_1d_cb)
self._ax_registered_cb = fig.add_subplot(gs_bottom[0,1])
self._axes.append(self._ax_registered_cb)
self._show_components = show_components
self._registered_cmap = registered_cmap
if sample_line_kwargs is not None:
self._sample_line_kwargs = sample_line_kwargs
else:
self._sample_line_kwargs = {}
self._plot_truth = plot_truth
if self._plot_truth:
if truth_line_kwargs is None:
self._truth_line_kwargs = \
dict(color=('b' if self._use_fgivenx else 'darkgreen'),
ls='-.',
lw=1.0,
alpha=1.0)
else:
self._truth_line_kwargs = truth_line_kwargs
if comp_truth_line_kwargs is not None:
self._comp_truth_line_kwargs = comp_truth_line_kwargs
else:
self._comp_truth_line_kwargs = self._truth_line_kwargs
if expectation_line_kwargs is None:
color = 'k' if self._use_fgivenx else 'r'
self._expectation_line_kwargs = dict(color=color,
ls='-',
lw=1.0,
alpha=1.0)
else:
self._expectation_line_kwargs = expectation_line_kwargs
if comp_expectation_line_kwargs is not None:
self._comp_expectation_line_kwargs = comp_expectation_line_kwargs
else:
self._comp_expectation_line_kwargs = self._expectation_line_kwargs
if background_line_kwargs is None:
self._background_line_kwargs = dict(color='orange',
ls='-',
lw=1.0,
alpha=1.0)
else:
self._background_line_kwargs = background_line_kwargs
plt.close()
yield
@property
def instruction_set(self):
return self._instruction_set
@instruction_set.deleter
def instruction_set(self):
try:
del self._instruction_set
except AttributeError:
pass
@make_verbose('SpectrumPlot object iterating over samples',
'SpectrumPlot object finished iterating')
def execute(self, thetas, wrapper):
self._num_samples = thetas.shape[0]
self._energies = self._signal.create_energy_array(self._rel_num_energies)
if self._use_fgivenx:
# determine which spectrum to compute contours for
if self._show_attenuated:
wrapped = wrapper(self, 'incident_sums')
self._instruction_set = 1
# calculate expected unattenuated incident
for i in range(self._num_samples):
_ = wrapped(None, thetas[i,:])
# rewrap to reset the cache iterator
wrapped = wrapper(self, 'attenuated_incident_sums')
self._instruction_set = 0
else:
wrapped = wrapper(self, 'incident_sums')
self._instruction_set = 1
self._add_incident_contours(wrapped, thetas)
self._instruction_set = 2
self._add_registered_contours(wrapper(self, 'registered_sums'),
thetas)
yield 'Added conditional posterior contours for incident spectrum.'
if self._add_background:
self._instruction_set = 3
wrapped = wrapper(self, 'background_sum')
for i in range(self._num_samples):
wrapped(None, thetas[i,:])
else:
del self.instruction_set
wrapped = wrapper(self, ['attenuated_incident_sums',
'incident_sums',
'registered_sums'])
for i in range(self._num_samples):
wrapped(None, thetas[i,:])
yield
def next(self):
""" Update posterior expected signals given the updated signal.
Plots signals if :mod:`fgivenx` is not used, otherwise returns
callback information for :mod:`fgivenx`.
.. note::
You cannot make an iterator from an instance of this class.
"""
try:
self._instruction_set
except AttributeError:
if self._show_attenuated:
signal = self._handle_attenuated_incident()
self._add_signal(self._ax_incident,
self._energies,
signal,
**self._sample_line_kwargs)
signal = self._handle_incident()
if not self._show_attenuated:
self._add_signal(self._ax_incident,
self._energies,
signal,
**self._sample_line_kwargs)
signal = self._handle_registered()
self._add_registered_spectrum(self._ax_registered_1d,
signal,
**self._sample_line_kwargs)
if self._add_background:
self._handle_background() # nothing to plot here
else:
if self._instruction_set == 0:
return self._handle_attenuated_incident() # end execution here
if self._instruction_set == 1:
return self._handle_incident()
if self._instruction_set == 2:
return self._handle_registered()
if self._instruction_set == 3:
self._handle_background() # nothing to return
return None # reached if not invoking fgivenx
def _handle_attenuated_incident(self):
""" Instructions for handling the attenuated incident spectrum. """
ref = self._signal
try:
self._attenuated_incident_sums
except AttributeError:
self._attenuated_incident_sums = [None]*len(ref.incident_specific_flux_signals)
attenuated_incident = None
for i, component in enumerate(ref.incident_specific_flux_signals):
temp = phase_integrator(1.0,
_np.array([0.0,1.0]),
component,
ref.phases[i],
0.0)
temp = energy_interpolator(1, # threads
temp,
_np.log10(ref.energies),
_np.log10(self._energies)).reshape(-1)
# requires a user implementation or will raise NotImplementedError
ref.interstellar(self._energies, temp)
try:
attenuated_incident += temp
except TypeError:
attenuated_incident = temp
try:
self._attenuated_incident_sums[i] += temp
except TypeError:
self._attenuated_incident_sums[i] = temp.copy()
return attenuated_incident
@property
def attenuated_incident_sums(self):
return self._attenuated_incident_sums
@attenuated_incident_sums.deleter
def attenuated_incident_sums(self):
try:
del self._attenuated_incident_sums
except AttributeError:
pass
@property
def expected_attenuated_incident(self):
""" Get the expectations of the incident (component) spectra. """
return [component/self._num_samples for component \
in self._attenuated_incident_sums]
def _handle_incident(self):
""" Instructions for handling the unattenuated incident spectrum. """
ref = self._signal
try:
self._incident_sums
except AttributeError:
self._incident_sums = [None] * len(ref.incident_specific_flux_signals)
incident = None
for i, component in enumerate(ref.incident_specific_flux_signals):
temp = phase_integrator(1.0,
_np.array([0.0,1.0]),
component,
ref.phases[i],
0.0)
temp = energy_interpolator(1, # threads
temp,
_np.log10(ref.energies),
_np.log10(self._energies)).reshape(-1)
try:
incident += temp
except TypeError:
incident = temp
try:
self._incident_sums[i] += temp
except TypeError:
self._incident_sums[i] = temp.copy()
return incident
@property
def incident_sums(self):
return self._incident_sums
@incident_sums.deleter
def incident_sums(self):
try:
del self._incident_sums
except AttributeError:
pass
@property
def expected_incident(self):
""" Get the expectations of the incident (component) spectra. """
return [component/self._num_samples for component in self._incident_sums]
def _handle_registered(self):
""" Instructions for handling the registered spectrum. """
ref = self._signal
try:
self._registered_sums
except AttributeError:
self._registered_sums = [None] * len(ref.signals)
registered = None
for i, component in enumerate(ref.signals):
temp = phase_integrator(1.0,
_np.array([0.0,1.0]),
component,
ref.phases[i],
0.0).reshape(-1)
try:
registered += temp
except TypeError:
registered = temp
try:
self._registered_sums[i] += component
except TypeError:
self._registered_sums[i] = component
return registered
@property
def registered_sums(self):
return self._registered_sums
@registered_sums.deleter
def registered_sums(self):
try:
del self._registered_sums
except AttributeError:
pass
@property
def expected_registered(self):
""" Get the expectations of the registered count-rate spectra. """
return [component/self._num_samples for component in self._registered_sums]
def _handle_background(self):
""" Instructions for handling the background spectrum. """
ref = self._signal
try:
self._background_sum
except AttributeError:
self._background_sum = None
background = ref.background_signal
try:
self._background_sum += background
except TypeError:
self._background_sum = background
return None
@property
def background_sum(self):
return self._background_sum
@background_sum.deleter
def background_sum(self):
try:
del self._background_sum
except AttributeError:
pass
@property
def expected_background(self):
""" Get the expectation of the background count-rate spectrum. """
mean = self._background_sum/self._num_samples
# transform to count rate signal, assuming background signal
# is in units of counts; subclass and overwrite if you want to change
return mean/self._signal.data.exposure_time
@make_verbose('SpectrumPlot object finalizing',
'SpectrumPlot object finalized')
def finalize(self):
""" Execute final instructions. """
ref = self._signal
self._plot_components = self._show_components and ref.num_components > 1
# add the incident signals
if self._plot_truth:
self._add_true_incident_signals()
self._add_expected_incident_signals()
# add the registered signals
if self._plot_truth:
self._add_true_registered_signals()
self._add_expected_registered_signals()
def _add_true_incident_signals(self):
""" Render ground truth incident (component) signals. """
ref = self._signal
total = None
for component, phases in zip(ref.incident_specific_flux_signals,
ref.phases):
temp = phase_integrator(1.0,
_np.array([0.0,1.0]),
component,
phases,
0.0)
temp = energy_interpolator(1, # threads
temp,
_np.log10(ref.energies),
_np.log10(self._energies)).reshape(-1)
if self._show_attenuated:
ref.interstellar(self.energies, temp)
try:
total += temp
except TypeError:
total = temp
if self._plot_components:
self._add_signal(self._ax_incident,
self._energies,
temp,
**self._comp_truth_line_kwargs)
self._add_signal(self._ax_incident,
self._energies,
total,
**self._truth_line_kwargs)
def _add_expected_incident_signals(self):
""" Render posterior-expected incident (component) signals. """
ax = self._ax_incident
view_y_bottom = ax.yaxis.get_view_interval()[0]
ref = self._signal
total = None
for component in self.expected_incident:
try:
total += component
except TypeError:
total = component
if self._plot_components:
self._add_signal(ax,
self._energies,
component,
**self._comp_expectation_line_kwargs)
self._add_signal(ax,
self._energies,
total,
**self._expectation_line_kwargs)
if self._show_attenuated:
total = None
for component in self.expected_attenuated_incident:
try:
total += component
except TypeError:
total = component
if self._plot_components:
self._add_signal(ax,
self._energies,
component,
**self._comp_expectation_line_kwargs)
self._add_signal(ax,
self._energies,
total,
**self._expectation_line_kwargs)
ax.set_ylim(bottom = view_y_bottom)
ax.set_xlim([self._signal.energy_edges[0],
self._signal.energy_edges[-1]])
locmaj = LogLocator(base=10.0, numticks=100)
ax.yaxis.set_major_locator(locmaj)
locmin = LogLocator(base=10.0, subs=_np.arange(2,10)*0.1, numticks=100)
ax.yaxis.set_minor_locator(locmin)
ax.yaxis.set_minor_formatter(NullFormatter())
def _add_true_registered_signals(self):
""" Render ground truth registered (component) signals. """
ref = self._signals
total = None
for component, phases in zip(ref.signals, ref.phases):
temp = phase_integrator(1.0,
_np.array([0.0,1.0]),
component,
phases,
0.0).reshape(-1)
try:
total += temp
except TypeError:
toral = temp
if self._plot_components:
self._add_registered_spectrum(self._ax_registered_1d,
temp,
**self._comp_truth_line_kwargs)
self._add_registered_spectrum(self._ax_registered_1d,
total,
**self._truth_line_kwargs)
if self._add_background: # another line including the background
total += ref.background_signal
self._add_registered_spectrum(self._ax_registered_1d,
total,
**self._background_line_kwargs)
def _add_expected_registered_signals(self):
""" Render posterior-expected registered (component) signals. """
ref = self._signal
total = None
for component, phases in zip(self.expected_registered, ref.phases):
temp = phase_integrator(1.0,
_np.array([0.0,1.0]),
component,
phases,
0.0).reshape(-1)
try:
total += temp
except TypeError:
total = temp
if self._plot_components:
self._add_registered_spectrum(self._ax_registered_1d,
temp,
**self._comp_expectation_line_kwargs)
# 1D
self._add_registered_spectrum(self._ax_registered_1d,
total,
**self._expectation_line_kwargs)
if self._add_background: # another line including the background
total += self.expected_background
self._add_registered_spectrum(self._ax_registered_1d,
total,
**self._background_line_kwargs)
ax = self._ax_registered_1d
ax.set_xlim([ref.data.channels[0],
ref.data.channels[-1]])
locmaj = LogLocator(base=10.0, numticks=100)
ax.yaxis.set_major_locator(locmaj)
locmin = LogLocator(base=10.0, subs=_np.arange(2,10)*0.1, numticks=100)
ax.yaxis.set_minor_locator(locmin)
ax.yaxis.set_minor_formatter(NullFormatter())
# 2D
total = None
for component, shift, phases in zip(self.expected_registered,
ref.shifts, ref.phases):
temp = interp(self._phases,
phases,
component,
shift)
try:
total += temp
except TypeError:
total = temp
if self._add_background: # add expectated background
for i in range(total.shape[1]):
total[:,i] += self.expected_background
registered = self._ax_registered.pcolormesh(ref.data.channels,
self._phases,
total.T, # channel number as x-axis
cmap = cm.get_cmap(self._registered_cmap),
linewidth = 0,
rasterized = self._rasterized)
registered.set_edgecolor('face')
self._ax_registered.set_xlim([ref.data.channels[0],
ref.data.channels[-1]])
self._registered_cb = plt.colorbar(registered,
cax=self._ax_registered_cb,
ticks=_get_default_locator(None),
format=_get_default_formatter())
self._registered_cb.ax.set_frame_on(True)
self._registered_cb.ax.yaxis.set_minor_locator(AutoMinorLocator())
self._registered_cb.set_label(label=r'counts/s', labelpad=15)
def _add_registered_spectrum(self, ax, spectrum, **kwargs):
""" Add registered spectrum line as a function of channel number. """
if not kwargs:
kwargs.update(dict(color='k', linestyle='-', lw=0.05, alpha=1.0))
elif 'ls' in kwargs:
kwargs['linestyle'] = kwargs.pop('ls')
ax.step(self._signal.data.channels,
spectrum,
where='mid',
**kwargs)
@make_verbose('Adding credible intervals on the incident specific photon '
'flux spectrum',
'Credible intervals added')
def _add_incident_contours(self, callback, thetas):
""" Add contours to 1D incident specific flux spectrum axes objects. """
self._add_contours(callback, thetas, self._energies,
self._ax_incident,
self._ax_incident_cb,
**self._incident_contour_kwargs)
label = r'$\pi(\mathrm{photons/keV/cm}^{2}\mathrm{/s};E)$'
self._ax_incident_cb.set_ylabel(label)
@make_verbose('Adding credible intervals on the count-rate spectrum',
'Credible intervals added')
def _add_registered_contours(self, callback, thetas):
""" Add contours to 1D count-rate spectrum axes objects. """
self._add_contours(callback, thetas, self._signal.data.channels,
self._ax_registered_1d,
self._ax_registered_1d_cb,
**self._registered_contour_kwargs)
self._ax_registered_1d_cb.set_ylabel(r'$\pi(\mathrm{counts/s};\mathrm{channel})$')