Skip to content

Commit

Permalink
Merge pull request #775 from mantidproject/766_adjust_bragg_peaks_for…
Browse files Browse the repository at this point in the history
…_log

Fix scaling of Bragg peaks for log scales
  • Loading branch information
SilkeSchomann authored Jun 8, 2022
2 parents b4c09af + a2f94d9 commit 93f0b27
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 13 deletions.
48 changes: 43 additions & 5 deletions mslice/plotting/plot_window/cut_plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ def __init__(self, figure_manager, cut_plotter_presenter, workspace_name):
self._waterfall_cache = {}
self._is_icut = False
self._powder_lines = {}
self._datum_dirty = True
self._datum_cache = 0

def save_default_options(self):
self.default_options = {
Expand Down Expand Up @@ -160,6 +162,7 @@ def update_legend(self, line_data=None):

def change_axis_scale(self, xy_config):
current_axis = self._canvas.figure.gca()
orig_y_scale_log = self.y_log
if xy_config['x_log']:
xmin = xy_config['x_range'][0]
xdata = [ll.get_xdata() for ll in current_axis.get_lines()]
Expand Down Expand Up @@ -191,6 +194,9 @@ def change_axis_scale(self, xy_config):
self.x_range = xy_config['x_range']
self.y_range = xy_config['y_range']

if xy_config['y_log'] or (xy_config['y_log'] != orig_y_scale_log):
self.update_bragg_peaks(refresh=True)

def get_line_options(self, line):
index = self._get_line_index(line)
if index >= 0:
Expand Down Expand Up @@ -290,6 +296,9 @@ def remove_line_by_index(self, line_index):
line.remove()
containers.remove(container)

self._datum_dirty = True
self.update_bragg_peaks(refresh=True)

def toggle_errorbar(self, line_index, line_options):
container = self._canvas.figure.gca().containers[line_index]
error_bar_elements = container.get_children()[1:]
Expand Down Expand Up @@ -324,15 +333,38 @@ def set_is_icut(self, is_icut):
def is_icut(self):
return self._is_icut

def update_bragg_peaks(self):
def _get_overplot_datum(self):
if self._datum_dirty:
if not self.waterfall:
self._datum_cache = np.nanmedian([line.get_ydata() for line in self._canvas.figure.gca().get_lines()
if not self._cut_plotter_presenter.is_overplot(line)])
else:
for line in self._canvas.figure.gca().get_lines():
if not self._cut_plotter_presenter.is_overplot(line):
self._datum_cache = np.nanmedian([line.get_ydata()])
break

self._datum_dirty = False

return self._datum_cache

def update_bragg_peaks(self, refresh=False):
if self.plot_window.action_aluminium.isChecked():
self._cut_plotter_presenter.add_overplot_line(self.ws_name, 'Aluminium', False, cif=None)
refresh and self._cut_plotter_presenter.hide_overplot_line(None, 'Aluminium')
self._cut_plotter_presenter.add_overplot_line(self.ws_name, 'Aluminium', False, None, self.y_log,
self._get_overplot_datum())
if self.plot_window.action_copper.isChecked():
self._cut_plotter_presenter.add_overplot_line(self.ws_name, 'Copper', False, cif=None)
refresh and self._cut_plotter_presenter.hide_overplot_line(None, 'Copper')
self._cut_plotter_presenter.add_overplot_line(self.ws_name, 'Copper', False, None, self.y_log,
self._get_overplot_datum())
if self.plot_window.action_niobium.isChecked():
self._cut_plotter_presenter.add_overplot_line(self.ws_name, 'Niobium', False, cif=None)
refresh and self._cut_plotter_presenter.hide_overplot_line(None, 'Niobium')
self._cut_plotter_presenter.add_overplot_line(self.ws_name, 'Niobium', False, None, self.y_log,
self._get_overplot_datum())
if self.plot_window.action_tantalum.isChecked():
self._cut_plotter_presenter.add_overplot_line(self.ws_name, 'Tantalum', False, cif=None)
refresh and self._cut_plotter_presenter.hide_overplot_line(None, 'Tantalum')
self._cut_plotter_presenter.add_overplot_line(self.ws_name, 'Tantalum', False, None, self.y_log,
self._get_overplot_datum())
self.update_legend()

def save_icut(self):
Expand Down Expand Up @@ -412,6 +444,9 @@ def toggle_waterfall(self):
self._apply_offset(self.plot_window.waterfall_x, self.plot_window.waterfall_y)
else:
self._apply_offset(0., 0.)

self._datum_dirty = True
self.update_bragg_peaks(refresh=True)
self._canvas.draw()

def _cache_line(self, line):
Expand Down Expand Up @@ -458,6 +493,9 @@ def on_newplot(self, ax, plot_over):
if new_line and num_lines > 1:
self.toggle_waterfall()

self._datum_dirty = True
self.update_bragg_peaks(refresh=True)

def generate_script(self, clipboard=False):
try:
generate_script(self.ws_name, None, self, self.plot_window, clipboard)
Expand Down
3 changes: 2 additions & 1 deletion mslice/plotting/plot_window/overplot_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ def toggle_overplot_line(plot_handler, plotter_presenter, key, recoil, checked,
plot_handler.manager.report_as_current()

if checked:
plotter_presenter.add_overplot_line(plot_handler.ws_name, key, recoil, cif_file)
plotter_presenter.add_overplot_line(plot_handler.ws_name, key, recoil, cif_file, plot_handler.y_log,
plot_handler._get_overplot_datum())
else:
plotter_presenter.hide_overplot_line(plot_handler.ws_name, key)

Expand Down
8 changes: 8 additions & 0 deletions mslice/plotting/plot_window/slice_plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -574,3 +574,11 @@ def is_changed(self, item):
if self.default_options is None:
return False
return self.default_options[item] != getattr(self, item)

@property
def y_log(self): # needed for interface consistency with cut plot
return False

@staticmethod
def _get_overplot_datum(): # needed for interface consistency with cut plot
return 0
34 changes: 30 additions & 4 deletions mslice/presenters/cut_plotter_presenter.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
from mslice.models.powder.powder_functions import compute_powder_line
import warnings

BRAGG_SIZE_ON_AXES = 0.15


class CutPlotterPresenter(PresenterUtility):

Expand Down Expand Up @@ -97,8 +99,25 @@ def hide_overplot_line(self, workspace, key):
line = cache.pop(key)
remove_line(line)

def add_overplot_line(self, workspace_name, key, recoil, cif=None):
recoil = False
@staticmethod
def _get_log_bragg_y_coords(size, portion_of_axes, datum):
datum = 0.001 if datum == 0 else datum
y1, y2 = plt.gca().get_ylim()
if (y2 > 0 and y1 > 0) or (y2 < 0 and y1 < 0):
total_steps = np.log10(y2 / y1)
elif y1 < 0:
total_steps_up = np.log10(y2) + 1 if abs(y2) >= 1 else abs(y2)
total_steps_down = np.log10(-y1) + 1 if abs(y1) >= 1 else abs(y1)
total_steps = total_steps_up + total_steps_down
else:
y1 = 1 if y1 == 0 else y1
y2 = 1 if y2 == 0 else y2
total_steps = np.log10(y2 / y1) + 1

adj_factor = total_steps * portion_of_axes / 2
return np.resize(np.array([10 ** adj_factor, 10 ** (-adj_factor), np.nan]), size) * datum

def add_overplot_line(self, workspace_name, key, recoil, cif=None, y_has_logarithmic=None, datum=0):
cache = self._cut_cache_dict[plt.gca()][0]
cache.rotated = not is_twotheta(cache.cut_axis.units) and not is_momentum(cache.cut_axis.units)
try:
Expand All @@ -115,9 +134,13 @@ def add_overplot_line(self, workspace_name, key, recoil, cif=None):
q_axis = cache.cut_axis
x, y = compute_powder_line(workspace_name, q_axis, key, cif_file=cif)
try:
y = np.array(y) * (scale_fac / np.nanmax(y))
if not y_has_logarithmic:
y = np.array(y) * scale_fac / np.nanmax(y) + datum
else:
y = self._get_log_bragg_y_coords(len(y), BRAGG_SIZE_ON_AXES, datum)

self._overplot_cache[key] = plot_overplot_line(x, y, key, recoil, cache)
except ValueError:
except (ValueError, IndexError):
warnings.warn("No Bragg peak found.")

def store_icut(self, icut):
Expand All @@ -137,3 +160,6 @@ def update_main_window(self):

def workspace_selection_changed(self):
pass

def is_overplot(self, line):
return line in self._overplot_cache.values()
2 changes: 1 addition & 1 deletion mslice/presenters/slice_plotter_presenter.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def hide_overplot_line(self, workspace, key):
line = cache.overplot_lines.pop(key)
remove_line(line)

def add_overplot_line(self, workspace_name, key, recoil, cif=None):
def add_overplot_line(self, workspace_name, key, recoil, cif=None, y_has_logarithmic=None, datum=None):
cache = self._slice_cache[workspace_name]
if recoil:
x, y = compute_recoil_line(workspace_name, cache.momentum_axis, key)
Expand Down
5 changes: 4 additions & 1 deletion mslice/tests/cut_plot_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def test_change_scale_log(self):
self.axes.get_lines = MagicMock(return_value=[line])
self.canvas.figure.gca = MagicMock(return_value=self.axes)
xy_config = {'x_log': True, 'y_log': True, 'x_range': (0, 20), 'y_range': (1, 7)}

self.cut_plot.update_bragg_peaks = MagicMock()
self.cut_plot.change_axis_scale(xy_config)

if LooseVersion(mpl_version) < LooseVersion('3.3'):
Expand All @@ -67,6 +67,7 @@ def test_change_scale_log(self):
self.axes.set_xscale.assert_called_once_with('symlog', linthresh=10.0)
self.axes.set_yscale.assert_called_once_with('symlog', linthresh=1.0)

self.cut_plot.update_bragg_peaks.assert_called_once_with(refresh=True)
self.assertEqual(self.cut_plot.x_range, (0, 20))
self.assertEqual(self.cut_plot.y_range, (1, 7))

Expand Down Expand Up @@ -99,6 +100,7 @@ def test_update_legend(self):

def test_waterfall(self):
self.cut_plot._apply_offset = MagicMock()
self.cut_plot.update_bragg_peaks = MagicMock()
self.cut_plot.waterfall = True
self.cut_plot.waterfall_x = 1
self.cut_plot.waterfall_y = 2
Expand All @@ -107,3 +109,4 @@ def test_waterfall(self):
self.cut_plot.waterfall = False
self.cut_plot.toggle_waterfall()
self.cut_plot._apply_offset.assert_called_with(0, 0)
self.cut_plot.update_bragg_peaks.assert_called_with(refresh=True)
2 changes: 1 addition & 1 deletion mslice/tests/slice_plot_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def test_arbitrary_recoil_line(self, qt_get_int_mock):
self.plot_figure.action_arbitrary_nuclei.isChecked = MagicMock(return_value=True)

self.slice_plot.arbitrary_recoil_line()
self.slice_plotter.add_overplot_line.assert_called_once_with('workspace', 5, True, None)
self.slice_plotter.add_overplot_line.assert_called_once_with('workspace', 5, True, None, False, 0)

@patch('mslice.plotting.plot_window.slice_plot.QtWidgets.QInputDialog.getInt')
def test_arbitrary_recoil_line_cancelled(self, qt_get_int_mock):
Expand Down

0 comments on commit 93f0b27

Please sign in to comment.