Skip to content

Commit

Permalink
Set default InlineBackend to retina
Browse files Browse the repository at this point in the history
  • Loading branch information
has2k1 committed May 8, 2023
1 parent 9e36428 commit 35de8cb
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 5 deletions.
16 changes: 12 additions & 4 deletions doc/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ New Features

.. code-block:: python
theme(figure_size=(8, 6), dpi=100)
theme(figure_size=(8, 6), dpi=100)
will create an `800px x 600px` image.

Expand All @@ -37,7 +37,7 @@ New Features

.. code-block:: python
theme(plot_subtitle=element_text(size=8))
theme(plot_subtitle=element_text(size=8))
Enhancements
Expand All @@ -47,6 +47,16 @@ Enhancements
:meth:`~plotnine.ggplot.save_helper`. It gives you access to the
matplotlib figure that will be saved to file.

- When plotting with an ipython interactive backend (e.g. in a
jupyter notebook). The default image output is retina. You
do not need to run this command.

.. code-block:: python
%config InlineBackend.figure_format = "retina"
Plotnine still respects any values set the user.

API Changes
***********

Expand All @@ -72,8 +82,6 @@ API Changes

- Changed default font-family (san-serif) from DejaVu Sans to Helvetica.

- Default dpi has changed from 100 to 300.

Bug Fixes
*********

Expand Down
43 changes: 43 additions & 0 deletions plotnine/ggplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from .themes.theme import theme, theme_get
from .utils import (
from_inches,
get_ipython,
is_data_like,
order_as_data_mapping,
to_inches,
Expand Down Expand Up @@ -762,6 +763,16 @@ class plot_context:
exits.
"""

# Default to retina unless user chooses otherwise
_IPYTHON_CONFIG: dict[str, dict[str, Any]] = {
"InlineBackend": {
"figure_format": "retina",
"close_figures": True,
"print_figure_kwargs": {"bbox_inches": None},
}
}
_ip_config_inlinebackend: dict[str, Any] = {}

def __init__(self, plot: ggplot, show: bool = False):
self.plot = plot
self.show = show
Expand All @@ -782,6 +793,7 @@ def __enter__(self) -> plot_context:
)
self.rc_context.__enter__()
self.pd_option_context.__enter__()
self._enter_ipython()
return self

def __exit__(self, exc_type, exc_value, exc_traceback):
Expand All @@ -802,4 +814,35 @@ def __exit__(self, exc_type, exc_value, exc_traceback):

self.rc_context.__exit__(exc_type, exc_value, exc_traceback)
self.pd_option_context.__exit__(exc_type, exc_value, exc_traceback)
self._exit_ipython()
delattr(self.plot.theme, "_targets")

def _enter_ipython(self):
"""
Setup ipython parameters in for the plot
"""
ip = get_ipython()
if not ip:
return
elif not hasattr(ip.config, "InlineBackend"):
return

for key, value in self._IPYTHON_CONFIG["InlineBackend"].items():
if key not in ip.config.InlineBackend: # pyright: ignore
self._ip_config_inlinebackend[key] = key
ip.run_line_magic("config", f"InlineBackend.{key} = {value!r}")

def _exit_ipython(self):
"""
Undo ipython parameters in for the plot
"""
ip = get_ipython()
if not ip:
return
elif not hasattr(ip.config, "InlineBackend"):
return

for key in self._ip_config_inlinebackend:
del ip.config["InlineBackend"][key] # pyright: ignore

self._ip_config_inlinebackend = {}
2 changes: 1 addition & 1 deletion plotnine/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
aspect_ratio = "auto"

#: Default DPI used by the themes
dpi = 300
dpi = 100

#: Default figure size inches
figure_size = (640 / dpi, 480 / dpi)
Expand Down
16 changes: 16 additions & 0 deletions plotnine/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@

from plotnine.typing import DataLike, FloatArray, FloatArrayLike, IntArray

try:
from IPython.core.interactiveshell import InteractiveShell
except ImportError:
pass


# Points and lines of equal size should give the
# same visual diameter (for points) and thickness
Expand Down Expand Up @@ -1238,3 +1243,14 @@ def __enter__(self):

def __exit__(self, type, value, traceback):
return self._cm.__exit__(type, value, traceback)


def get_ipython() -> "InteractiveShell" | None:
"""
Return running IPython instance or None
"""
try:
from IPython.core.getipython import get_ipython
except ImportError:
return None
return get_ipython()

0 comments on commit 35de8cb

Please sign in to comment.