Skip to content
Merged
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 148 additions & 10 deletions hexrdgui/image_canvas.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import copy
import math
import logging

from PySide6.QtCore import QThreadPool, QTimer, Signal, Qt
from PySide6.QtWidgets import QFileDialog, QMessageBox
Expand All @@ -8,8 +9,9 @@
from matplotlib.figure import Figure
from matplotlib.lines import Line2D
from matplotlib.patches import Circle
from matplotlib.ticker import AutoLocator, FuncFormatter
from matplotlib.ticker import AutoLocator, AutoMinorLocator, FuncFormatter

import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.transforms as tx

Expand All @@ -35,6 +37,8 @@
)
from hexrdgui.utils.tth_distortion import apply_tth_distortion_if_needed

FONTSIZE_LABEL=15
FONTSIZE_TICKS=15

class ImageCanvas(FigureCanvas):

Expand Down Expand Up @@ -1004,6 +1008,7 @@ def show_polar(self):
worker.signals.error.connect(self.async_worker_error)

def finish_show_polar(self, iviewer):

if self.mode != ViewType.polar:
# Image mode was switched during generation. Ignore this.
return
Expand Down Expand Up @@ -1034,10 +1039,39 @@ def finish_show_polar(self, iviewer):
}
self.axes_images.append(self.axis.imshow(**kwargs))
self.axis.axis('auto')

self.axis.yaxis.set_major_locator(AutoLocator())
self.axis.yaxis.set_minor_locator(AutoMinorLocator())

self.axis.xaxis.set_major_locator(PolarXAxisTickLocator(self))
self.axis.xaxis.set_minor_locator(PolarXAxisMinorTickLocator(self))

kwargs = {
'left': True,
'right': True,
'bottom': True,
'top': True,
'which': 'major',
'length': 10,
'labelfontfamily': 'serif',
'labelsize': FONTSIZE_TICKS,
}
self.axis.tick_params(**kwargs)

kwargs['which'] = 'minor'
kwargs['length'] = 2
self.axis.tick_params(**kwargs)

self.axis.tick_params(
bottom=True, top=True, which='major', length=8)
self.axis.tick_params(
bottom=True, top=True, which='minor', length=2)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe these don't have have an effect (these appear to be set by the previous calls to tick_params, and I don't see a difference in the plots if I remove these lines).

Do you know if these lines are necessary?


# Do not allow the axis to autoscale, which could happen if
# overlays are drawn out-of-bounds
self.axis.autoscale(False)
self.axis.set_ylabel(r'$\eta$ [deg]')
self.axis.set_ylabel(
r'$\eta$ [deg]', fontsize=FONTSIZE_LABEL, family='serif')
self.axis.label_outer()
else:
rescale_image = False
Expand All @@ -1053,11 +1087,11 @@ def finish_show_polar(self, iviewer):
axis = self.figure.add_subplot(grid[3, 0], sharex=self.axis)
data = (tth, self.compute_azimuthal_integral_sum())
unscaled = (tth, self.compute_azimuthal_integral_sum(False))
self.azimuthal_line_artist, = axis.plot(*data)
self.azimuthal_line_artist, = axis.plot(*data, '-k', lw=2.5)
HexrdConfig().last_unscaled_azimuthal_integral_data = unscaled

self.azimuthal_integral_axis = axis
axis.set_ylabel(r'Azimuthal Average')
axis.set_ylabel(r'Azimuthal Average', fontsize=FONTSIZE_LABEL, family='serif')
self.update_azimuthal_plot_overlays()
self.update_wppf_plot()

Expand All @@ -1067,15 +1101,62 @@ def finish_show_polar(self, iviewer):
formatter = PolarXAxisFormatter(default_formatter, f)
axis.xaxis.set_major_formatter(formatter)

# Set our custom tick locators as well
self.axis.xaxis.set_major_locator(PolarXAxisTickLocator(self))
axis.yaxis.set_major_locator(AutoLocator())
axis.yaxis.set_minor_locator(AutoMinorLocator())

axis.xaxis.set_major_locator(PolarXAxisTickLocator(self))
self.axis.xaxis.set_minor_locator(PolarXAxisMinorTickLocator(self))

# change property of ticks
kwargs = {
'left': True,
'right': True,
'bottom': True,
'top': True,
'which': 'major',
'length': 10,
'labelfontfamily': 'serif',
'labelsize': FONTSIZE_TICKS,
}
axis.tick_params(**kwargs)

kwargs['which'] = 'minor'
kwargs['length'] = 2
axis.tick_params(**kwargs)

