Skip to content

Commit

Permalink
Python 3 support (#57)
Browse files Browse the repository at this point in the history
- Travis build tests python3.6+pyqt5, python2.7+pyqt5, and python2.7+pyqt4
- Default overall test script moved to python 3.7
- Fixed bugs with pyqt5 and python3.6 and 3.7
  • Loading branch information
eldond authored May 19, 2020
1 parent 242df74 commit 3b17054
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 35 deletions.
52 changes: 38 additions & 14 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,28 +1,52 @@
language: python
sudo: required
dist: trusty
python:
- "2.7"
jobs:
include:
- name: "python 2.7 qt4 trusty pgmpl"
dist: trusty
python: 2.7
# virtualenv:
# system_site_packages: true
before_install:
- sudo apt-get update
- sudo apt-get -y install python-qt4
before_script:
# From pyqtgraph's .travis.yml: https://github.com/pyqtgraph/pyqtgraph/blob/develop/.travis.yml
# We need to create a (fake) display on Travis, let's use a funny resolution
- export DISPLAY=:99.0
- "sh -e /etc/init.d/xvfb start"
- /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -screen 0 1400x900x24 -ac +extension GLX +render
- export PGMPL_TEST_VERBOSE=1
- name: "python 2.7 qt5 bionic pgmpl"
dist: bionic
python: 2.7
before_install:
- sudo apt-get update
- sudo apt-get -y install python-pyqt5
services:
- xvfb
- name: "python 3.6 qt5 bionic pgmpl"
dist: bionic
python: 3.6
before_install:
- sudo apt-get update
- sudo apt-get -y install python3-pyqt5
services:
- xvfb

# https://stackoverflow.com/a/35029430/6605826

# system_site_packages limits py versions https://travis-ci.community/t/python-3-6-and-3-7-with-system-site-packages-enabled-fails-to-activate-on-xenial/1697
virtualenv:
system_site_packages: true

# apt-get commands depend on py version: https://stackoverflow.com/a/20621143/6605826
install:
- sudo apt-get update
- sudo apt-get -y install python-qt4
# - sudo apt-get update
# - if [[ $TRAVIS_PYTHON_VERSION < 3 ]]; then sudo apt-get -y install python-qt4; fi
# - if [[ $TRAVIS_PYTHON_VERSION > 3 ]]; then sudo apt-get -y install python3-pyqt5; fi
- pip install -r requirements.txt
- pip install codecov coverage

before_script:
# From pyqtgraph's .travis.yml: https://github.com/pyqtgraph/pyqtgraph/blob/develop/.travis.yml
# We need to create a (fake) display on Travis, let's use a funny resolution
- export DISPLAY=:99.0
- "sh -e /etc/init.d/xvfb start"
- /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -screen 0 1400x900x24 -ac +extension GLX +render
- export PGMPL_TEST_VERBOSE=1

script:
- coverage run -m unittest discover --pattern=*.py -s tests

Expand Down
9 changes: 5 additions & 4 deletions pgmpl/axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,12 @@ def _make_custom_verts(verts):
:param verts: sequence of (x, y), optional
:return: a pyqt path suitable for use with Axes.plot()'s symbol keyword.
"""
from pyqtgraph.graphicsItems.ScatterPlotItem import Symbols
verts_x = np.array([vert[0] for vert in verts])
verts_y = np.array([vert[1] for vert in verts])
return pg.arrayToQPath(verts_x, verts_y, connect='all')
key = 'custom_pgmpl_symbol_1'
Symbols[key] = pg.arrayToQPath(verts_x, verts_y, connect='all')
return key

def scatter(self, x=None, y=None, **kwargs):
"""
Expand Down Expand Up @@ -171,7 +174,6 @@ def scatter(self, x=None, y=None, **kwargs):
plotkw['symbolPen'] = [pg.mkPen(**spkw) for spkw in sympen_kw]
if plotkw.get('symbol', None) is None: # Shouldn't happen unless user sets None explicitly b/c default is 'o'
plotkw['symbol'] = self._make_custom_verts(kwargs.pop('verts', None))

return super(Axes, self).plot(x=x, y=y, **plotkw)

def imshow(self, x=None, aspect=None, **kwargs):
Expand All @@ -190,8 +192,7 @@ def contour(self, *args, **kwargs):
def contourf(self, *args, **kwargs):
printd(' pgmpl.axes.Axes.contourf()...')
kwargs['filled'] = True
contours = QuadContourSet(self, *args, **kwargs)
return contours
return QuadContourSet(self, *args, **kwargs)

def set_xlabel(self, label):
"""Imitates basic use of matplotlib.axes.Axes.set_xlabel()"""
Expand Down
13 changes: 11 additions & 2 deletions pgmpl/figure.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,11 @@ def add_subplot(self, nrows, ncols, index, **kwargs):
col = (index-1) % ncols
ax = Axes(nrows=nrows, ncols=ncols, index=index, **kwargs)
self.layout.addItem(ax, row+1, col)
try:
tolist(self.axes)
except RuntimeError:
print('Warning: Qt has deleted the axes; figure had a residual reference to a bad Qt object. (add_subplot)')
self.axes = None
self.axes = ax if self.axes is None else tolist(self.axes) + [ax]
self.fig_colspan = max([ncols, self.fig_colspan])
self.refresh_suptitle()
Expand Down Expand Up @@ -196,10 +201,14 @@ def gca(self):
Imitation of matplotlib gca()
:return: Current axes for this figure, creating them if necessary
"""
if self.axes is not None:
try:
ax = list(flatten(np.atleast_1d(self.axes)))[-1]
except RuntimeError: # Happens if Qt has deleted the Axes
print('Warning: Qt has deleted the axes; figure had a residual reference to a bad Qt object. (gca)')
self.axes = None
if self.axes is None:
ax = self.add_subplot(1, 1, 1)
else:
ax = list(flatten(np.atleast_1d(self.axes)))[-1]
return ax

def close(self):
Expand Down
30 changes: 17 additions & 13 deletions pgmpl/translate.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@

# pgmpl imports
from pgmpl.util import set_debug, printd, tolist
from pyqtgraph.graphicsItems.ScatterPlotItem import Symbols

# Install custom symbols
theta = np.linspace(0, 2 * np.pi, 36)
Symbols['.'] = pg.arrayToQPath(np.cos(theta) * 0.125, np.sin(theta) * 0.125, connect='all')
Symbols[','] = pg.arrayToQPath(np.array([-0.01, 0, 0.01, 0, -0.01]), np.array([0, 0.01, 0, -0.01, 0]), connect='all')
Symbols['_'] = pg.arrayToQPath(np.array([-0.5, 0.5]), np.array([0, 0]), connect='all')
Symbols['|'] = pg.arrayToQPath(np.array([0, 0]), np.array([-0.5, 0.5]), connect='all')
Symbols['x'] = pg.arrayToQPath(
np.array([-0.5, 0.5, 0, 0.5, -0.5, 0]), np.array([-0.5, 0.5, 0, -0.5, 0.5, 0]), connect='all'
)


def dealias(**kws):
Expand Down Expand Up @@ -171,19 +182,12 @@ def symbol_translator(**kw):
:return: string
Code for the relevant pyqtgraph symbol.
"""
theta = np.linspace(0, 2 * np.pi, 36)
return { # mpl symbol : pyqt4 symbol
'.': pg.arrayToQPath(np.cos(theta) * 0.125, np.sin(theta) * 0.125, connect='all'),
',': pg.arrayToQPath(np.array([-0.01, 0, 0.01, 0, -0.01]),
np.array([0, 0.01, 0, -0.01, 0]), connect='all'),
'x': pg.arrayToQPath(np.array([-0.5, 0.5, 0, 0.5, -0.5, 0]),
np.array([-0.5, 0.5, 0, -0.5, 0.5, 0]), connect='all'),
'+': '+', '*': 'star', 'o': 'o', 'v': 't', '^': 't1', '>': 't2', '<': 't3',
'd': 'd', 's': 's', 'p': 'p', 'h': 'h',
'_': pg.arrayToQPath(np.array([-0.5, 0.5]), np.array([0, 0]), connect='all'),
'|': pg.arrayToQPath(np.array([0, 0]), np.array([-0.5, 0.5]), connect='all'),
'None': None, 'none': None, None: None,
}.get(kw['marker'], 'o') if 'marker' in kw else None
# mpl symbol : pyqt4 symbol
pyqt_symbol = {
'.': '.', ',': ',', 'x': 'x', '+': '+', '*': 'star', 'o': 'o', 'v': 't', '^': 't1', '>': 't2', '<': 't3',
'd': 'd', 's': 's', 'p': 'p', 'h': 'h', '_': '_', '|': '|', 'None': None, 'none': None, None: None,
}.get(kw.get('marker', None), 'o')
return pyqt_symbol


def symbol_edge_setup(pgkw, plotkw):
Expand Down
2 changes: 1 addition & 1 deletion test.sh
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#!/bin/bash
python2.7 -m unittest discover --pattern=*.py -s tests
python3.7 -m unittest discover --pattern=*.py -s tests
4 changes: 3 additions & 1 deletion tests/test_translate.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ def test_style_translator(self):
assert style_translator(linestyle="-") == QtCore.Qt.SolidLine

def test_symbol_translator(self):
from pyqtgraph.graphicsItems.ScatterPlotItem import Symbols
news = [None] * self.nt
for i in range(self.nt):
news[i] = symbol_translator(**self.plot_kw_tests[i])
Expand All @@ -95,7 +96,8 @@ def test_symbol_translator(self):
assert symbol_translator(marker='^') == 't1'
custom_markers = '_x|,.'
for custom in custom_markers:
assert isinstance(symbol_translator(marker=custom), QtGui.QPainterPath)
assert isinstance(symbol_translator(marker=custom), QtGui.QPainterPath) \
or isinstance(Symbols.get(custom, None), QtGui.QPainterPath)

def test_setup_pen_kw(self):
newp = [None] * self.nt
Expand Down

0 comments on commit 3b17054

Please sign in to comment.