Skip to content

Commit

Permalink
Trac #27866: Introduce graphics insets
Browse files Browse the repository at this point in the history
This ticket introduces graphics insets, i.e. it allows to have various
`Graphics` objects at arbitrary locations and sizes on a single figure.
Previously, only graphics arrays, i.e. `Graphics` objects arranged in a
regular array, were possible.

This is made possible thanks to the generic class `MultiGraphics`
introduced in #27865.
The user interface is constituted of three new functions:
- the method `Graphics.inset()`, which adds an inset to a given
graphics; see this [https://sagemanifolds.obspm.fr/preview/graphics_inse
t/reference/plotting/sage/plot/graphics.html#sage.plot.graphics.Graphics
.inset preview example]
- the method `MultiGraphics.inset()`, which adds an inset to a multi-
graphics (e.g. a `GraphicsArray`); see this [https://sagemanifolds.obspm
.fr/preview/graphics_inset/reference/plotting/sage/plot/multigraphics.ht
ml#sage.plot.multigraphics.MultiGraphics.inset preview example]
- the function `multi_graphics()` , which creates a figure from a list
of `Graphics` objects at user-specified locations; see this [https://sag
emanifolds.obspm.fr/preview/graphics_inset/reference/plotting/sage/plot/
plot.html#sage.plot.plot.multi_graphics preview example]

URL: https://trac.sagemath.org/27866
Reported by: egourgoulhon
Ticket author(s): Eric Gourgoulhon
Reviewer(s): Markus Wageringel
  • Loading branch information
Release Manager committed Oct 26, 2019
2 parents 2c7753a + ed586d3 commit 73e16ef
Show file tree
Hide file tree
Showing 5 changed files with 658 additions and 38 deletions.
8 changes: 5 additions & 3 deletions src/sage/docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,11 @@ def sphinx_plot(graphics, **kwds):
if isinstance(graphics, (sage.plot.graphics.Graphics,
sage.plot.multigraphics.MultiGraphics)):
graphics.matplotlib(figure=figure, figsize=figsize, **options)
# tight_layout adjusts the *subplot* parameters so ticks aren't
# cut off, etc.
figure.tight_layout()
if isinstance(graphics, (sage.plot.graphics.Graphics,
sage.plot.multigraphics.GraphicsArray)):
# for Graphics and GraphicsArray, tight_layout adjusts the
# *subplot* parameters so ticks aren't cut off, etc.
figure.tight_layout()
else:
# 3d graphics via png
import matplotlib as mpl
Expand Down
7 changes: 4 additions & 3 deletions src/sage/plot/all.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from __future__ import absolute_import
from .graphics import Graphics
from .plot import plot, graphics_array, list_plot, parametric_plot, polar_plot
from .plot import plot_loglog, plot_semilogx, plot_semilogy
from .plot import list_plot_loglog, list_plot_semilogx, list_plot_semilogy
from .plot import (plot, graphics_array, multi_graphics, list_plot,
parametric_plot, polar_plot, plot_loglog, plot_semilogx,
plot_semilogy, list_plot_loglog, list_plot_semilogx,
list_plot_semilogy)
from .line import line, line2d
from .arrow import arrow, arrow2d
from .bar_chart import bar_chart
Expand Down
89 changes: 87 additions & 2 deletions src/sage/plot/graphics.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@
- Eric Gourgoulhon (2015-03-19): Add parameter axes_labels_size (:trac:`18004`)
- Eric Gourgoulhon (2019-05-18): :class:`~sage.plot.multigraphics.GraphicsArray`
- Eric Gourgoulhon (2019-05-24): :class:`~sage.plot.multigraphics.GraphicsArray`
moved to new module :mod:`~sage.plot.multigraphics`; various improvements and
fixes in :meth:`Graphics.matplotlib` and ``Graphics._set_scale``.
fixes in :meth:`Graphics.matplotlib` and ``Graphics._set_scale``; new method
:meth:`Graphics.inset`
"""

Expand Down Expand Up @@ -3316,3 +3317,87 @@ def description(self):
data.append([g_zorder, g_str, g])
data.sort()
return '\n'.join(g[1] for g in data)

def inset(self, graphics, pos=None, fontsize=None):
r"""
Add a graphics object as an inset.
INPUT:
- ``graphics`` -- the graphics object (instance of :class:`Graphics`)
to be added as an inset to the current graphics
- ``pos`` -- (default: ``None``) 4-tuple
``(left, bottom, width, height)``
specifying the location and size of the inset on the final figure,
all quantities being in fractions of the figure width and height; if
``None``, the value ``(0.7, 0.7, 0.2, 0.2)`` is used
- ``fontsize`` -- (default: ``None``) integer, font size (in points)
for the inset; if ``None``, the value of 6 points is used, unless
``fontsize`` has been explicitely set in the construction of
``graphics`` (in this case, it is not overwritten here)
OUTPUT:
- instance of :class:`~sage.plot.multigraphics.MultiGraphics`
EXAMPLES::
sage: f(x) = x^2*sin(1/x)
sage: g1 = plot(f(x), (x, -2, 2), axes_labels=['$x$', '$y$'])
sage: g2 = plot(f(x), (x, -0.3, 0.3), axes_labels=['$x$', '$y$'],
....: frame=True)
sage: g1.inset(g2)
Multigraphics with 2 elements
.. PLOT::
f = (x**2*sin(1/x)).function(x)
g1 = plot(f(x), (x, -2, 2), axes_labels=['$x$', '$y$'])
g2 = plot(f(x), (x, -0.3, 0.3), axes_labels=['$x$', '$y$'], \
frame=True)
sphinx_plot(g1.inset(g2))
Using non-default values for the position/size and the font size::
sage: g1.inset(g2, pos=(0.15, 0.7, 0.25, 0.25), fontsize=8)
Multigraphics with 2 elements
.. PLOT::
f = (x**2*sin(1/x)).function(x)
g1 = plot(f(x), (x, -2, 2), axes_labels=['$x$', '$y$'])
g2 = plot(f(x), (x, -0.3, 0.3), axes_labels=['$x$', '$y$'], \
frame=True)
sphinx_plot(g1.inset(g2, pos=(0.15, 0.7, 0.25, 0.25), fontsize=8))
We can add another inset by invoking ``inset`` on the last output::
sage: g1g2 = _
sage: g3 = plot(f(x), (x, -0.05, 0.05), axes_labels=['$x$', '$y$'],
....: frame=True)
sage: g1g2.inset(g3, pos=(0.65, 0.12, 0.25, 0.25))
Multigraphics with 3 elements
.. PLOT::
f = (x**2*sin(1/x)).function(x)
g1 = plot(f(x), (x, -2, 2), axes_labels=['$x$', '$y$'])
g2 = plot(f(x), (x, -0.3, 0.3), axes_labels=['$x$', '$y$'], \
frame=True)
g1g2 = g1.inset(g2, pos=(0.15, 0.7, 0.25, 0.25), fontsize=8)
g3 = plot(f(x), (x, -0.05, 0.05), axes_labels=['$x$', '$y$'], \
frame=True)
sphinx_plot(g1g2.inset(g3, pos=(0.65, 0.12, 0.25, 0.25)))
"""
from .multigraphics import MultiGraphics
if pos is None:
pos = (0.7, 0.7, 0.2, 0.2)
pos0 = (0.05, 0.05, 0.9, 0.9)
if fontsize is not None:
graphics._extra_kwds['fontsize'] = fontsize
elif 'fontsize' not in graphics._extra_kwds:
graphics._extra_kwds['fontsize'] = 6
return MultiGraphics([(self, pos0), (graphics, pos)])
Loading

0 comments on commit 73e16ef

Please sign in to comment.