Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: ipython/matplotlib-inline
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 0.1.4
Choose a base ref
...
head repository: ipython/matplotlib-inline
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 0.1.5
Choose a head ref
  • 12 commits
  • 5 files changed
  • 4 contributors

Commits on May 20, 2022

  1. Merge pull request #14 from fperez/master

    Remove matplotlib rc overrides.
    
    Addresses:
    - ipython/ipython#10383
    - matplotlib/matplotlib#23007
    fperez authored May 20, 2022
    Copy the full SHA
    170a075 View commit details

Commits on Jun 10, 2022

  1. Move draw_if_interactive logic to new_figure_manager_given_figure.

    Currently, Matplotlib only ever calls draw_if_interactive at the end of
    `plt.figure()` (and upon figure unpickling), i.e. this is a mechanism to
    further customize handling of newly generated figures.  (Prior to
    Matplotlib 1.5, draw_if_interactive was also called at the end of all
    pyplot functions to trigger a figure redraw, but this is now handled by
    the stale attribute.)
    
    In order to simplify the backend API ("what is the API that a backend
    module must/can provide"), I am planning to deprecate (on Matplotlib's
    side) the ability for backends to provide a draw_if_interactive function
    (forcing them to always do `if interactive(): draw_idle()`).  Instead,
    any relevant new-figure-customization logic can instead go into
    `new_figure_manager_given_figure`.  This PR implements this change for
    matplotlib-inline, and should be fully back-compatible all the way back
    to Matplotlib 1.5.  I would like to make these changes first on the side
    of the clients (i.e., the third-party backends), to catch any possible
    problems with the intended change on Matplotlib's side.
    anntzer committed Jun 10, 2022
    Copy the full SHA
    6380cd9 View commit details

Commits on Jun 14, 2022

  1. Copy the full SHA
    de3b78e View commit details

Commits on Jun 15, 2022

  1. Merge pull request #15 from anntzer/udif

    Move draw_if_interactive logic to new_figure_manager_given_figure.
    fperez authored Jun 15, 2022
    Copy the full SHA
    f764b43 View commit details

Commits on Aug 12, 2022

  1. Merge pull request #17 from agoose77/patch-1

    Fix: always clear `_draw_called`
    fperez authored Aug 12, 2022
    Copy the full SHA
    3347d0f View commit details

Commits on Aug 16, 2022

  1. Update README install/description.

    List correct package in installation instructions and provide updated description,
    clarifying `%matplotlib inline` magic isn't needed anymore in default clients.
    fperez committed Aug 16, 2022
    Copy the full SHA
    4b9ca8d View commit details
  2. Copy the full SHA
    5f2765e View commit details
  3. Copy the full SHA
    1b05e96 View commit details
  4. Copy the full SHA
    773a6a0 View commit details
  5. Fix (C) year

    fperez committed Aug 16, 2022
    Copy the full SHA
    d07b137 View commit details
  6. Copy the full SHA
    8411553 View commit details
  7. Update to v 0.1.5 for correct release.

    Had to yank 0.1.4 from PyPI as I accidentally used the wrong remote at the last
    minute.
    fperez committed Aug 16, 2022
    Copy the full SHA
    f33be24 View commit details
Showing with 83 additions and 67 deletions.
  1. +1 −1 LICENSE
  2. +11 −3 README.md
  3. +1 −1 matplotlib_inline/__init__.py
  4. +67 −62 matplotlib_inline/backend_inline.py
  5. +3 −0 setup.cfg
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
BSD 3-Clause License

Copyright (c) 2019,
Copyright (c) 2019-2022, IPython Development Team.
All rights reserved.

Redistribution and use in source and binary forms, with or without
14 changes: 11 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
# Matplotlib Inline Back-end for IPython and Jupyter

This package provides support for matplotlib to display figures directly inline in the Jupyter notebook and related clients, as shown below.

## Installation

With conda:

```bash
conda install -c conda-forge notebook matplotlib
conda install -c conda-forge matplotlib-inline
```

With pip:

```bash
pip install notebook matplotlib
pip install matplotlib-inline
```

## Usage

This package is included in IPython and can be used in a Jupyter Notebook:
Note that in current versions of JupyterLab and Jupyter Notebook, the explicit use of the `%matplotlib inline` directive is not needed anymore, though other third-party clients may still require it.

This will produce a figure immediately below:

```python
%matplotlib inline
@@ -28,3 +32,7 @@ x = np.linspace(0, 3*np.pi, 500)
plt.plot(x, np.sin(x**2))
plt.title('A simple chirp');
```

## License

Licensed under the terms of the BSD 3-Clause License, by the IPython Development Team (see `LICENSE` file).
2 changes: 1 addition & 1 deletion matplotlib_inline/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
from . import backend_inline, config # noqa
__version__ = "0.1.3" # noqa
__version__ = "0.1.5" # noqa
129 changes: 67 additions & 62 deletions matplotlib_inline/backend_inline.py
Original file line number Diff line number Diff line change
@@ -4,13 +4,11 @@
# Distributed under the terms of the BSD 3-Clause License.

