Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
7 changes: 3 additions & 4 deletions .github/workflows/ci_tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ jobs:
optional-packages: ''
- python-version: 3.9
numpy-version: '1.21'
optional-packages: 'geopandas'
optional-packages: 'geopandas ipython'
defaults:
run:
shell: bash -l {0}
Expand Down Expand Up @@ -96,9 +96,8 @@ jobs:
mamba install gmt=6.2.0 numpy=${{ matrix.numpy-version }} \
pandas xarray netCDF4 packaging \
${{ matrix.optional-packages }} \
coverage[toml] dvc ipython make \
pytest-cov pytest-mpl pytest>=6.0 \
sphinx-gallery
coverage[toml] dvc make pytest>=6.0 \
pytest-cov pytest-mpl sphinx-gallery

# Show installed pkg information for postmortem diagnostic
- name: List installed packages
Expand Down
2 changes: 1 addition & 1 deletion pygmt/src/inset.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ def inset(self, **kwargs):
...
>>> # Map elements outside the "with" block are plotted in the main figure
>>> fig.logo(position="jBR+o0.2c+w3c")
>>> fig.show()
>>> fig.show() # doctest: +SKIP
<IPython.core.display.Image object>
"""
kwargs = self._preprocess(**kwargs) # pylint: disable=protected-access
Expand Down
47 changes: 46 additions & 1 deletion pygmt/tests/test_figure.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,17 @@
"""
import os

try:
import IPython
except ModuleNotFoundError:
IPython = None # pylint: disable=invalid-name


import numpy as np
import numpy.testing as npt
import pytest
from pygmt import Figure, set_display
from pygmt.exceptions import GMTInvalidInput
from pygmt.exceptions import GMTError, GMTInvalidInput
from pygmt.helpers import GMTTempFile


Expand Down Expand Up @@ -52,6 +58,23 @@ def test_figure_region_country_codes():
npt.assert_allclose(fig.region, np.array([0.0, 360.0, -90.0, 90.0]))


def test_figure_repr():
"""
Make sure that figure output's PNG and HTML printable representations look
ok.
"""
fig = Figure()
fig.basemap(region=[0, 1, 2, 3], frame=True)
# Check that correct PNG 8-byte file header is produced
# https://en.wikipedia.org/wiki/Portable_Network_Graphics#File_header
repr_png = fig._repr_png_() # pylint: disable=protected-access
Copy link
Member

Choose a reason for hiding this comment

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

Is _repr_png_ and _repr_html_ useful? I have no idea how these functions can be used.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good question. They are used by IPython.display.display_png and IPython.display.display_html respectively, i.e. for display in Jupyter notebooks.

Technically I should have written these unit test using IPython.display.display_png(fig) and IPython.display.display_html(fig) instead of testing these non-public functions directly, but it's hard to test a pop-up figure. So I've settled for testing the __repr_png__ and __repr_html__ instead (which works with or without IPython installed). Con with this approach is that I need to do pylint: disable=protected-access 🙃

Copy link
Member

Choose a reason for hiding this comment

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

They are used by IPython.display.display_png and IPython.display.display_html respectively, i.e. for display in Jupyter notebooks.

PyGMT already provides the Figure.show() function for display in Jupyter notebooks. Removing _repr_png_() and _repr_html_() doesn't affect the Figure.show() function. Do you think we should remove these two functions?

Copy link
Member Author

Choose a reason for hiding this comment

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

It might not affect Figure.show(), but I think we need to keep it. Having __repr_png__() and __repr_html__ means that putting just fig at the last line of a Jupyter notebook cell will display the plot. E.g. like this:

image

This works in Jupyter/IPython because of a IPython.display.display_html(fig) call. Similarly, if you put a df (pandas.DataFrame) on the last line of a cell, a nicely formatted html table will be printed because Jupyter/IPython does IPython.display.display_html(df) (see the __repr_html__ at https://github.com/pandas-dev/pandas/blob/73c68257545b5f8530b7044f56647bd2db92e2ba/pandas/core/frame.py#L1007-L1049).

assert repr_png.hex().startswith("89504e470d0a1a0a")
# Check that correct HTML image tags are produced
repr_html = fig._repr_html_() # pylint: disable=protected-access
assert repr_html.startswith('<img src="data:image/png;base64,')
assert repr_html.endswith('" width="500px">')


def test_figure_savefig_exists():
"""
Make sure the saved figure has the right name.
Expand Down Expand Up @@ -159,6 +182,7 @@ def mock_psconvert(*args, **kwargs): # pylint: disable=unused-argument
)


@pytest.mark.skipif(IPython is None, reason="run when IPython is installed")
def test_figure_show():
"""
Test that show creates the correct file name and deletes the temp dir.
Expand Down Expand Up @@ -199,6 +223,27 @@ def test_figure_show_invalid_method():
fig.show(method="test")


@pytest.mark.skipif(IPython is not None, reason="run without IPython installed")
def test_figure_show_notebook_error_without_ipython():
"""
Test to check if an error is raised when display method is 'notebook', but
IPython is not installed.
"""
fig = Figure()
fig.basemap(region=[0, 1, 2, 3], frame=True)
with pytest.raises(GMTError):
fig.show(method="notebook")


def test_figure_display_external():
"""
Test to check that a figure can be displayed in an external window.
"""
fig = Figure()
fig.basemap(region=[0, 3, 6, 9], projection="X1c", frame=True)
fig.show(method="external")
Comment on lines +238 to +244
Copy link
Member

Choose a reason for hiding this comment

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

The CI can't open external viewers. Why does this test work?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, the console won't show a window pop-up, but I think the code will still execute fine somehow. Looking at the codecov diff at https://app.codecov.io/gh/GenericMappingTools/pygmt/compare/1496/changes#D2L237, the launch_external_viewer function is being called up to the time.sleep(0.5) line, so it seems that Linux/macOS/Windows launchers (xdg-open/open/not-sure-what's-on windows) are available on CI?

image



def test_figure_set_display_invalid():
"""
Test to check if an error is raised when an invalid method is passed to
Expand Down
4 changes: 2 additions & 2 deletions pygmt/tests/test_sphinx_gallery.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@
from pygmt.figure import SHOWED_FIGURES, Figure

pygmt_sphinx_gallery = pytest.importorskip(
"pygmt.sphinx_gallery", reason="requires sphinx-gallery to be installed"
"pygmt.sphinx_gallery", reason="Requires sphinx-gallery to be installed"
)
pytest.importorskip("IPython", reason="Requires IPython to be installed")


def test_pygmtscraper():
"""
Make sure the scraper finds the figures and removes them from the pool.
"""

showed = SHOWED_FIGURES.copy()
for _ in range(len(SHOWED_FIGURES)):
SHOWED_FIGURES.pop()
Expand Down