Commit e63b1824 authored by Paul McCarthy's avatar Paul McCarthy 🚵
Browse files

Merge branch 'rel/0.33.2' into 'v0.33'

Rel/0.33.2

See merge request fsl/fsleyes/fsleyes!209
parents 56932482 2de624fa
......@@ -9,6 +9,41 @@ This document contains the ``fsleyes`` release history in reverse
chronological order.
0.33.2 (Tuesday 23rd June 2020)
-------------------------------
Added
^^^^^
* Added some more line styles to the plotting panels (!206).
* Added a new "accessible" lookup table, courtesy of Paul Tol
(https://personal.sron.nl/~pault/) (!206).
Changed
^^^^^^^
* Increased the default plotting line width (!206).
* The default plot colours are now from a pre-generated accessible palette,
rather than being randomly generated (!206).
* The default plot line style is also rotated, in addition the plot colour
(!206).
* Adjusted the histogram panel so that, when plotting a probability histogram,
the values are normalised by bin-width (!203).
* A minor adjustment to the default font, to improve readability on some
platforms (!202).
Fixed
^^^^^
* Fixed an issue with FSLeyes not shutting down cleanly (!204).
0.33.1 (Monday 8th June 2020)
-----------------------------
......
......@@ -371,12 +371,13 @@ latex_elements = {
# special-members flag)
autoclass_content = 'class'
# Document private members and special members (e.g. __init__)
autodoc_default_flags = ['private-members', 'special-members']
# Documentation for python modules is in the same order
# as the source code.
autodoc_member_order = 'bysource'
autodoc_default_options = {
'special-members' : True,
'private-members' : True,
'undoc-members' : True,
'member-order' : 'bysource',
}
def autodoc_skip_member(app, what, name, obj, skip, options):
......
......@@ -5,3 +5,4 @@ freesurfercolorlut FreeSurferColorLut
mgh-cma-freesurfer MGH/CMA/Freesurfer
melodic-classes Melodic IC classification
random_big Random (big)
paul_tol_accessible Accessible
# The "bright" colour-blind accessible colour palette,
# devised by Paul Tol (https://personal.sron.nl/~pault/).
1 0.266667 0.466667 0.666667 Blue
2 0.400000 0.800000 0.933333 Cyan
3 0.133333 0.533333 0.200000 Green
4 0.800000 0.733333 0.266667 Yellow
5 0.933333 0.400000 0.466667 Red
6 0.666667 0.200000 0.466667 Purple
7 0.666667 0.666667 0.666667 Grey
......@@ -133,9 +133,9 @@ class AddMaskDataSeriesAction(base.Action):
xdata = np.arange(len(ydata))
ds.colour = self.__plotPanel.getOverlayPlotColour(overlay)
ds.lineStyle = self.__plotPanel.getOverlayPlotStyle(overlay)
ds.lineWidth = 2
ds.alpha = 1
ds.lineWidth = 1
ds.lineStyle = '-'
ds.label = '{} [mask: {}]'.format(overlay.name, maskimg.name)
# We have to run the data through
......
......@@ -135,9 +135,9 @@ class AddROIHistogramAction(base.Action):
self.displayCtx,
self.__plotPanel)
ds.colour = self.__plotPanel.getOverlayPlotColour(overlay)
ds.lineStyle = self.__plotPanel.getOverlayPlotStyle(overlay)
ds.lineWidth = 2
ds.alpha = 1
ds.lineWidth = 1
ds.lineStyle = '-'
ds.label = '{} [mask: {}]'.format(overlay.name, maskimg.name)
# We have to run the data through
......
......@@ -855,7 +855,10 @@ def fileType(fname):
return 'vest'
with open(fname, 'rt') as f:
line = f.readline().strip()
for line in f:
line = f.readline().strip()
if (line != '') and (not line.startswith('#')):
break
tkns = list(line.split())
......
......@@ -164,7 +164,7 @@ class FSLeyesFrame(wx.Frame):
fontSize = 10
font.SetPointSize(fontSize)
font.SetWeight(wx.FONTWEIGHT_LIGHT)
font.SetWeight(wx.FONTWEIGHT_NORMAL)
self.SetFont(font)
self.__overlayList = overlayList
......
......@@ -615,6 +615,7 @@ class GLContext(object):
# created, we no longer need
# references to the wx objects
app = self.__app
self.__parent.Close()
self.__parent = None
self.__canvas = None
self.__app = None
......
......@@ -71,8 +71,18 @@ class DataSeries(props.HasProperties):
"""Line width. """
lineStyle = props.Choice(('-', '--', '-.', ':'))
"""Line style. """
lineStyle = props.Choice(('-',
'--',
'-.',
':',
(0, (5, 7)),
(0, (1, 7)),
(0, (4, 10, 1, 10)),
(0, (4, 1, 1, 1, 1, 1)),
(0, (4, 1, 4, 1, 1, 1))))
"""Line style. See
https://matplotlib.org/gallery/lines_bars_and_markers/linestyles.html
"""
def __init__(self, overlay, overlayList, displayCtx, plotPanel):
......
......@@ -222,6 +222,13 @@ class HistogramSeries(dataseries.DataSeries):
return self.__xdata, self.__ydata
@property
def binWidth(self):
"""Returns the width of one bin for this :class:`HistogramSeries`. """
lo, hi = self.dataRange.x
return (hi - lo) / self.nbins
def getVertexData(self):
"""Returns a ``numpy`` array of shape ``(N, 2)``, which contains a
set of "vertices" which can be used to display the histogram data
......@@ -241,7 +248,8 @@ class HistogramSeries(dataseries.DataSeries):
return verts
def getNumHistogramValues(self):
@property
def numHistogramValues(self):
"""Returns the number of values which were used in calculating the
histogram.
"""
......
......@@ -427,7 +427,9 @@ class RangePolygon(patches.Polygon):
# post-processing normally performed
# by the HistogramPanel to the data.
if hsPanel.histType == 'probability':
vertices[:, 1] /= hs.getNumHistogramValues()
nvals = hs.numHistogramValues
binWidth = hs.binWidth
vertices[:, 1] /= (nvals * binWidth)
# Nothing to plot, or we shouldn't
# be plotting the range overlay
......@@ -457,7 +459,9 @@ class RangePolygon(patches.Polygon):
yval = float(histy[xidx])
if hsPanel.histType == 'probability':
yval /= hs.getNumHistogramValues()
nvals = hs.numHistogramValues
binWidth = hs.binWidth
yval /= (nvals * binWidth)
vertices = np.array([[lo, 0], [lo, yval], [hi, yval], [hi, 0]])
......
......@@ -1329,10 +1329,17 @@ choices = TypeDict({
'HistogramPanel.plotType' : {'centre' : 'Bin centres',
'edge' : 'Bin edges'},
'DataSeries.lineStyle' : {'-' : 'Solid line',
'--' : 'Dashed line',
'-.' : 'Dash-dot line',
':' : 'Dotted line'},
'DataSeries.lineStyle' : {
'-' : 'Solid line',
'--' : 'Dashed line',
'-.' : 'Dash-dot line',
':' : 'Dotted line',
(0, (5, 7)) : 'Loose dashed line',
(0, (1, 7)) : 'Loose dotted line',
(0, (4, 10, 1, 10)) : 'Loose dash-dot line',
(0, (4, 1, 1, 1, 1, 1)) : 'Dash-dot-dot line',
(0, (4, 1, 4, 1, 1, 1)) : 'Dash-dash-dot line',
},
'TimeSeriesPanel.plotMode' : {'normal' : 'Normal - no '
'scaling/offsets',
......
......@@ -14,7 +14,7 @@ version number. See also the :mod:`fsl.version` module.
"""
__version__ = '0.33.1'
__version__ = '0.33.2'
"""Current version number, as a string. The FSLeyes version number consists
of three numbers, separated by a period, which roughly obeys the Semantic
Versioning conventions (http://semver.org/).
......
......@@ -254,9 +254,9 @@ class HistogramPanel(plotpanel.OverlayPlotPanel):
hs = hsType(overlay, self.overlayList, self.displayCtx, self)
hs.colour = self.getOverlayPlotColour(overlay)
hs.lineStyle = self.getOverlayPlotStyle(overlay)
hs.lineWidth = 2
hs.alpha = 1
hs.lineWidth = 1
hs.lineStyle = '-'
return hs, [], []
......@@ -310,9 +310,16 @@ class HistogramPanel(plotpanel.OverlayPlotPanel):
return xdata, ydata
# Or a HistogramSeries instance
nvals = hs.getNumHistogramValues()
if self.histType == 'count': return xdata, ydata
elif self.histType == 'probability': return xdata, ydata / nvals
if self.histType == 'count':
return xdata, ydata
# Normalise by bin width to produce a
# probability density function, so it
# will look approximately the same,
# regardless of the current nbins setting
elif self.histType == 'probability':
nvals = hs.numHistogramValues
return xdata, ydata / (nvals * hs.binWidth)
def __selectedOverlayChanged(self, *a):
......
......@@ -831,6 +831,7 @@ class PlotPanel(viewpanel.ViewPanel):
labels,
loc='upper right',
fontsize=10,
handlelength=3,
fancybox=True)
legend.get_frame().set_alpha(0.6)
......@@ -1131,8 +1132,17 @@ class OverlayPlotPanel(PlotPanel):
the same (initial) colour is used for the same overlay, across multiple
plots.
Sub-classes should use the :meth:`getOverlayPlotColour` method to retrieve
the initial colour to use for a given overlay.
See also :attr:`plotStyles`.
Sub-classes should use the :meth:`getOverlayPlotColour` and
:meth:`getOverlayPlotStyle`methods to retrieve the initial colour and
linestyle to use for a given overlay.
"""
plotStyles = {}
"""This dictionary is used to store a collection of ``{overlay : colour}``
mappings - it is used in conjunction with :attr:`plotColours`.
"""
......@@ -1182,6 +1192,15 @@ class OverlayPlotPanel(PlotPanel):
self.__refreshProps = {}
self.__refreshCounts = {}
# Pre-generated default colours and line
# styles to use - see plotColours, plotStyles,
# getOverlayPlotColour, and getOverlayPlotStyle
lut = fslcm.getLookupTable('paul_tol_accessible')
styles = plotting.DataSeries.lineStyle.getChoices()
limit = min(len(lut), len(styles))
self.__defaultColours = [l.colour for l in lut[ :limit]]
self.__defaultStyles = [s for s in styles[:limit]]
self .addListener('dataSeries',
self.__name,
self.__dataSeriesChanged)
......@@ -1276,12 +1295,36 @@ class OverlayPlotPanel(PlotPanel):
colour = self.plotColours.get(overlay)
if colour is None:
colour = fslcm.randomDarkColour()
idx = len(self.plotColours) % len(self.__defaultColours)
colour = self.__defaultColours[idx]
self.plotColours[overlay] = colour
return colour
def getOverlayPlotStyle(self, overlay):
"""Returns an initial line style to use for plots associated with the
given overlay. If a colour is present in the :attr:`plotStyles`
dictionary, it is returned. Otherwise a line style is generated,
added to ``plotStyles``, and returned.
The format of the returned line style is suitable for use with the
``linestyle`` argument of the ``matplotlib`` ``plot``functions.
"""
if isinstance(overlay, fsloverlay.ProxyImage):
overlay = overlay.getBase()
style = self.plotStyles.get(overlay)
if style is None:
idx = len(self.plotStyles) % len(self.__defaultStyles)
style = self.__defaultStyles[idx]
self.plotStyles[overlay] = style
return style
@actions.action
def addDataSeries(self):
"""Every :class:`.DataSeries` which is currently plotted, and has not
......@@ -1374,7 +1417,9 @@ class OverlayPlotPanel(PlotPanel):
.. note:: Sub-class implementations should set the
:attr:`.DataSeries.colour` property to that returned by
the :meth:`getOverlayPlotColour` method.
the :meth:`getOverlayPlotColour` method, and the
:attr:`.DataSeries.lineStyle` property to that returned by
the :meth:`getOverlayPlotStyle` method
Different ``DataSeries`` types need to be re-drawn when different
......
......@@ -207,9 +207,9 @@ class PowerSpectrumPanel(plotpanel.OverlayPlotPanel):
return None, None, None
ps.colour = self.getOverlayPlotColour(overlay)
ps.lineStyle = self.getOverlayPlotStyle(overlay)
ps.lineWidth = 2
ps.alpha = 1.0
ps.lineWidth = 1
ps.lineStyle = '-'
return ps, targets, propNames
......
......@@ -344,9 +344,9 @@ class TimeSeriesPanel(plotpanel.OverlayPlotPanel):
return None, None, None
ts.colour = self.getOverlayPlotColour(overlay)
ts.lineStyle = self.getOverlayPlotStyle(overlay)
ts.lineWidth = 2
ts.alpha = 1
ts.lineWidth = 1
ts.lineStyle = '-'
return ts, targets, propNames
......
......@@ -100,7 +100,7 @@ def test_HistogramSeries():
gotx, goty = hs.getData()
assert hs.nbins == nbins
assert hs.getNumHistogramValues() == nvals
assert hs.numHistogramValues == nvals
assert np.all(np.isclose(hx, gotx))
assert np.all(np.isclose(hy, goty))
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment