Skip to content

Commit

Permalink
Merge pull request #35 from samueldmcdermott/ticklabel34
Browse files Browse the repository at this point in the history
Version 0.5
  • Loading branch information
FaustinCarter authored Oct 12, 2023
2 parents 586d4fd + adcfecd commit 7af0f50
Show file tree
Hide file tree
Showing 14 changed files with 55 additions and 136 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/pythonpackage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10"]
python-version: ["3.8", "3.9", "3.10", "3.11"]
os: [windows-latest]

steps:
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
Version 0.5.0
* Drop support for matplotlib < 2.2 and numpy < 1.7.1
* Take advantage of "new" built in axis-label alignment (thanks @samueldmcdermott)
* Dropped `holdRC` keyword argument now that minimum matplotlib version is greater than 2.0

Version 0.4.1
* Add `packaging` package to explicit list of deps to fix import bug.
* Fix bug where plot legend did not respect truthLineStyles
Expand Down
28 changes: 15 additions & 13 deletions docs/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ Required packages

pygtc is compatible with Python 2.7 and 3.6 or greater and requires the following packages:

* numpy >= 1.5
* matplotlib >= 1.5.3 (preferably >= 2.0)
* numpy >= 1.7.1
* matplotlib >= 2.2.0
* scipy (optional)
* packaging
* packaging (typcally included with setuptools already)
* pandas (optional -- provides easy auto-naming of chains)
* pytest (optional -- only needed for running unit tests)
* pytest-mpl (optional -- only needed for running unit tests)
Expand Down Expand Up @@ -57,23 +57,25 @@ or from source::
Running tests
~~~~~~~~~~~~~
For tests to *for sure* pass (i.e. reproduce pixel-perfect copies of our
baseline images), you'll want to have ``matplotlib ==3.5.1`` installed and be
working on ``python >=3.9``. Additionally you'll need to ensure that you are
using ``freetype ==2.10.4``. You'll need ``pytest`` and ``pytest-mpl`` installed
to run the tests, although pygtc functions fine without them. You also should
have the Arial font installed, as that is pygtc's default font and tests will
"fail" if matplotlib falls back on Deja Vu Sans (even though the images produced
might look perfectly fine). Test base images were produced on Windows 10 using
the ``Agg`` backend and if you are on another system there is no guarantee that
you will get a pixel-perfect copy of what the Agg backend produces. However, the
baseline images), you'll want to have ``matplotlib == 3.7.2`` installed and be
working on ``python >= 3.9``. Additionally you'll need to ensure that you are
using ``freetype ==2.12.1`` (although versions as low as ``2.10`` may work,
too). You'll need ``pytest`` and ``pytest-mpl`` installed to run the tests,
although pygtc functions fine without them. You also should have the Arial font
installed, as that is pygtc's default font and tests will "fail" if matplotlib
falls back on Deja Vu Sans (even though the images produced might look perfectly
fine). Test base images were produced on Windows 10 using the ``Agg`` backend.
If you are on another system there is no guarantee that you will get a
pixel-perfect copy of what the Agg backend produces (although when we ran them
on Ubuntu 20.04 with the above version pins they all passed). However, the
images produced by the tests should still look great! They are saved to a folder
called ``result_images`` in whatever directory you ran the tests from.

To run the test suite, use the pytest utility from within the pygtc package
directory::

cd /path/to/pygtc
pytest --mpl --mpl-results-path=results
pytest --mpl --mpl-results-path=./result_images

There are 25 tests to run, and it should take between 20-30 seconds to run them
all. If the first test fails, there may be something wrong with your matplotlib
Expand Down
2 changes: 1 addition & 1 deletion pygtc/VERSION.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.4.1
0.5.0
3 changes: 2 additions & 1 deletion pygtc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
__author__ = "Sebastian Bocquet and Faustin W. Carter"
__contributors__ = [
'Samuel Flender',
'Ben Hoyle'
'Ben Hoyle',
'Samuel D McDermott',
]
__all__ = ['plotGTC', 'haveScipy']
version_filename = os.path.join(os.path.dirname(
Expand Down
133 changes: 20 additions & 113 deletions pygtc/pygtc.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,10 @@
except ImportError:
haveScipy = False

PYVER = sys.version_info[0]
MPLVER = version.parse(mpl.__version__)
_PYVER = sys.version_info[0]
_MPLVER = version.parse(mpl.__version__)

if MPLVER >= version.parse('2.1'):
density_kw = {'density':True}
else:
warnings.warn("Future versions of pygtc will require matplotlib >= 2.1", DeprecationWarning)
density_kw = {'normed':True}
_SNAKE_LEGEND_HANDLES = _MPLVER >= version.parse('3.6')

__all__ = ['plotGTC']

Expand Down Expand Up @@ -173,8 +169,7 @@ def plotGTC(chains, **kwargs):
mathTextFontSet : string
Set font family for rendering LaTex. Default is ``'stixsans'``. Set to
``None`` to use the default setting in your matplotlib rc. See Notes
for known issues regarding this keyword.
``None`` to use the default setting in your matplotlib rc.
customLabelFont : ``matplotlib.fontdict``
Full customization of label fonts. See matplotlib for full
Expand All @@ -189,46 +184,13 @@ def plotGTC(chains, **kwargs):
documentation. Default is ``{'family':'Arial', 'size':6}``. Attempting
to set the color will result in an error.
holdRC : bool
Whether or not to reset rcParams back to default. You may wish to set
this to ``True`` if you are working in interactive mode (ie with
IPython or in a JuPyter notebook) and you want the plots that display
to be identical to the plots that save in the pdf. See Notes below for
more information. Default is ``False``.
Returns
-------
fig : ``matplotlib.figure`` object
You can do all sorts of fun things with this in terms of customization
after it gets returned. If you are using a ``JuPyter`` notebook with
inline plotting enabled, you should assign a variable to catch the
return or else the figure will plot twice.
Note
----
If you are calling ``plotGTC`` from within an interactive python session
(ie via IPython or in a JuPyter notebook), the label font in the saved pdf
may differ from the plot that appears when calling
``matplotlib.pyplot.show()``.
This will happen if the mathTextFontSet keyword sets a value that is
different than the one stored in ``rcParams['mathtext.fontset']`` and you
are using equations in your labels by enclosing them in $..$. The output
pdf will display correctly, but the interactive plot will use whatever is
stored in the rcParams default to render the text that is inside the $..$.
Unfortunately, this is an oversight in matplotlib's design, which only
allows one global location for specifying this setting. As a workaround,
you can set ``holdRC = True`` when calling ``plotGTC`` and it will *not*
reset your rcParams back to their default state. Thus, when the figure
renders in interactive mode, it will match the saved pdf. If you wish to
reset your rcParams back to default at any point, you can call
``matplotlib.rcdefaults()``. However, if you are in a jupyter notebook and
have set ``%matplotlib inline``, then calling ``matplotlib.rcdefaults()``
may not set things back the way they were, but rerunning the line magic
will.
This is all due to a bug in matplotlib that is slated to be fixed in the
upcoming 2.0 release."""
return or else the figure will plot twice."""

# Figure setting

Expand Down Expand Up @@ -537,9 +499,6 @@ def plotGTC(chains, **kwargs):
if mathTextFontSet is not None:
plt.rcParams['mathtext.fontset'] = mathTextFontSet

holdRC = kwargs.pop('holdRC', False)
assert holdRC in [True, False], "holdRC must be True or False."

# Grab the custom fontdicts
# Default size is 9 for all labels.
defaultFontFamily = 'Arial'
Expand Down Expand Up @@ -733,7 +692,7 @@ def _mpx(self, x):
x+self.custom_shift)

# Python 3 changes how this gets called
if PYVER >= 3:
if _PYVER >= 3:

xLabel.set_x = types.MethodType(_mpx, xLabel)
else:
Expand Down Expand Up @@ -767,7 +726,7 @@ def _mpx(self, x):
def _mpy(self, y):
return mpl.text.Text.set_y(self,
y+self.custom_shift)
if PYVER >= 3:
if _PYVER >= 3:
yLabel.set_y = types.MethodType(_mpy, yLabel)
else:
yLabel.set_y = types.MethodType(_mpy, yLabel,
Expand Down Expand Up @@ -838,20 +797,6 @@ def _mpy(self, y):
if paramNames is not None:
ax.set_xlabel(paramNames[i], fontdict=customLabelFont)

# Hack to get scaling to work for final 1D plot under MPL < 2.0
if (MPLVER < version.parse('2.0')) and (smoothingKernel == 0):
max_y = 0
# Loop through the children, find the polygons
# and extract the maximum y-value
for child in ax.get_children():
if type(child) == plt.Polygon:
child_max_y = child.get_xy()[:, 1].max()
if child_max_y > max_y:
max_y = child_max_y

# Set upper limit to be 5% above maximum y-value
ax.set_ylim(0, max_y*1.05)

else:
ax.get_xaxis().set_ticklabels([])

Expand Down Expand Up @@ -896,7 +841,7 @@ def _mpy(self, y):
# shift the x labels when it gets called during render
def _mpx(self, x):
return mpl.text.Text.set_x(self, x+self.custom_shift)
if PYVER >= 3:
if _PYVER >= 3:
xLabel.set_x = types.MethodType(_mpx, xLabel)
else:
xLabel.set_x = types.MethodType(_mpx, xLabel,
Expand All @@ -913,49 +858,8 @@ def _mpx(self, x):

# Align labels if there is more than one panel
if len(axH) > 1:
fig.canvas.draw()
bboxSize = np.empty(len(axH))

try:
# This is the canonical way to get the renderer, which the OSX
# backend started supporting in mpl 2.0. Older versions of the OSX
# backend don't implement the method though, and access the
# renderer obect directly. This should do it right, but fall
# through to the "wrong" way for older versions or backends that
# have yet to implement.
renderer = fig.canvas.get_renderer()
except AttributeError:
# If the get_renderer method doesn't exist, then try accessing the
# renderer directly.
renderer = fig.canvas.renderer

# x labels
# Get label length of the bottom row
for i in range(len(axH)):
bboxTickLabel = (axH[i].xaxis.get_ticklabel_extents(renderer)[0]
.get_points())
bboxSize[i] = bboxTickLabel[1, 1]-bboxTickLabel[0, 1]
panelWidth = (axH[i].get_window_extent()
.transformed(fig.dpi_scale_trans.inverted()).width)
# Apply longest spacing to all panels in last row
longestTickLabel = 3+np.amax(bboxSize)
loc = (longestTickLabel/mplPPI/panelWidth)
for i in range(len(axH)):
axH[i].get_xaxis().set_label_coords(.5, -loc)

# y labels
# Get label length of the left column
for i in range(len(axV)):
bboxTickLabel = (axV[i].yaxis.get_ticklabel_extents(renderer)[0]
.get_points())
bboxSize[i] = bboxTickLabel[1, 0]-bboxTickLabel[0, 0]
panelHeight = (axV[i].get_window_extent()
.transformed(fig.dpi_scale_trans.inverted()).height)
# Apply longest spacing to all panels in first column
longestTickLabel = 2+np.amax(bboxSize)
loc = (longestTickLabel/mplPPI/panelHeight)
for i in range(len(axV)):
axV[i].get_yaxis().set_label_coords(-loc, .5)
fig.align_ylabels(axV)
fig.align_xlabels(axH)

# Legend
if (chainLabels is not None) or (truthLabels is not None):
Expand Down Expand Up @@ -994,8 +898,12 @@ def _mpx(self, x):
text.set_color(color)
# Remove markers in legend
if showLegendMarker is not True:
for item in leg.legendHandles:
item.set_visible(False)
if _SNAKE_LEGEND_HANDLES:
for item in leg.legend_handles:
item.set_visible(False)
else:
for item in leg.legendHandles:
item.set_visible(False)

# Panel spacing, save to file (optional) and return

Expand All @@ -1010,8 +918,7 @@ def _mpx(self, x):
if plotName is not None:
fig.savefig(plotName, bbox_inches='tight')

if not holdRC:
plt.rcParams['mathtext.fontset'] = oldMathTextFontSet
plt.rcParams['mathtext.fontset'] = oldMathTextFontSet

return fig

Expand Down Expand Up @@ -1082,7 +989,7 @@ def __plot1d(ax, nChains, chains1d, weights, nBins, smoothingKernel,
else:
# create 1d histogram
hist1d, edges = np.histogram(chains1d[k], weights=weights[k],
bins=nBins, **density_kw)
bins=nBins, density=True)
# Bin center between histogram edges
centers = (edges[1:]+edges[:-1])/2
# Filter data
Expand All @@ -1107,13 +1014,13 @@ def __plot1d(ax, nChains, chains1d, weights, nBins, smoothingKernel,
# Filled stepfilled histograms
ax.hist(chains1d[k], weights=weights[k],
bins=nBins, histtype='stepfilled',
edgecolor='None', color=colors[k][1], **density_kw)
edgecolor='None', color=colors[k][1], density=True)
for k in reversed(range(nChains)):
# Is there a chain to plot?
if not np.isnan(chains1d[k]).all():
# Step curves for hidden histogram(s)
ax.hist(chains1d[k], weights=weights[k],
bins=nBins, histtype='step', color=colors[k][1], **density_kw)
bins=nBins, histtype='step', color=colors[k][1], density=True)

# Truth line
if truths1d is not None:
Expand Down
Binary file modified pygtc/tests/baseline/mathTextFontSet.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified pygtc/tests/baseline/pandas.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified pygtc/tests/baseline/paramNames_noTex.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified pygtc/tests/baseline/paramNames_withTex.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#####Stricter version requirements than setup.py#####
packaging
numpy >= 1.5
matplotlib >=1.5.3
numpy >= 1.7.1
matplotlib >=2.2.0

#####Packages that provide some extra utility, but aren't required#####
#pytest
Expand Down
4 changes: 2 additions & 2 deletions rtd_environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ dependencies:
- packaging
- python>=3.6
- ipython>=6.2
- matplotlib-base>=2.0
- numpy>=1.5
- matplotlib-base>=2.2
- numpy>=1.7.1
- scipy
6 changes: 5 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@
]
},
long_description=open("README.rst").read(),
install_requires=["packaging", "numpy", "matplotlib"],
install_requires=[
"packaging",
"numpy>=1.7.1",
"matplotlib>=2.2",
],
classifiers=[
"Development Status :: 4 - Beta",
"Intended Audience :: Science/Research",
Expand Down
4 changes: 2 additions & 2 deletions test-environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ channels:
- defaults
- conda-forge
dependencies:
- freetype=2.10.4
- matplotlib=3.5.1
- freetype=2.12.1
- matplotlib=3.7.2
- numpy
- packaging
- pandas
Expand Down

0 comments on commit 7af0f50

Please sign in to comment.