import matplotlib
from matplotlib.backends.backend_agg import ( # noqa
new_figure_manager,
FigureCanvasAgg,
new_figure_manager_given_figure,
)
from matplotlib import colors
from matplotlib.backends import backend_agg
from matplotlib.backends.backend_agg import FigureCanvasAgg
from matplotlib._pylab_helpers import Gcf
from matplotlib.figure import Figure

from IPython.core.interactiveshell import InteractiveShell
from IPython.core.getipython import get_ipython
@@ -20,6 +18,57 @@
from .config import InlineBackend


def new_figure_manager(num, *args, FigureClass=Figure, **kwargs):
"""
Return a new figure manager for a new figure instance.
This function is part of the API expected by Matplotlib backends.
"""
return new_figure_manager_given_figure(num, FigureClass(*args, **kwargs))


def new_figure_manager_given_figure(num, figure):
"""
Return a new figure manager for a given figure instance.
This function is part of the API expected by Matplotlib backends.
"""
manager = backend_agg.new_figure_manager_given_figure(num, figure)

# Hack: matplotlib FigureManager objects in interacive backends (at least
# in some of them) monkeypatch the figure object and add a .show() method
# to it. This applies the same monkeypatch in order to support user code
# that might expect `.show()` to be part of the official API of figure
# objects. For further reference:
# https://github.com/ipython/ipython/issues/1612
# https://github.com/matplotlib/matplotlib/issues/835

if not hasattr(figure, 'show'):
# Queue up `figure` for display
figure.show = lambda *a: display(
figure, metadata=_fetch_figure_metadata(figure))

# If matplotlib was manually set to non-interactive mode, this function
# should be a no-op (otherwise we'll generate duplicate plots, since a user
# who set ioff() manually expects to make separate draw/show calls).
if not matplotlib.is_interactive():
return

# ensure current figure will be drawn, and each subsequent call
# of draw_if_interactive() moves the active figure to ensure it is
# drawn last
try:
show._to_draw.remove(figure)
except ValueError:
# ensure it only appears in the draw list once
pass
# Queue up the figure for drawing in next show() call
show._to_draw.append(figure)
show._draw_called = True

return manager


def show(close=None, block=None):
"""Show all figures as SVG/PNG payloads sent to the IPython clients.
@@ -56,51 +105,6 @@ def show(close=None, block=None):
show._to_draw = []


def draw_if_interactive():
"""
Is called after every pylab drawing command
"""
# signal that the current active figure should be sent at the end of
# execution. Also sets the _draw_called flag, signaling that there will be
# something to send. At the end of the code execution, a separate call to
# flush_figures() will act upon these values
manager = Gcf.get_active()
if manager is None:
return
fig = manager.canvas.figure

# Hack: matplotlib FigureManager objects in interacive backends (at least
# in some of them) monkeypatch the figure object and add a .show() method
# to it. This applies the same monkeypatch in order to support user code
# that might expect `.show()` to be part of the official API of figure
# objects.
# For further reference:
# https://github.com/ipython/ipython/issues/1612
# https://github.com/matplotlib/matplotlib/issues/835

if not hasattr(fig, 'show'):
# Queue up `fig` for display
fig.show = lambda *a: display(fig, metadata=_fetch_figure_metadata(fig))

# If matplotlib was manually set to non-interactive mode, this function
# should be a no-op (otherwise we'll generate duplicate plots, since a user
# who set ioff() manually expects to make separate draw/show calls).
if not matplotlib.is_interactive():
return

# ensure current figure will be drawn, and each subsequent call
# of draw_if_interactive() moves the active figure to ensure it is
# drawn last
try:
show._to_draw.remove(fig)
except ValueError:
# ensure it only appears in the draw list once
pass
# Queue up the figure for drawing in next show() call
show._to_draw.append(fig)
show._draw_called = True


def flush_figures():
"""Send all figures that changed
@@ -115,19 +119,20 @@ def flush_figures():
if not show._draw_called:
return

if InlineBackend.instance().close_figures:
# ignore the tracking, just draw and close all figures
try:
return show(True)
except Exception as e:
# safely show traceback if in IPython, else raise
ip = get_ipython()
if ip is None:
raise e
else:
ip.showtraceback()
return
try:
if InlineBackend.instance().close_figures:
# ignore the tracking, just draw and close all figures
try:
return show(True)
except Exception as e:
# safely show traceback if in IPython, else raise
ip = get_ipython()
if ip is None:
raise e
else:
ip.showtraceback()
return

# exclude any figures that were closed:
active = set([fm.canvas.figure for fm in Gcf.get_all_fig_managers()])
for fig in [fig for fig in show._to_draw if fig in active]:
3 changes: 3 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -2,6 +2,8 @@
name = matplotlib-inline
version = attr: matplotlib_inline.__version__
description = Inline Matplotlib backend for Jupyter
long_description = file: README.md, LICENSE
long_description_content_type = text/markdown
author = IPython Development Team
author_email = ipython-dev@scipy.org
url = https://github.com/ipython/matplotlib-inline
@@ -27,3 +29,4 @@ classifiers =
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10