Add Jochen colormap, LT and YT map automatic colorscale adjustment
This commit is contained in:
@@ -422,6 +422,7 @@ class PlotColormaps(StrEnum):
|
||||
inferno = "inferno"
|
||||
gist_rainbow = "gist_rainbow"
|
||||
nipy_spectral = "nipy_spectral"
|
||||
jochen_deluxe = "jochen_deluxe"
|
||||
|
||||
@dataclass
|
||||
class ReflectivityOutputConfig(ArgParsable):
|
||||
@@ -458,7 +459,7 @@ class ReflectivityOutputConfig(ArgParsable):
|
||||
)
|
||||
|
||||
plot_colormap: PlotColormaps = field(
|
||||
default=PlotColormaps.gist_ncar,
|
||||
default=PlotColormaps.jochen_deluxe,
|
||||
metadata={
|
||||
'short': 'pcmap',
|
||||
'group': 'output',
|
||||
@@ -594,6 +595,7 @@ class E2HPlotSelection(StrEnum):
|
||||
All = 'all'
|
||||
YZ = 'Iyz'
|
||||
LT = 'Ilt'
|
||||
YT = 'Iyt'
|
||||
TZ = 'Itz'
|
||||
Q = 'Iq'
|
||||
L = 'Il'
|
||||
@@ -673,7 +675,7 @@ class E2HReductionConfig(ArgParsable):
|
||||
)
|
||||
|
||||
plot_colormap: PlotColormaps = field(
|
||||
default=PlotColormaps.gist_ncar,
|
||||
default=PlotColormaps.jochen_deluxe,
|
||||
metadata={
|
||||
'short': 'pcmap',
|
||||
'group': 'output',
|
||||
@@ -689,6 +691,14 @@ class E2HReductionConfig(ArgParsable):
|
||||
},
|
||||
)
|
||||
|
||||
thetaRangeR: Tuple[float, float] = field(
|
||||
default_factory=lambda: [-0.75, 0.75],
|
||||
metadata={
|
||||
'short': 'T',
|
||||
'group': 'region of interest',
|
||||
'help': 'theta region of interest w.r.t. beam center',
|
||||
},
|
||||
)
|
||||
|
||||
@dataclass
|
||||
class E2HConfig:
|
||||
|
||||
@@ -3,12 +3,15 @@ Classes used to calculate projections/binnings from event data onto given grids.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import warnings
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import List, Tuple, Union
|
||||
|
||||
import numpy as np
|
||||
from dataclasses import dataclass
|
||||
|
||||
from matplotlib.colors import LogNorm
|
||||
|
||||
from .event_data_types import EventDatasetProtocol
|
||||
from .instrument import Detector, LZGrid
|
||||
from .normalization import LZNormalisation
|
||||
@@ -275,16 +278,25 @@ class LZProjection(ProjectionInterface):
|
||||
else:
|
||||
cmap=False
|
||||
|
||||
if not 'norm' in kwargs:
|
||||
kwargs['norm'] = LogNorm()
|
||||
|
||||
if self.is_normalized:
|
||||
self._graph = plt.pcolormesh(self.lamda, self.alphaF, self.data.ref, **kwargs)
|
||||
if cmap:
|
||||
plt.colorbar(label='R')
|
||||
I = self.data.ref
|
||||
else:
|
||||
self._graph = plt.pcolormesh(self.lamda, self.alphaF, self.data.I, **kwargs)
|
||||
if cmap:
|
||||
I = self.data.I
|
||||
|
||||
|
||||
if not 'norm' in kwargs:
|
||||
vmin = I[(I>0)].min()
|
||||
vmax = np.nanmax(I)
|
||||
kwargs['norm'] = LogNorm(vmin, vmax, clip=True)
|
||||
|
||||
|
||||
# suppress warning for wrongly sorted y-axis pixels (blades overlap)
|
||||
with warnings.catch_warnings(action='ignore', category=UserWarning):
|
||||
self._graph = plt.pcolormesh(self.lamda, self.alphaF, I, **kwargs)
|
||||
if cmap:
|
||||
if self.is_normalized:
|
||||
plt.colorbar(label='R')
|
||||
else:
|
||||
plt.colorbar(label='I / cpm')
|
||||
plt.xlabel('$\\lambda$ / $\\AA$')
|
||||
plt.ylabel('$\\Theta$ / °')
|
||||
@@ -300,6 +312,20 @@ class LZProjection(ProjectionInterface):
|
||||
"""
|
||||
Inline update of previous plot by just updating the data.
|
||||
"""
|
||||
if self.is_normalized:
|
||||
I = self.data.ref
|
||||
else:
|
||||
I = self.data.I
|
||||
|
||||
if isinstance(self._graph.norm, LogNorm):
|
||||
vmin = I[(I>0)].min()*0.5
|
||||
else:
|
||||
vmin = 0
|
||||
vmax = np.nanmax(I)
|
||||
self._graph.set_array(I)
|
||||
self._graph.norm.vmin = vmin
|
||||
self._graph.norm.vmax = vmax
|
||||
|
||||
if self.is_normalized:
|
||||
self._graph.set_array(self.data.ref)
|
||||
else:
|
||||
@@ -408,23 +434,21 @@ class YZProjection(ProjectionInterface):
|
||||
del(kwargs['colorbar'])
|
||||
else:
|
||||
cmap=False
|
||||
if not 'aspect' in kwargs:
|
||||
kwargs['aspect'] = 'auto'
|
||||
|
||||
vmax = self.data.I.max()
|
||||
|
||||
if not 'norm' in kwargs:
|
||||
kwargs['norm'] = LogNorm()
|
||||
vmin = self.data.I[(self.data.I>0)].min()*0.5
|
||||
kwargs['norm'] = LogNorm(vmin, vmax)
|
||||
|
||||
self._graph = plt.imshow(self.data.I.T,
|
||||
extent=(float(self.y[0]), float(self.y[-1]),
|
||||
float(self.z[0]), float(self.z[-1])),
|
||||
**kwargs)
|
||||
self._graph = plt.pcolormesh(self.y, self.z, self.data.I.T, **kwargs)
|
||||
if cmap:
|
||||
plt.colorbar(label='I / cpm')
|
||||
|
||||
plt.xlabel('Y')
|
||||
plt.ylabel('Z')
|
||||
plt.xlim(self.y[0], self.y[-1])
|
||||
plt.ylim(self.z[0], self.z[-1])
|
||||
plt.ylim(self.z[-1], self.z[0])
|
||||
plt.title('Horizontal Pixel vs. Vertical Pixel')
|
||||
|
||||
self._graph_axis = plt.gca()
|
||||
@@ -434,7 +458,14 @@ class YZProjection(ProjectionInterface):
|
||||
"""
|
||||
Inline update of previous plot by just updating the data.
|
||||
"""
|
||||
if isinstance(self._graph.norm, LogNorm):
|
||||
vmin = self.data.I[(self.data.I>0)].min()*0.5
|
||||
else:
|
||||
vmin = 0
|
||||
vmax = self.data.I.max()
|
||||
self._graph.set_array(self.data.I.T)
|
||||
self._graph.norm.vmin = vmin
|
||||
self._graph.norm.vmax = vmax
|
||||
|
||||
def draw_yzcross(self, event):
|
||||
if event.inaxes is not self._graph_axis:
|
||||
@@ -451,6 +482,57 @@ class YZProjection(ProjectionInterface):
|
||||
art.remove()
|
||||
plt.draw()
|
||||
|
||||
class YTProjection(YZProjection):
|
||||
theta: np.ndarray
|
||||
|
||||
def __init__(self, tthh: float):
|
||||
dd = Detector.delta_z[1]-Detector.delta_z[0]
|
||||
delta = np.hstack([Detector.delta_z, Detector.delta_z[-1]+dd])-dd/2.
|
||||
self.theta = tthh + delta
|
||||
super().__init__()
|
||||
|
||||
def plot(self, **kwargs):
|
||||
from matplotlib import pyplot as plt
|
||||
from matplotlib.colors import LogNorm
|
||||
|
||||
if 'colorbar' in kwargs:
|
||||
cmap=True
|
||||
del(kwargs['colorbar'])
|
||||
else:
|
||||
cmap=False
|
||||
|
||||
if not 'norm' in kwargs:
|
||||
kwargs['norm'] = LogNorm()
|
||||
|
||||
self._graph = plt.pcolormesh(self.y, self.theta, self.data.I.T, **kwargs)
|
||||
if cmap:
|
||||
plt.colorbar(label='I / cpm')
|
||||
|
||||
plt.xlabel('Y')
|
||||
plt.ylabel('Theta / °')
|
||||
plt.xlim(self.y[0], self.y[-1])
|
||||
plt.ylim(self.theta[-1], self.theta[0])
|
||||
plt.title('Horizontal Pixel vs. Angle')
|
||||
|
||||
self._graph_axis = plt.gca()
|
||||
plt.connect('button_press_event', self.draw_tzcross)
|
||||
|
||||
def draw_tzcross(self, event):
|
||||
if event.inaxes is not self._graph_axis:
|
||||
return
|
||||
from matplotlib import pyplot as plt
|
||||
tbm = self._graph_axis.figure.canvas.manager.toolbar.mode
|
||||
if event.button is plt.MouseButton.LEFT and tbm=='':
|
||||
self._graph_axis.plot([event.xdata, event.xdata], [self.theta[0], self.theta[-1]], '-', color='grey')
|
||||
self._graph_axis.plot([self.y[0], self.y[-1]], [event.ydata, event.ydata], '-', color='grey')
|
||||
self._graph_axis.text(event.xdata, event.ydata, f'({event.xdata:.1f}, {event.ydata:.1f})', backgroundcolor='white')
|
||||
plt.draw()
|
||||
if event.button is plt.MouseButton.RIGHT and tbm=='':
|
||||
for art in list(self._graph_axis.lines)+list(self._graph_axis.texts):
|
||||
art.remove()
|
||||
plt.draw()
|
||||
|
||||
|
||||
class TofZProjection(ProjectionInterface):
|
||||
tof: np.ndarray
|
||||
z: np.ndarray
|
||||
@@ -494,23 +576,18 @@ class TofZProjection(ProjectionInterface):
|
||||
del(kwargs['colorbar'])
|
||||
else:
|
||||
cmap=False
|
||||
if not 'aspect' in kwargs:
|
||||
kwargs['aspect'] = 'auto'
|
||||
|
||||
if not 'norm' in kwargs:
|
||||
kwargs['norm'] = LogNorm()
|
||||
|
||||
self._graph = plt.imshow(self.data.I.T,
|
||||
extent=(float(self.tof[0])*1e3, float(self.tof[-1])*1e3,
|
||||
float(self.z[0]), float(self.z[-1])),
|
||||
**kwargs)
|
||||
self._graph = plt.pcolormesh(self.tof*1e3, self.z, self.data.I.T, **kwargs)
|
||||
if cmap:
|
||||
plt.colorbar(label='I / cpm')
|
||||
|
||||
plt.xlabel('Time of Flight / ms')
|
||||
plt.ylabel('Z')
|
||||
plt.xlim(self.tof[0]*1e3, self.tof[-1]*1e3)
|
||||
plt.ylim(self.z[0], self.z[-1])
|
||||
plt.ylim(self.z[-1], self.z[0])
|
||||
plt.title('Time of Flight vs. Vertical Pixel')
|
||||
|
||||
self._graph_axis = plt.gca()
|
||||
|
||||
@@ -5,8 +5,9 @@ Can be used as a live preview with automatic update when files are modified.
|
||||
|
||||
import logging
|
||||
import os
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
from matplotlib.colors import ListedColormap
|
||||
|
||||
from orsopy import fileio
|
||||
from datetime import datetime
|
||||
@@ -20,7 +21,7 @@ from . import event_handling as eh
|
||||
from .path_handling import PathResolver
|
||||
from .projection import CombinedProjection, LZProjection, ProjectionInterface, ReflectivityProjector, TofProjection, \
|
||||
TofZProjection, \
|
||||
YZProjection
|
||||
YTProjection, YZProjection
|
||||
|
||||
NEEDS_LAMDA = (E2HPlotSelection.All, E2HPlotSelection.LT, E2HPlotSelection.Q, E2HPlotSelection.L)
|
||||
|
||||
@@ -70,10 +71,12 @@ class E2HReduction:
|
||||
self.event_actions |= eh.FilterMonitorThreshold(self.config.experiment.lowCurrentThreshold)
|
||||
if not self.config.reduction.fast:
|
||||
self.event_actions |= eh.FilterStrangeTimes()
|
||||
if self.config.reduction.plot==E2HPlotSelection.TZ:
|
||||
# perform time fold-back and corrections for tof if not fast mode
|
||||
if self.config.reduction.plot in [E2HPlotSelection.YT, E2HPlotSelection.YZ]:
|
||||
# perform time fold-back and apply yRange filter if not fast mode
|
||||
self.event_actions |= ea.MergeFrames()
|
||||
self.event_actions |= ea.AnalyzePixelIDs(self.config.experiment.yRange)
|
||||
if self.config.reduction.plot==E2HPlotSelection.YT:
|
||||
# perform corrections for tof if not fast mode
|
||||
self.event_actions |= eh.TofTimeCorrection(self.config.experiment.incidentAngle==IncidentAngle.alphaF)
|
||||
# select needed actions in depenence of plots
|
||||
if self.config.reduction.plot in NEEDS_LAMDA:
|
||||
@@ -87,12 +90,14 @@ class E2HReduction:
|
||||
if self.config.reduction.plot in [E2HPlotSelection.All, E2HPlotSelection.LT, E2HPlotSelection.Q]:
|
||||
self.grid = LZGrid(0.01, [0.0, 0.25])
|
||||
|
||||
if self.config.reduction.plot in [E2HPlotSelection.All, E2HPlotSelection.LT, E2HPlotSelection.YZ, E2HPlotSelection.TZ]:
|
||||
if self.config.reduction.plot in [E2HPlotSelection.All, E2HPlotSelection.LT, E2HPlotSelection.YZ, E2HPlotSelection.YT]:
|
||||
self.plot_kwds['colorbar'] = True
|
||||
self.plot_kwds['cmap'] = str(self.config.reduction.plot_colormap)
|
||||
if self.config.reduction.plotArgs==E2HPlotArguments.Linear:
|
||||
self.plot_kwds['norm'] = None
|
||||
|
||||
self.register_colormap()
|
||||
|
||||
def reduce(self):
|
||||
if self.config.reduction.plot in [E2HPlotSelection.All, E2HPlotSelection.LT, E2HPlotSelection.Q]:
|
||||
if self.config.reduction.normalizationModel:
|
||||
@@ -121,16 +126,29 @@ class E2HReduction:
|
||||
if self.config.reduction.show_plot:
|
||||
plt.show()
|
||||
|
||||
def register_colormap(self):
|
||||
cmap = plt.colormaps['gnuplot'](np.arange(256))
|
||||
cmap[:1, :] = np.array([256/256, 255/256, 236/256, 1])
|
||||
cmap = ListedColormap(cmap, name='jochen_deluxe', N=cmap.shape[0])
|
||||
#cmap.set_bad((1.,1.,0.9))
|
||||
plt.colormaps.register(cmap)
|
||||
|
||||
def prepare_graphs(self):
|
||||
last_file_header = AmorHeader(self.file_list[-1])
|
||||
tthh = last_file_header.geometry.nu - last_file_header.geometry.mu
|
||||
|
||||
if not self.config.reduction.is_default('thetaRangeR'):
|
||||
# adjust range based on detector center
|
||||
thetaRange = [ti+tthh for ti in self.config.reduction.thetaRangeR]
|
||||
else:
|
||||
thetaRange = [tthh - last_file_header.geometry.div/2, tthh + last_file_header.geometry.div/2]
|
||||
|
||||
if self.config.reduction.plot==E2HPlotSelection.LT:
|
||||
self.projection = LZProjection(tthh, self.grid)
|
||||
if not self.config.reduction.fast:
|
||||
self.projection.correct_gravity(last_file_header.geometry.detectorDistance)
|
||||
self.projection.apply_lamda_mask(self.config.experiment.lambdaRange)
|
||||
self.projection.apply_theta_mask(thetaRange)
|
||||
self.projection.apply_norm_mask(self.norm)
|
||||
|
||||
if self.config.reduction.plot==E2HPlotSelection.Q:
|
||||
@@ -139,12 +157,16 @@ class E2HReduction:
|
||||
plz.correct_gravity(last_file_header.geometry.detectorDistance)
|
||||
plz.calculate_q()
|
||||
plz.apply_lamda_mask(self.config.experiment.lambdaRange)
|
||||
plz.apply_theta_mask(thetaRange)
|
||||
plz.apply_norm_mask(self.norm)
|
||||
self.projection = ReflectivityProjector(plz, self.norm)
|
||||
|
||||
if self.config.reduction.plot==E2HPlotSelection.YZ:
|
||||
self.projection = YZProjection()
|
||||
|
||||
if self.config.reduction.plot==E2HPlotSelection.YT:
|
||||
self.projection = YTProjection(tthh)
|
||||
|
||||
if self.config.reduction.plot==E2HPlotSelection.TZ:
|
||||
self.projection = TofZProjection(last_file_header.timing.tau, foldback=not self.config.reduction.fast)
|
||||
|
||||
@@ -157,6 +179,7 @@ class E2HReduction:
|
||||
plz.correct_gravity(last_file_header.geometry.detectorDistance)
|
||||
plz.calculate_q()
|
||||
plz.apply_lamda_mask(self.config.experiment.lambdaRange)
|
||||
plz.apply_theta_mask(thetaRange)
|
||||
plz.apply_norm_mask(self.norm)
|
||||
pr = ReflectivityProjector(plz, self.norm)
|
||||
pyz = YZProjection()
|
||||
|
||||
Reference in New Issue
Block a user