# add grid lines parallel to x-axis in azimuthal average
kwargs = {
'visible': True,
'which': 'major',
'axis': 'y',
'linewidth': 0.25,
'linestyle': '-',
'color': 'k',
'alpha': 0.75,
}
axis.grid(**kwargs)

kwargs = {
'visible': True,
'which': 'minor',
'axis': 'y',
'linewidth': 0.075,
'linestyle': '--',
'color': 'k',
'alpha': 0.9,
}
axis.grid(**kwargs)

# add grid lines parallel to y-axis
kwargs['which'] = 'both'
kwargs['axis'] = 'x'
axis.grid(**kwargs)
else:
self.update_azimuthal_integral_plot()
axis = self.azimuthal_integral_axis

# Update the xlabel in case it was modified (via tth distortion)
axis.set_xlabel(self.polar_xlabel)
axis.set_xlabel(self.polar_xlabel, fontsize=FONTSIZE_LABEL, family='serif')
else:
if len(self.axes_images) == 0:
self.axis = self.figure.add_subplot(111)
Expand All @@ -1087,13 +1168,14 @@ def finish_show_polar(self, iviewer):
'interpolation': 'none',
}
self.axes_images.append(self.axis.imshow(**kwargs))
self.axis.set_ylabel(r'$\eta$ [deg]')
self.axis.set_ylabel(r'$\eta$ [deg]', fontsize=FONTSIZE_LABEL, family='serif')
else:
rescale_image = False
self.axes_images[0].set_data(img)

# Update the xlabel in case it was modified (via tth distortion)
self.axis.set_xlabel(self.polar_xlabel)
self.axis.set_xlabel(self.polar_xlabel, fontsize=FONTSIZE_LABEL, family='serif')


if rescale_image:
self.axis.relim()
Expand Down Expand Up @@ -1193,7 +1275,8 @@ def polar_x_axis_type(self):

def on_polar_x_axis_type_changed(self):
# Update the x-label
self.azimuthal_integral_axis.set_xlabel(self.polar_xlabel)
self.azimuthal_integral_axis.set_xlabel(self.polar_xlabel,
fontsize=FONTSIZE_LABEL, family='serif')

# Still need to draw if the x-label was modified
self.draw_idle()
Expand Down Expand Up @@ -1755,6 +1838,61 @@ def tick_values(self, vmin, vmax):
# Convert back to tth
return canvas.polar_x_type_to_tth(values)

class PolarXAxisMinorTickLocator(AutoMinorLocator):
"""Subclass the tick locator so we can modify its behavior

We will modify any value ranges provided so that the current x-axis type
provides nice looking ticks.

For instance, for Q, we want to space minor ticks non-linearly between major ticks
"""
def __init__(self, canvas, *args, **kwargs):
super().__init__(*args, **kwargs)
self._hexrdgui_canvas = canvas

def __call__(self):
canvas = self._hexrdgui_canvas
if self.axis.get_scale() == 'log':
logging.warning('PolarXAxisMinorTickLocator does not work on logarithmic scales')
return []

majorlocs = np.unique(self.axis.get_majorticklocs())
if len(majorlocs) < 2:
# Need at least two major ticks to find minor tick locations.
# TODO: Figure out a way to still be able to display minor ticks with less
# than two major ticks visible. For now, just display no ticks at all.
return []

# Convert to our current x type
majorlocs = canvas.polar_tth_to_x_type(majorlocs)
majorstep = majorlocs[1] - majorlocs[0]

if self.ndivs is None:
self.ndivs = mpl.rcParams[
'ytick.minor.ndivs' if self.axis.axis_name == 'y'
else 'xtick.minor.ndivs'] # for x and z axis

if self.ndivs == 'auto':
majorstep_mantissa = 10 ** (np.log10(majorstep) % 1)
ndivs = 5 if np.isclose(majorstep_mantissa, [1, 2.5, 5, 10]).any() else 4
else:
ndivs = self.ndivs

minorstep = majorstep / ndivs

vmin, vmax = sorted(self.axis.get_view_interval())
# Convert to our current x type
vmin, vmax = canvas.polar_tth_to_x_type([vmin, vmax])
t0 = majorlocs[0]
tmin = round((vmin - t0) / minorstep)
tmax = round((vmax - t0) / minorstep) + 1
locs = (np.arange(tmin, tmax) * minorstep) + t0

# Convert back to tth
locs = canvas.polar_x_type_to_tth(locs)

return self.raise_if_exceeds(locs)


class PolarXAxisFormatter(FuncFormatter):
"""Subclass the func formatter so we can keep the default formatter in sync
Expand Down
Loading