Skip to content

Commit

Permalink
Redesign the display mechanism
Browse files Browse the repository at this point in the history
This is a new design of the PyGMT display mechanism, following the
discussions in #269, with some changes.

**It's working now but not finished yet.**
  • Loading branch information
seisman committed Oct 1, 2020
1 parent c191d3e commit b83db60
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 47 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ test:
@echo ""
@cd $(TESTDIR); python -c "import $(PROJECT); $(PROJECT).show_versions()"
@echo ""
cd $(TESTDIR); pytest $(PYTEST_ARGS) $(PROJECT)
cd $(TESTDIR); PYGMT_DISABLE_EXTERNAL_DISPLAY="true" pytest $(PYTEST_ARGS) $(PROJECT)
cp $(TESTDIR)/coverage.xml .
cp -r $(TESTDIR)/htmlcov .
rm -r $(TESTDIR)
Expand Down
2 changes: 1 addition & 1 deletion doc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
SPHINXBUILD = PYGMT_DISABLE_EXTERNAL_DISPLAY="true" sphinx-build
SPHINXAUTOGEN = sphinx-autogen
BUILDDIR = _build

Expand Down
2 changes: 1 addition & 1 deletion pygmt/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

# Import modules to make the high-level GMT Python API
from .session_management import begin as _begin, end as _end
from .figure import Figure
from .figure import Figure, set_display
from .filtering import blockmedian
from .gridding import surface
from .sampling import grdtrack
Expand Down
97 changes: 55 additions & 42 deletions pygmt/figure.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,14 @@
Define the Figure class that handles all plotting.
"""
import os
import sys
from tempfile import TemporaryDirectory
import base64

try:
from IPython.display import Image
except ImportError:
Image = None

from .clib import Session
from .base_plotting import BasePlotting
from .exceptions import GMTError, GMTInvalidInput
from .exceptions import GMTInvalidInput
from .helpers import (
build_arg_string,
fmt_docstring,
Expand All @@ -27,6 +24,29 @@
# This is needed for the sphinx-gallery scraper in pygmt/sphinx_gallery.py
SHOWED_FIGURES = []

# Variable to control show() display
SHOW_CONFIG = {
"external": True, # Open in an external viewer
"notebook": True, # Notebook display
}

# Determine the default display mode
try:
IPython = sys.modules["IPython"]
if "IPKernelApp" in IPython.get_ipython().config: # Jupyter Notebook enabled
SHOW_CONFIG["notebook"] = True
SHOW_CONFIG["external"] = False
else:
SHOW_CONFIG["notebook"] = False
SHOW_CONFIG["external"] = True
except KeyError:
SHOW_CONFIG["notebook"] = False
SHOW_CONFIG["external"] = True

# Check environment variable to override default values
if os.environ.get("PYGMT_DISABLE_EXTERNAL_DISPLAY", "default").lower() == "true":
SHOW_CONFIG["external"] = False


class Figure(BasePlotting):
"""
Expand Down Expand Up @@ -57,7 +77,7 @@ class Figure(BasePlotting):
>>> fig = Figure()
>>> fig.basemap(region='JP', projection="M3i", frame=True)
>>> # The fig.region attribute shows the WESN bounding box for the figure
>>> print(', '.join('{:.2f}'.format(i) for i in fig.region))
>>> print(', '.join('{:.2f}'.format(i) for i in fig.region))
122.94, 145.82, 20.53, 45.52
"""
Expand Down Expand Up @@ -235,63 +255,40 @@ def savefig(
if show:
launch_external_viewer(fname)

def show(self, dpi=300, width=500, method="static"):
def show(self, dpi=300, width=500):
"""
Display a preview of the figure.
Inserts the preview in the Jupyter notebook output. You will need to
have IPython installed for this to work. You should have it if you are
using the notebook.
If ``method='external'``, makes PDF preview instead and opens it in the
default viewer for your operating system (falls back to the default web
browser). Note that the external viewer does not block the current
process, so this won't work in a script.
Inserts the preview in the Jupyter notebook output, otherwise opens it
in the default viewer for your operating system (falls back to the
default web browser). Note that the external viewer does not block the
current process, so this won't work in a script.
Parameters
----------
dpi : int
The image resolution (dots per inch).
width : int
Width of the figure shown in the notebook in pixels. Ignored if
``method='external'``.
method : str
How the figure will be displayed. Options are (1) ``'static'``: PNG
preview (default); (2) ``'external'``: PDF preview in an external
program.
Width of the figure shown in the notebook in pixels.
Returns
-------
img : IPython.display.Image
Only if ``method != 'external'``.
Only if in Jupyter notebook.
"""
# Module level variable to know which figures had their show method
# called. Needed for the sphinx-gallery scraper.
SHOWED_FIGURES.append(self)

if method not in ["static", "external"]:
raise GMTInvalidInput("Invalid show method '{}'.".format(method))
if method == "external":
if SHOW_CONFIG["notebook"]:
png = self._repr_png_()
if IPython is not None:
IPython.display.display(IPython.display.Image(data=png, width=width))

if SHOW_CONFIG["external"]:
pdf = self._preview(fmt="pdf", dpi=dpi, anti_alias=False, as_bytes=False)
launch_external_viewer(pdf)
img = None
elif method == "static":
png = self._preview(
fmt="png", dpi=dpi, anti_alias=True, as_bytes=True, transparent=True
)
if Image is None:
raise GMTError(
" ".join(
[
"Cannot find IPython.",
"Make sure you have it installed",
"or use 'external=True' to open in an external viewer.",
]
)
)
img = Image(data=png, width=width)
return img

def shift_origin(self, xshift=None, yshift=None):
"""
Expand Down Expand Up @@ -374,3 +371,19 @@ def _repr_html_(self):
base64_png = base64.encodebytes(raw_png)
html = '<img src="data:image/png;base64,{image}" width="{width}px">'
return html.format(image=base64_png.decode("utf-8"), width=500)


def set_display(mode):
"""
Set the display mode.
"""
if mode == "notebook":
SHOW_CONFIG["notebook"] = True
SHOW_CONFIG["external"] = False
elif mode == "external":
SHOW_CONFIG["notebook"] = False
SHOW_CONFIG["external"] = True
else:
raise GMTInvalidInput(
f'Invalid display mode {mode}, should be either "notebook" or "external".'
)
3 changes: 1 addition & 2 deletions pygmt/tests/test_figure.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,7 @@ def test_figure_show():
"Test that show creates the correct file name and deletes the temp dir"
fig = Figure()
fig.basemap(region="10/70/-300/800", projection="X3i/5i", frame="af")
img = fig.show(width=800)
assert img.width == 800
fig.show(width=800)


@pytest.mark.mpl_image_compare
Expand Down

0 comments on commit b83db60

Please sign in to comment.